diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowBuilder.java b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowBuilder.java index 7425493651c..aed6690bbaf 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowBuilder.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowBuilder.java @@ -49,8 +49,10 @@ public interface JetControlFlowBuilder { void exitSubroutine(@NotNull JetDeclaration subroutine); - @Nullable + @NotNull JetElement getCurrentSubroutine(); + @Nullable + JetElement getReturnSubroutine(); void returnValue(@NotNull JetExpression returnExpression, @NotNull JetElement subroutine); void returnNoValue(@NotNull JetElement returnExpression, @NotNull JetElement subroutine); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowBuilderAdapter.java b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowBuilderAdapter.java index df5470480f4..609b6f0fd3f 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowBuilderAdapter.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowBuilderAdapter.java @@ -140,13 +140,20 @@ public class JetControlFlowBuilderAdapter implements JetControlFlowBuilder { builder.exitSubroutine(subroutine); } + @NotNull @Override - @Nullable public JetElement getCurrentSubroutine() { assert builder != null; return builder.getCurrentSubroutine(); } + @Override + @Nullable + public JetElement getReturnSubroutine() { + assert builder != null; + return builder.getReturnSubroutine(); + } + @Override public void returnValue(@NotNull JetExpression returnExpression, @NotNull JetElement subroutine) { assert builder != null; diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java index ac4eb24fd0f..6844d746734 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java @@ -528,8 +528,8 @@ public class JetControlFlowProcessor { } JetSimpleNameExpression labelElement = expression.getTargetLabel(); JetElement subroutine; + String labelName = expression.getLabelName(); if (labelElement != null) { - String labelName = expression.getLabelName(); assert labelName != null; PsiElement labeledElement = BindingContextUtils.resolveToDeclarationPsiElement(trace.getBindingContext(), labelElement); if (labeledElement != null) { @@ -541,13 +541,18 @@ public class JetControlFlowProcessor { } } else { - subroutine = builder.getCurrentSubroutine(); + subroutine = builder.getReturnSubroutine(); // TODO : a context check } //todo cache JetFunctionLiteral instead if (subroutine instanceof JetFunctionLiteralExpression) { subroutine = ((JetFunctionLiteralExpression) subroutine).getFunctionLiteral(); } + boolean error = false; + if (builder.getCurrentSubroutine() != subroutine) { + trace.report(RETURN_NOT_ALLOWED.on(expression)); + error = true; + } if (subroutine instanceof JetFunction || subroutine instanceof JetPropertyAccessor || subroutine instanceof JetConstructor) { if (returnedExpression == null) { builder.returnNoValue(expression, subroutine); @@ -556,9 +561,9 @@ public class JetControlFlowProcessor { builder.returnValue(expression, subroutine); } } - else { + else if (!error) { if (labelElement != null) { - trace.report(NOT_A_RETURN_LABEL.on(expression, expression.getLabelName())); + trace.report(NOT_A_RETURN_LABEL.on(expression, labelName)); } else { trace.report(RETURN_NOT_ALLOWED.on(expression)); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetFlowInformationProvider.java b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetFlowInformationProvider.java index 91b653fa8f3..966adee2c24 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetFlowInformationProvider.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetFlowInformationProvider.java @@ -75,17 +75,22 @@ public class JetFlowInformationProvider { Pseudocode pseudocode = pseudocodeMap.get(subroutine); assert pseudocode != null; + final Set instructions = Sets.newHashSet(pseudocode.getInstructions()); SubroutineExitInstruction exitInstruction = pseudocode.getExitInstruction(); for (Instruction previousInstruction : exitInstruction.getPreviousInstructions()) { previousInstruction.accept(new InstructionVisitor() { @Override public void visitReturnValue(ReturnValueInstruction instruction) { - returnedExpressions.add((JetExpression) instruction.getElement()); + if (instructions.contains(instruction)) { //exclude non-local return expressions + returnedExpressions.add((JetExpression) instruction.getElement()); + } } @Override public void visitReturnNoValue(ReturnNoValueInstruction instruction) { - returnedExpressions.add((JetExpression) instruction.getElement()); + if (instructions.contains(instruction)) { + returnedExpressions.add((JetExpression) instruction.getElement()); + } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/JetControlFlowInstructionsGenerator.java b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/JetControlFlowInstructionsGenerator.java index 261a27a31b7..ea1730d948d 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/JetControlFlowInstructionsGenerator.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/JetControlFlowInstructionsGenerator.java @@ -45,7 +45,12 @@ public class JetControlFlowInstructionsGenerator extends JetControlFlowBuilderAd @Override public void enterSubroutine(@NotNull JetDeclaration subroutine) { - pushBuilder(subroutine, subroutine); + if (builder != null && subroutine instanceof JetFunctionLiteral) { + pushBuilder(subroutine, builder.getReturnSubroutine()); + } + else { + pushBuilder(subroutine, subroutine); + } assert builder != null; builder.enterSubroutine(subroutine); } @@ -66,13 +71,13 @@ public class JetControlFlowInstructionsGenerator extends JetControlFlowBuilderAd private final Pseudocode pseudocode; private final Label error; private final Label sink; - private final JetElement currentSubroutine; + private final JetElement returnSubroutine; - private JetControlFlowInstructionsGeneratorWorker(@NotNull JetElement scopingElement, @NotNull JetElement currentSubroutine) { + private JetControlFlowInstructionsGeneratorWorker(@NotNull JetElement scopingElement, @NotNull JetElement returnSubroutine) { this.pseudocode = new Pseudocode(scopingElement); this.error = pseudocode.createLabel("error"); this.sink = pseudocode.createLabel("sink"); - this.currentSubroutine = currentSubroutine; + this.returnSubroutine = returnSubroutine; } public Pseudocode getPseudocode() { @@ -134,9 +139,15 @@ public class JetControlFlowInstructionsGenerator extends JetControlFlowBuilderAd add(new SubroutineEnterInstruction(subroutine)); } + @NotNull @Override public JetElement getCurrentSubroutine() { - return currentSubroutine;// subroutineInfo.empty() ? null : subroutineInfo.peek().getElement(); + return pseudocode.getCorrespondingElement(); + } + + @Override + public JetElement getReturnSubroutine() { + return returnSubroutine;// subroutineInfo.empty() ? null : subroutineInfo.peek().getElement(); } @Override diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/FunctionDescriptorUtil.java b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/FunctionDescriptorUtil.java index 32e19f286de..ac115746064 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/FunctionDescriptorUtil.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/FunctionDescriptorUtil.java @@ -89,7 +89,7 @@ public class FunctionDescriptorUtil { ReceiverDescriptor.NO_RECEIVER, Collections.emptyList(), JetStandardClasses.getValueParameters(functionDescriptor, functionType), - JetStandardClasses.getReturnType(functionType), + JetStandardClasses.obtainReturnTypeFromFunctionType(functionType), Modality.FINAL, Visibility.LOCAL); } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetPsiUtil.java b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetPsiUtil.java index 3d828b01f86..0af3fab3d14 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetPsiUtil.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetPsiUtil.java @@ -1,5 +1,6 @@ package org.jetbrains.jet.lang.psi; +import com.intellij.psi.PsiElement; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lexer.JetTokens; @@ -62,4 +63,14 @@ public class JetPsiUtil { } return rootElements; } + + @Nullable + public static JetNamedFunction getSurroundingFunction(@Nullable PsiElement element) { + while (element != null) { + if (element instanceof JetNamedFunction) return (JetNamedFunction) element; + if (element instanceof JetClassOrObject || element instanceof JetNamespace) return null; + element = element.getParent(); + } + return null; + } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingContextUtils.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingContextUtils.java index c617571bba0..1fdff1d39fb 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingContextUtils.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingContextUtils.java @@ -4,8 +4,12 @@ import com.intellij.psi.PsiElement; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; +import org.jetbrains.jet.lang.descriptors.FunctionDescriptor; import org.jetbrains.jet.lang.descriptors.VariableDescriptor; import org.jetbrains.jet.lang.psi.*; +import org.jetbrains.jet.lang.types.JetType; + +import static org.jetbrains.jet.lang.resolve.BindingContext.DECLARATION_TO_DESCRIPTOR; /** * @author abreslav @@ -40,4 +44,12 @@ public class BindingContextUtils { } return null; } + + @Nullable + public static JetType getFunctionReturnType(@NotNull BindingContext bindingContext, @NotNull JetFunction function) { + DeclarationDescriptor descriptor = bindingContext.get(DECLARATION_TO_DESCRIPTOR, function); + assert descriptor instanceof FunctionDescriptor; + FunctionDescriptor functionDescriptor = (FunctionDescriptor) descriptor; + return functionDescriptor.getReturnType(); + } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/JetStandardClasses.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/JetStandardClasses.java index c76c5c797ca..c84b501bc34 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/JetStandardClasses.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/JetStandardClasses.java @@ -385,7 +385,7 @@ public class JetStandardClasses { } @NotNull - public static JetType getReturnType(@NotNull JetType type) { + public static JetType obtainReturnTypeFromFunctionType(@NotNull JetType type) { assert isFunctionType(type); List arguments = type.getArguments(); return arguments.get(arguments.size() - 1).getType(); 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 7abdb5cefe9..2c129f978a3 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 @@ -61,6 +61,7 @@ public class ClosureExpressionsTypingVisitor extends ExpressionTypingVisitor { @Override public JetType visitFunctionLiteralExpression(JetFunctionLiteralExpression expression, ExpressionTypingContext context) { JetFunctionLiteral functionLiteral = expression.getFunctionLiteral(); + if (functionLiteral.getBodyExpression() == null) return null; JetTypeReference receiverTypeRef = functionLiteral.getReceiverTypeRef(); final JetType receiverType; @@ -137,19 +138,22 @@ public class ClosureExpressionsTypingVisitor extends ExpressionTypingVisitor { JetTypeReference returnTypeRef = functionLiteral.getReturnTypeRef(); if (returnTypeRef != null) { returnType = context.getTypeResolver().resolveType(context.scope, returnTypeRef); - context.getServices().checkFunctionReturnType(expression, context.replaceScope(functionInnerScope).replaceExpectedReturnType(returnType).replaceDataFlowInfo(context.dataFlowInfo)); + context.getServices().checkFunctionReturnType(expression, context.replaceScope(functionInnerScope). + replaceExpectedType(returnType).replaceExpectedReturnType(returnType).replaceDataFlowInfo(context.dataFlowInfo)); } else { if (functionTypeExpected) { - returnType = JetStandardClasses.getReturnType(expectedType); + returnType = JetStandardClasses.obtainReturnTypeFromFunctionType(expectedType); } - returnType = context.getServices().getBlockReturnedType(functionInnerScope, functionLiteral.getBodyExpression(), CoercionStrategy.COERCION_TO_UNIT, context.replaceExpectedType(returnType).replaceExpectedReturnType(returnType)); +// } + 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.getReturnType(expectedType); + JetType expectedReturnType = JetStandardClasses.obtainReturnTypeFromFunctionType(expectedType); if (JetStandardClasses.isUnit(expectedReturnType)) { functionDescriptor.setReturnType(expectedReturnType); return DataFlowUtils.checkType(JetStandardClasses.getFunctionType(Collections.emptyList(), effectiveReceiverType, parameterTypes, expectedReturnType), expression, context); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ControlStructureTypingVisitor.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ControlStructureTypingVisitor.java index 4bf50a63007..e0e1a312e70 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ControlStructureTypingVisitor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ControlStructureTypingVisitor.java @@ -1,12 +1,14 @@ package org.jetbrains.jet.lang.types.expressions; import com.intellij.psi.PsiElement; +import com.intellij.psi.util.PsiTreeUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.FunctionDescriptor; import org.jetbrains.jet.lang.descriptors.VariableDescriptor; import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.BindingContext; +import org.jetbrains.jet.lang.resolve.BindingContextUtils; import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo; import org.jetbrains.jet.lang.resolve.calls.OverloadResolutionResults; import org.jetbrains.jet.lang.resolve.scopes.JetScope; @@ -40,7 +42,6 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor { JetType conditionType = facade.getType(condition, context.replaceScope(scope)); if (conditionType != null && !isBoolean(context.semanticServices, conditionType)) { -// context.trace.getErrorHandler().genericError(condition.getNode(), "Condition must be of type Boolean, but was of type " + conditionType); context.trace.report(TYPE_MISMATCH_IN_CONDITION.on(condition, conditionType)); } } @@ -201,7 +202,6 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor { if (expectedParameterType != null && actualParameterType != null && !context.semanticServices.getTypeChecker().isSubtypeOf(expectedParameterType, actualParameterType)) { -// context.trace.getErrorHandler().genericError(typeReference.getNode(), "The loop iterates over values of type " + expectedParameterType + " but the parameter is declared to be " + actualParameterType); context.trace.report(TYPE_MISMATCH_IN_FOR_LOOP.on(typeReference, expectedParameterType, actualParameterType)); } } @@ -238,11 +238,9 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor { boolean hasNextPropertySupported = hasNextProperty != null; if (hasNextFunctionSupported && hasNextPropertySupported && !ErrorUtils.isErrorType(iteratorType)) { // TODO : overload resolution rules impose priorities here??? -// context.trace.getErrorHandler().genericError(reportErrorsOn, "An ambiguity between 'iterator().hasNext()' function and 'iterator().hasNext' property"); context.trace.report(HAS_NEXT_PROPERTY_AND_FUNCTION_AMBIGUITY.on(loopRangeExpression)); } else if (!hasNextFunctionSupported && !hasNextPropertySupported) { -// context.trace.getErrorHandler().genericError(reportErrorsOn, "Loop range must have an 'iterator().hasNext()' function or an 'iterator().hasNext' property"); context.trace.report(HAS_NEXT_MISSING.on(loopRangeExpression)); } else { @@ -251,10 +249,8 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor { OverloadResolutionResults nextResolutionResults = context.resolveExactSignature(new TransientReceiver(iteratorType), "next", Collections.emptyList()); if (nextResolutionResults.isAmbiguity()) { -// context.trace.getErrorHandler().genericError(reportErrorsOn, "Method 'iterator().next()' is ambiguous for this expression"); context.trace.report(NEXT_AMBIGUITY.on(loopRangeExpression)); } else if (nextResolutionResults.isNothing()) { -// context.trace.getErrorHandler().genericError(reportErrorsOn, "Loop range must have an 'iterator().next()' method"); context.trace.report(NEXT_MISSING.on(loopRangeExpression)); } else { FunctionDescriptor nextFunction = nextResolutionResults.getResult().getResultingDescriptor(); @@ -272,7 +268,6 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor { context.trace.report(ITERATOR_AMBIGUITY.on(loopRangeExpression, iteratorResolutionResults.getResults())); } else { -// context.trace.getErrorHandler().genericError(reportErrorsOn, errorMessage); context.trace.report(ITERATOR_MISSING.on(loopRangeExpression)); } } @@ -283,7 +278,6 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor { private FunctionDescriptor checkHasNextFunctionSupport(@NotNull JetExpression loopRange, @NotNull JetType iteratorType, ExpressionTypingContext context) { OverloadResolutionResults hasNextResolutionResults = context.resolveExactSignature(new TransientReceiver(iteratorType), "hasNext", Collections.emptyList()); if (hasNextResolutionResults.isAmbiguity()) { -// context.trace.getErrorHandler().genericError(loopRange.getNode(), "Method 'iterator().hasNext()' is ambiguous for this expression"); context.trace.report(HAS_NEXT_FUNCTION_AMBIGUITY.on(loopRange)); } else if (hasNextResolutionResults.isNothing()) { return null; @@ -291,7 +285,6 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor { assert hasNextResolutionResults.isSuccess(); JetType hasNextReturnType = hasNextResolutionResults.getResult().getResultingDescriptor().getReturnType(); if (!isBoolean(context.semanticServices, hasNextReturnType)) { -// context.trace.getErrorHandler().genericError(loopRange.getNode(), "The 'iterator().hasNext()' method of the loop range must return Boolean, but returns " + hasNextReturnType); context.trace.report(HAS_NEXT_FUNCTION_TYPE_MISMATCH.on(loopRange, hasNextReturnType)); } } @@ -308,11 +301,9 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor { JetType hasNextReturnType = hasNextProperty.getOutType(); if (hasNextReturnType == null) { // TODO : accessibility -// context.trace.getErrorHandler().genericError(loopRange.getNode(), "The 'iterator().hasNext' property of the loop range must be readable"); context.trace.report(HAS_NEXT_MUST_BE_READABLE.on(loopRange)); } else if (!isBoolean(context.semanticServices, hasNextReturnType)) { -// context.trace.getErrorHandler().genericError(loopRange.getNode(), "The 'iterator().hasNext' property of the loop range must return Boolean, but returns " + hasNextReturnType); context.trace.report(HAS_NEXT_PROPERTY_TYPE_MISMATCH.on(loopRange, hasNextReturnType)); } } @@ -373,20 +364,33 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor { public JetType visitReturnExpression(JetReturnExpression expression, ExpressionTypingContext context) { context.labelResolver.recordLabel(expression, context); if (context.expectedReturnType == TypeUtils.FORBIDDEN) { -// context.trace.getErrorHandler().genericError(expression.getNode(), "'return' is not allowed here"); context.trace.report(RETURN_NOT_ALLOWED.on(expression)); return null; } JetExpression returnedExpression = expression.getReturnedExpression(); - JetType returnedType = JetStandardClasses.getUnitType(); - if (returnedExpression != null) { - facade.getType(returnedExpression, context.replaceExpectedType(context.expectedReturnType).replaceScope(context.scope)); + JetType expectedType = context.expectedReturnType; + if (expression.getTargetLabel() == null) { + if (PsiTreeUtil.getParentOfType(expression, JetFunctionLiteral.class) == + PsiTreeUtil.getParentOfType(expression, JetDeclaration.class)) { // expression is located in function literal + JetNamedFunction function = JetPsiUtil.getSurroundingFunction(expression); + if (function != null && function.getReturnTypeRef() != null) { + expectedType = BindingContextUtils.getFunctionReturnType(context.trace.getBindingContext(), function); + } + } } else { - if (context.expectedReturnType != TypeUtils.NO_EXPECTED_TYPE && !JetStandardClasses.isUnit(context.expectedReturnType)) { -// context.trace.getErrorHandler().genericError(expression.getNode(), "This function must return a value of type " + context.expectedReturnType); - context.trace.report(RETURN_TYPE_MISMATCH.on(expression, context.expectedReturnType)); + PsiElement element = context.trace.get(LABEL_TARGET, expression.getTargetLabel()); + if (element instanceof JetFunction && ((JetFunction) element).getReturnTypeRef() != null) { + expectedType = BindingContextUtils.getFunctionReturnType(context.trace.getBindingContext(), (JetFunction) element); + } + } + if (returnedExpression != null) { + facade.getType(returnedExpression, context.replaceExpectedType(expectedType).replaceScope(context.scope)); + } + else { + if (expectedType != TypeUtils.NO_EXPECTED_TYPE && expectedType != null && !JetStandardClasses.isUnit(expectedType)) { + context.trace.report(RETURN_TYPE_MISMATCH.on(expression, expectedType)); } } return DataFlowUtils.checkType(JetStandardClasses.getNothingType(), expression, context); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingServices.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingServices.java index 93a98b4ddae..cfbe176d509 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingServices.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingServices.java @@ -122,7 +122,9 @@ public class ExpressionTypingServices { if (function instanceof JetFunctionLiteralExpression) { JetFunctionLiteralExpression functionLiteralExpression = (JetFunctionLiteralExpression) function; - getBlockReturnedType(newContext.scope, functionLiteralExpression.getBodyExpression(), CoercionStrategy.COERCION_TO_UNIT, newContext); + JetBlockExpression blockExpression = functionLiteralExpression.getBodyExpression(); + assert blockExpression != null; + getBlockReturnedType(newContext.scope, blockExpression, CoercionStrategy.COERCION_TO_UNIT, context); } else { expressionTypingFacade.getType(bodyExpression, newContext); diff --git a/compiler/testData/checkerWithErrorTypes/full/FunctionReturnTypes.jet b/compiler/testData/checkerWithErrorTypes/full/FunctionReturnTypes.jet index 5a041264da5..311a3b16aa6 100644 --- a/compiler/testData/checkerWithErrorTypes/full/FunctionReturnTypes.jet +++ b/compiler/testData/checkerWithErrorTypes/full/FunctionReturnTypes.jet @@ -5,9 +5,12 @@ fun unitEmpty() : Unit {} fun unitEmptyReturn() : Unit {return} fun unitIntReturn() : Unit {return 1} fun unitUnitReturn() : Unit {return ()} -fun test1() : Any = {return} +fun test1() : Any = {return} fun test2() : Any = @a {return@a 1} fun test3() : Any { return } +fun test4(): fun(): Unit = { return@test4 } +fun test5(): Any = @{ return@ } +fun test5(): Any = {return 1} fun bbb() { return 1 diff --git a/compiler/testData/checkerWithErrorTypes/full/Return.jet b/compiler/testData/checkerWithErrorTypes/full/Return.jet index 5b087076efe..905a88ed092 100644 --- a/compiler/testData/checkerWithErrorTypes/full/Return.jet +++ b/compiler/testData/checkerWithErrorTypes/full/Return.jet @@ -6,12 +6,12 @@ class A { if (1 < 2) return@inner else - return@outer + return@outer } if (1 < 2) - return@A + return@A else if (2 < 3) - return@inner + return@inner return@outer } -} +} \ No newline at end of file diff --git a/compiler/testData/checkerWithErrorTypes/quick/regressions/kt411.jet b/compiler/testData/checkerWithErrorTypes/quick/regressions/kt411.jet new file mode 100644 index 00000000000..aed23ee9382 --- /dev/null +++ b/compiler/testData/checkerWithErrorTypes/quick/regressions/kt411.jet @@ -0,0 +1,69 @@ +//kt-411 Wrong type expected when returning from a function literal + +namespace kt411 + +fun f() { + invoker( + @{ + return@ 11 // expects Function, but should expect Int + } + ) +} +fun invoker(gen : fun() : Int) : Int = 0 + +//more tests +fun t1() { + val v = @{ () : Int => + return@ 111 + } +} + +fun t2() : String { + val g : fun(): Int = @{ + if (true) { + return@ 1 + } + return "s" + } + return "s" +} + +fun t3() : String { + invoker( + @{ + if (true) { + return@t3 "1" + } + else { + return 2 + } + return@ 0 + } + ) + invoker( + @{ (): Int => + return@ 1 + } + ) + invoker( + { + return "0" + } + ) + return "2" +} + +fun t4() : Int { + val h : fun (): String = @l{ + return@l "a" + } + val g : fun (): String = @{ () : String => + return@ "a" + } + + fun inner(): String { + return "2" + } + + return 12 +} \ No newline at end of file diff --git a/idea/testData/checker/FunctionReturnTypes.jet b/idea/testData/checker/FunctionReturnTypes.jet index 5730b95e18b..b912b8d3022 100644 --- a/idea/testData/checker/FunctionReturnTypes.jet +++ b/idea/testData/checker/FunctionReturnTypes.jet @@ -5,7 +5,7 @@ fun unitEmpty() : Unit {} fun unitEmptyReturn() : Unit {return} fun unitIntReturn() : Unit {return 1} fun unitUnitReturn() : Unit {return ()} -fun test1() : Any = {return} +fun test1() : Any = { return } fun test2() : Any = @a {return@a 1} fun test3() : Any { return }