Local returns are only allowed with explicitly specified return types

This is a temporary limitation: otherwise type inference is having trouble to account for all the returned expressions.
 We will fix the inference and remove the limitation
This commit is contained in:
Andrey Breslav
2013-08-21 18:05:16 +04:00
parent d97506476f
commit 08625a6b2f
16 changed files with 52 additions and 23 deletions
@@ -535,6 +535,7 @@ public interface Errors {
DiagnosticFactory0<JetSimpleNameExpression> EXPRESSION_EXPECTED_NAMESPACE_FOUND = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<JetReturnExpression> RETURN_NOT_ALLOWED = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<JetReturnExpression> RETURN_NOT_ALLOWED_EXPLICIT_RETURN_TYPE_REQUIRED = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<JetReturnExpression> RETURN_IN_FUNCTION_WITH_EXPRESSION_BODY = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<JetDeclarationWithBody>
NO_RETURN_IN_FUNCTION_WITH_BLOCK_BODY = DiagnosticFactory0.create(ERROR, DECLARATION_WITH_BODY);
@@ -83,6 +83,7 @@ public class DefaultErrorMessages {
MAP.put(TYPECHECKER_HAS_RUN_INTO_RECURSIVE_PROBLEM,
"Type checking has run into a recursive problem. Easiest workaround: specify types of your declarations explicitly"); // TODO: message
MAP.put(RETURN_NOT_ALLOWED, "'return' is not allowed here");
MAP.put(RETURN_NOT_ALLOWED_EXPLICIT_RETURN_TYPE_REQUIRED, "'return' is only allowed in function literals that have return types specified explicitly");
MAP.put(PROJECTION_IN_IMMEDIATE_ARGUMENT_TO_SUPERTYPE, "Projections are not allowed for immediate arguments of a supertype");
MAP.put(LABEL_NAME_CLASH, "There is more than one label with such a name in this scope");
MAP.put(EXPRESSION_EXPECTED_NAMESPACE_FOUND, "Expression expected, but a namespace name found");
@@ -282,6 +282,8 @@ public class ClosureExpressionsTypingVisitor extends ExpressionTypingVisitor {
JetType declaredReturnType = null;
if (returnTypeRef != null) {
declaredReturnType = context.expressionTypingServices.getTypeResolver().resolveType(context.scope, returnTypeRef, context.trace, true);
// This is needed for ControlStructureTypingVisitor#visitReturnExpression() to properly type-check returned expressions
functionDescriptor.setReturnType(declaredReturnType);
if (expectedReturnType != null) {
if (!JetTypeChecker.INSTANCE.isSubtypeOf(declaredReturnType, expectedReturnType)) {
temporaryTrace.report(EXPECTED_RETURN_TYPE_MISMATCH.on(returnTypeRef, expectedReturnType));
@@ -58,6 +58,8 @@ import static org.jetbrains.jet.lang.types.expressions.ExpressionTypingUtils.*;
public class ControlStructureTypingVisitor extends ExpressionTypingVisitor {
public static final String RETURN_NOT_ALLOWED_MESSAGE = "Return not allowed";
protected ControlStructureTypingVisitor(@NotNull ExpressionTypingInternals facade) {
super(facade);
}
@@ -504,7 +506,7 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor {
} while (containingFunction instanceof JetFunctionLiteral);
// Unqualified, in a function literal
context.trace.report(RETURN_NOT_ALLOWED.on(expression));
resultType = ErrorUtils.createErrorType("Return not allowed");
resultType = ErrorUtils.createErrorType(RETURN_NOT_ALLOWED_MESSAGE);
}
if (containingFunctionDescriptor != null) {
expectedType = DescriptorUtils.getFunctionExpectedReturnType(containingFunctionDescriptor, (JetElement) containingFunction);
@@ -513,17 +515,24 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor {
else {
// Outside a function
context.trace.report(RETURN_NOT_ALLOWED.on(expression));
resultType = ErrorUtils.createErrorType("Return not allowed");
resultType = ErrorUtils.createErrorType(RETURN_NOT_ALLOWED_MESSAGE);
}
}
else if (labelTargetElement != null) {
SimpleFunctionDescriptor functionDescriptor = context.trace.get(FUNCTION, labelTargetElement);
if (functionDescriptor != null) {
expectedType = DescriptorUtils.getFunctionExpectedReturnType(functionDescriptor, labelTargetElement);
if (functionDescriptor != containingFunctionDescriptor) {
boolean inLambdaWithNoExplicitType = expectedType == TypeUtils.NO_EXPECTED_TYPE;
if (inLambdaWithNoExplicitType) {
// expectedType is NO_EXPECTED_TYPE iff the return type of the corresponding function descriptor is not computed yet
// our temporary policy is to prohibit returns in this case. It mostly applies to local returns in lambdas
context.trace.report(RETURN_NOT_ALLOWED_EXPLICIT_RETURN_TYPE_REQUIRED.on(expression));
resultType = ErrorUtils.createErrorType(RETURN_NOT_ALLOWED_MESSAGE);
}
else if (functionDescriptor != containingFunctionDescriptor) {
// Qualified, non-local
context.trace.report(RETURN_NOT_ALLOWED.on(expression));
resultType = ErrorUtils.createErrorType("Return not allowed");
resultType = ErrorUtils.createErrorType(RETURN_NOT_ALLOWED_MESSAGE);
}
}
else {