From 3bfd7955a04eeb9b5d646c7a147876e579b23d81 Mon Sep 17 00:00:00 2001 From: svtk Date: Fri, 11 Nov 2011 01:00:40 +0400 Subject: [PATCH] KT-352 Function variable declaration type isn't checked inside a function body --- .../ClosureExpressionsTypingVisitor.java | 126 ++++++++++-------- .../quick/regressions/kt352.jet | 27 ++++ 2 files changed, 99 insertions(+), 54 deletions(-) create mode 100644 compiler/testData/checkerWithErrorTypes/quick/regressions/kt352.jet diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ClosureExpressionsTypingVisitor.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ClosureExpressionsTypingVisitor.java index 2c129f978a3..d6e5645c5fb 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ClosureExpressionsTypingVisitor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ClosureExpressionsTypingVisitor.java @@ -24,6 +24,7 @@ import static org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor /** * @author abreslav + * @author svtk */ public class ClosureExpressionsTypingVisitor extends ExpressionTypingVisitor { protected ClosureExpressionsTypingVisitor(@NotNull ExpressionTypingInternals facade) { @@ -61,8 +62,54 @@ public class ClosureExpressionsTypingVisitor extends ExpressionTypingVisitor { @Override public JetType visitFunctionLiteralExpression(JetFunctionLiteralExpression expression, ExpressionTypingContext context) { JetFunctionLiteral functionLiteral = expression.getFunctionLiteral(); - if (functionLiteral.getBodyExpression() == null) return null; + JetBlockExpression bodyExpression = functionLiteral.getBodyExpression(); + if (bodyExpression == null) return null; + JetType expectedType = context.expectedType; + boolean functionTypeExpected = expectedType != TypeUtils.NO_EXPECTED_TYPE && JetStandardClasses.isFunctionType(expectedType); + + FunctionDescriptorImpl functionDescriptor = createFunctionDescriptor(expression, context, functionTypeExpected); + + List parameterTypes = Lists.newArrayList(); + List valueParameters = functionDescriptor.getValueParameters(); + for (ValueParameterDescriptor valueParameter : valueParameters) { + parameterTypes.add(valueParameter.getOutType()); + } + ReceiverDescriptor receiverParameter = functionDescriptor.getReceiverParameter(); + JetType receiver = receiverParameter != NO_RECEIVER ? receiverParameter.getType() : null; + + JetType returnType = TypeUtils.NO_EXPECTED_TYPE; + JetScope functionInnerScope = FunctionDescriptorUtil.getFunctionInnerScope(context.scope, functionDescriptor, context.trace); + JetTypeReference returnTypeRef = functionLiteral.getReturnTypeRef(); + if (returnTypeRef != null) { + returnType = context.getTypeResolver().resolveType(context.scope, returnTypeRef); + context.getServices().checkFunctionReturnType(expression, context.replaceScope(functionInnerScope). + replaceExpectedType(returnType).replaceExpectedReturnType(returnType).replaceDataFlowInfo(context.dataFlowInfo)); + } + else { + if (functionTypeExpected) { + returnType = JetStandardClasses.obtainReturnTypeFromFunctionType(expectedType); + } + returnType = context.getServices().getBlockReturnedType(functionInnerScope, bodyExpression, CoercionStrategy.COERCION_TO_UNIT, + context.replaceExpectedType(returnType).replaceExpectedReturnType(returnType)); + } + JetType safeReturnType = returnType == null ? ErrorUtils.createErrorType("") : returnType; + functionDescriptor.setReturnType(safeReturnType); + + boolean hasDeclaredValueParameters = functionLiteral.getValueParameterList() != null; + if (!hasDeclaredValueParameters && functionTypeExpected) { + JetType expectedReturnType = JetStandardClasses.obtainReturnTypeFromFunctionType(expectedType); + if (JetStandardClasses.isUnit(expectedReturnType)) { + functionDescriptor.setReturnType(JetStandardClasses.getUnitType()); + return DataFlowUtils.checkType(JetStandardClasses.getFunctionType(Collections.emptyList(), receiver, parameterTypes, JetStandardClasses.getUnitType()), expression, context); + } + + } + return DataFlowUtils.checkType(JetStandardClasses.getFunctionType(Collections.emptyList(), receiver, parameterTypes, safeReturnType), expression, context); + } + + private FunctionDescriptorImpl createFunctionDescriptor(JetFunctionLiteralExpression expression, ExpressionTypingContext context, boolean functionTypeExpected) { + JetFunctionLiteral functionLiteral = expression.getFunctionLiteral(); JetTypeReference receiverTypeRef = functionLiteral.getReceiverTypeRef(); final JetType receiverType; if (receiverTypeRef != null) { @@ -71,27 +118,43 @@ public class ClosureExpressionsTypingVisitor extends ExpressionTypingVisitor { ReceiverDescriptor implicitReceiver = context.scope.getImplicitReceiver(); receiverType = implicitReceiver.exists() ? implicitReceiver.getType() : null; } - FunctionDescriptorImpl functionDescriptor = new FunctionDescriptorImpl( context.scope.getContainingDeclaration(), Collections.emptyList(), ""); - List parameterTypes = Lists.newArrayList(); + List valueParameterDescriptors = createValueParameterDescriptors(context, functionLiteral, functionDescriptor, functionTypeExpected); + + JetType effectiveReceiverType; + if (receiverTypeRef == null) { + if (functionTypeExpected) { + effectiveReceiverType = JetStandardClasses.getReceiverType(context.expectedType); + } + else { + effectiveReceiverType = null; + } + } + else { + effectiveReceiverType = receiverType; + } + functionDescriptor.initialize(effectiveReceiverType, NO_RECEIVER, Collections.emptyList(), valueParameterDescriptors, null, Modality.FINAL, Visibility.LOCAL); + context.trace.record(BindingContext.FUNCTION, expression, functionDescriptor); + return functionDescriptor; + } + + private List createValueParameterDescriptors(ExpressionTypingContext context, JetFunctionLiteral functionLiteral, FunctionDescriptorImpl functionDescriptor, boolean functionTypeExpected) { List valueParameterDescriptors = Lists.newArrayList(); List declaredValueParameters = functionLiteral.getValueParameters(); - JetType expectedType = context.expectedType; - boolean functionTypeExpected = expectedType != TypeUtils.NO_EXPECTED_TYPE && JetStandardClasses.isFunctionType(expectedType); List expectedValueParameters = (functionTypeExpected) - ? JetStandardClasses.getValueParameters(functionDescriptor, expectedType) + ? JetStandardClasses.getValueParameters(functionDescriptor, context.expectedType) : null; - if (functionTypeExpected && declaredValueParameters.isEmpty() && expectedValueParameters.size() == 1) { + boolean hasDeclaredValueParameters = functionLiteral.getValueParameterList() != null; + if (functionTypeExpected && !hasDeclaredValueParameters && expectedValueParameters.size() == 1) { ValueParameterDescriptor valueParameterDescriptor = expectedValueParameters.get(0); ValueParameterDescriptor it = new ValueParameterDescriptorImpl( functionDescriptor, 0, Collections.emptyList(), "it", valueParameterDescriptor.getInType(), valueParameterDescriptor.getOutType(), valueParameterDescriptor.hasDefaultValue(), valueParameterDescriptor.getVarargElementType() ); valueParameterDescriptors.add(it); - parameterTypes.add(it.getOutType()); context.trace.record(AUTO_CREATED_IT, it); } else { @@ -113,54 +176,9 @@ public class ClosureExpressionsTypingVisitor extends ExpressionTypingVisitor { } } ValueParameterDescriptor valueParameterDescriptor = context.getClassDescriptorResolver().resolveValueParameterDescriptor(functionDescriptor, declaredParameter, i, type); - parameterTypes.add(valueParameterDescriptor.getOutType()); valueParameterDescriptors.add(valueParameterDescriptor); } } - - JetType effectiveReceiverType; - if (receiverTypeRef == null) { - if (functionTypeExpected) { - effectiveReceiverType = JetStandardClasses.getReceiverType(expectedType); - } - else { - effectiveReceiverType = null; - } - } - else { - effectiveReceiverType = receiverType; - } - functionDescriptor.initialize(effectiveReceiverType, NO_RECEIVER, Collections.emptyList(), valueParameterDescriptors, null, Modality.FINAL, Visibility.LOCAL); - context.trace.record(BindingContext.FUNCTION, expression, functionDescriptor); - - JetType returnType = TypeUtils.NO_EXPECTED_TYPE; - JetScope functionInnerScope = FunctionDescriptorUtil.getFunctionInnerScope(context.scope, functionDescriptor, context.trace); - JetTypeReference returnTypeRef = functionLiteral.getReturnTypeRef(); - if (returnTypeRef != null) { - returnType = context.getTypeResolver().resolveType(context.scope, returnTypeRef); - context.getServices().checkFunctionReturnType(expression, context.replaceScope(functionInnerScope). - replaceExpectedType(returnType).replaceExpectedReturnType(returnType).replaceDataFlowInfo(context.dataFlowInfo)); - } - else { - if (functionTypeExpected) { - returnType = JetStandardClasses.obtainReturnTypeFromFunctionType(expectedType); - } -// } - returnType = context.getServices().getBlockReturnedType(functionInnerScope, functionLiteral.getBodyExpression(), CoercionStrategy.COERCION_TO_UNIT, - context.replaceExpectedType(returnType).replaceExpectedReturnType(returnType)); - } - JetType safeReturnType = returnType == null ? ErrorUtils.createErrorType("") : returnType; - functionDescriptor.setReturnType(safeReturnType); - - if (functionTypeExpected) { - JetType expectedReturnType = JetStandardClasses.obtainReturnTypeFromFunctionType(expectedType); - if (JetStandardClasses.isUnit(expectedReturnType)) { - functionDescriptor.setReturnType(expectedReturnType); - return DataFlowUtils.checkType(JetStandardClasses.getFunctionType(Collections.emptyList(), effectiveReceiverType, parameterTypes, expectedReturnType), expression, context); - } - - } - return DataFlowUtils.checkType(JetStandardClasses.getFunctionType(Collections.emptyList(), effectiveReceiverType, parameterTypes, safeReturnType), expression, context); + return valueParameterDescriptors; } - } diff --git a/compiler/testData/checkerWithErrorTypes/quick/regressions/kt352.jet b/compiler/testData/checkerWithErrorTypes/quick/regressions/kt352.jet new file mode 100644 index 00000000000..da402197d5f --- /dev/null +++ b/compiler/testData/checkerWithErrorTypes/quick/regressions/kt352.jet @@ -0,0 +1,27 @@ +//KT-352 Function variable declaration type isn't checked inside a function body + +namespace kt352 + +val f : fun(Any) : Unit = { () : Unit => } //type mismatch + +fun foo() { + val f : fun(Any) : Unit = { () : Unit => } //!!! no error +} + +class A() { + val f : fun(Any) : Unit = { () : Unit => } //type mismatch +} + +//more tests +val g : fun() : Unit = { (): Int => 42 } + +val h : fun() : Unit = { doSmth() } + +fun doSmth(): Int = 42 +fun doSmth(a: String) {} + +val testIt : fun(Any) : Unit = { + if (it is String) { + doSmth(it) + } +} \ No newline at end of file