Merge remote branch 'origin/master'

This commit is contained in:
Andrey Breslav
2011-11-10 14:51:54 +03:00
16 changed files with 179 additions and 44 deletions
@@ -49,8 +49,10 @@ public interface JetControlFlowBuilder {
void exitSubroutine(@NotNull JetDeclaration subroutine); void exitSubroutine(@NotNull JetDeclaration subroutine);
@Nullable @NotNull
JetElement getCurrentSubroutine(); JetElement getCurrentSubroutine();
@Nullable
JetElement getReturnSubroutine();
void returnValue(@NotNull JetExpression returnExpression, @NotNull JetElement subroutine); void returnValue(@NotNull JetExpression returnExpression, @NotNull JetElement subroutine);
void returnNoValue(@NotNull JetElement returnExpression, @NotNull JetElement subroutine); void returnNoValue(@NotNull JetElement returnExpression, @NotNull JetElement subroutine);
@@ -140,13 +140,20 @@ public class JetControlFlowBuilderAdapter implements JetControlFlowBuilder {
builder.exitSubroutine(subroutine); builder.exitSubroutine(subroutine);
} }
@NotNull
@Override @Override
@Nullable
public JetElement getCurrentSubroutine() { public JetElement getCurrentSubroutine() {
assert builder != null; assert builder != null;
return builder.getCurrentSubroutine(); return builder.getCurrentSubroutine();
} }
@Override
@Nullable
public JetElement getReturnSubroutine() {
assert builder != null;
return builder.getReturnSubroutine();
}
@Override @Override
public void returnValue(@NotNull JetExpression returnExpression, @NotNull JetElement subroutine) { public void returnValue(@NotNull JetExpression returnExpression, @NotNull JetElement subroutine) {
assert builder != null; assert builder != null;
@@ -528,8 +528,8 @@ public class JetControlFlowProcessor {
} }
JetSimpleNameExpression labelElement = expression.getTargetLabel(); JetSimpleNameExpression labelElement = expression.getTargetLabel();
JetElement subroutine; JetElement subroutine;
String labelName = expression.getLabelName();
if (labelElement != null) { if (labelElement != null) {
String labelName = expression.getLabelName();
assert labelName != null; assert labelName != null;
PsiElement labeledElement = BindingContextUtils.resolveToDeclarationPsiElement(trace.getBindingContext(), labelElement); PsiElement labeledElement = BindingContextUtils.resolveToDeclarationPsiElement(trace.getBindingContext(), labelElement);
if (labeledElement != null) { if (labeledElement != null) {
@@ -541,13 +541,18 @@ public class JetControlFlowProcessor {
} }
} }
else { else {
subroutine = builder.getCurrentSubroutine(); subroutine = builder.getReturnSubroutine();
// TODO : a context check // TODO : a context check
} }
//todo cache JetFunctionLiteral instead //todo cache JetFunctionLiteral instead
if (subroutine instanceof JetFunctionLiteralExpression) { if (subroutine instanceof JetFunctionLiteralExpression) {
subroutine = ((JetFunctionLiteralExpression) subroutine).getFunctionLiteral(); 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 (subroutine instanceof JetFunction || subroutine instanceof JetPropertyAccessor || subroutine instanceof JetConstructor) {
if (returnedExpression == null) { if (returnedExpression == null) {
builder.returnNoValue(expression, subroutine); builder.returnNoValue(expression, subroutine);
@@ -556,9 +561,9 @@ public class JetControlFlowProcessor {
builder.returnValue(expression, subroutine); builder.returnValue(expression, subroutine);
} }
} }
else { else if (!error) {
if (labelElement != null) { if (labelElement != null) {
trace.report(NOT_A_RETURN_LABEL.on(expression, expression.getLabelName())); trace.report(NOT_A_RETURN_LABEL.on(expression, labelName));
} }
else { else {
trace.report(RETURN_NOT_ALLOWED.on(expression)); trace.report(RETURN_NOT_ALLOWED.on(expression));
@@ -75,17 +75,22 @@ public class JetFlowInformationProvider {
Pseudocode pseudocode = pseudocodeMap.get(subroutine); Pseudocode pseudocode = pseudocodeMap.get(subroutine);
assert pseudocode != null; assert pseudocode != null;
final Set<Instruction> instructions = Sets.newHashSet(pseudocode.getInstructions());
SubroutineExitInstruction exitInstruction = pseudocode.getExitInstruction(); SubroutineExitInstruction exitInstruction = pseudocode.getExitInstruction();
for (Instruction previousInstruction : exitInstruction.getPreviousInstructions()) { for (Instruction previousInstruction : exitInstruction.getPreviousInstructions()) {
previousInstruction.accept(new InstructionVisitor() { previousInstruction.accept(new InstructionVisitor() {
@Override @Override
public void visitReturnValue(ReturnValueInstruction instruction) { 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 @Override
public void visitReturnNoValue(ReturnNoValueInstruction instruction) { public void visitReturnNoValue(ReturnNoValueInstruction instruction) {
returnedExpressions.add((JetExpression) instruction.getElement()); if (instructions.contains(instruction)) {
returnedExpressions.add((JetExpression) instruction.getElement());
}
} }
@@ -45,7 +45,12 @@ public class JetControlFlowInstructionsGenerator extends JetControlFlowBuilderAd
@Override @Override
public void enterSubroutine(@NotNull JetDeclaration subroutine) { 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; assert builder != null;
builder.enterSubroutine(subroutine); builder.enterSubroutine(subroutine);
} }
@@ -66,13 +71,13 @@ public class JetControlFlowInstructionsGenerator extends JetControlFlowBuilderAd
private final Pseudocode pseudocode; private final Pseudocode pseudocode;
private final Label error; private final Label error;
private final Label sink; 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.pseudocode = new Pseudocode(scopingElement);
this.error = pseudocode.createLabel("error"); this.error = pseudocode.createLabel("error");
this.sink = pseudocode.createLabel("sink"); this.sink = pseudocode.createLabel("sink");
this.currentSubroutine = currentSubroutine; this.returnSubroutine = returnSubroutine;
} }
public Pseudocode getPseudocode() { public Pseudocode getPseudocode() {
@@ -134,9 +139,15 @@ public class JetControlFlowInstructionsGenerator extends JetControlFlowBuilderAd
add(new SubroutineEnterInstruction(subroutine)); add(new SubroutineEnterInstruction(subroutine));
} }
@NotNull
@Override @Override
public JetElement getCurrentSubroutine() { 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 @Override
@@ -89,7 +89,7 @@ public class FunctionDescriptorUtil {
ReceiverDescriptor.NO_RECEIVER, ReceiverDescriptor.NO_RECEIVER,
Collections.<TypeParameterDescriptor>emptyList(), Collections.<TypeParameterDescriptor>emptyList(),
JetStandardClasses.getValueParameters(functionDescriptor, functionType), JetStandardClasses.getValueParameters(functionDescriptor, functionType),
JetStandardClasses.getReturnType(functionType), JetStandardClasses.obtainReturnTypeFromFunctionType(functionType),
Modality.FINAL, Visibility.LOCAL); Modality.FINAL, Visibility.LOCAL);
} }
} }
@@ -1,5 +1,6 @@
package org.jetbrains.jet.lang.psi; package org.jetbrains.jet.lang.psi;
import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lexer.JetTokens; import org.jetbrains.jet.lexer.JetTokens;
@@ -62,4 +63,14 @@ public class JetPsiUtil {
} }
return rootElements; 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;
}
} }
@@ -4,8 +4,12 @@ import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; 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.descriptors.VariableDescriptor;
import org.jetbrains.jet.lang.psi.*; 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 * @author abreslav
@@ -40,4 +44,12 @@ public class BindingContextUtils {
} }
return null; 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();
}
} }
@@ -385,7 +385,7 @@ public class JetStandardClasses {
} }
@NotNull @NotNull
public static JetType getReturnType(@NotNull JetType type) { public static JetType obtainReturnTypeFromFunctionType(@NotNull JetType type) {
assert isFunctionType(type); assert isFunctionType(type);
List<TypeProjection> arguments = type.getArguments(); List<TypeProjection> arguments = type.getArguments();
return arguments.get(arguments.size() - 1).getType(); return arguments.get(arguments.size() - 1).getType();
@@ -61,6 +61,7 @@ public class ClosureExpressionsTypingVisitor extends ExpressionTypingVisitor {
@Override @Override
public JetType visitFunctionLiteralExpression(JetFunctionLiteralExpression expression, ExpressionTypingContext context) { public JetType visitFunctionLiteralExpression(JetFunctionLiteralExpression expression, ExpressionTypingContext context) {
JetFunctionLiteral functionLiteral = expression.getFunctionLiteral(); JetFunctionLiteral functionLiteral = expression.getFunctionLiteral();
if (functionLiteral.getBodyExpression() == null) return null;
JetTypeReference receiverTypeRef = functionLiteral.getReceiverTypeRef(); JetTypeReference receiverTypeRef = functionLiteral.getReceiverTypeRef();
final JetType receiverType; final JetType receiverType;
@@ -137,19 +138,22 @@ public class ClosureExpressionsTypingVisitor extends ExpressionTypingVisitor {
JetTypeReference returnTypeRef = functionLiteral.getReturnTypeRef(); JetTypeReference returnTypeRef = functionLiteral.getReturnTypeRef();
if (returnTypeRef != null) { if (returnTypeRef != null) {
returnType = context.getTypeResolver().resolveType(context.scope, returnTypeRef); 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 { else {
if (functionTypeExpected) { 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("<return type>") : returnType; JetType safeReturnType = returnType == null ? ErrorUtils.createErrorType("<return type>") : returnType;
functionDescriptor.setReturnType(safeReturnType); functionDescriptor.setReturnType(safeReturnType);
if (functionTypeExpected) { if (functionTypeExpected) {
JetType expectedReturnType = JetStandardClasses.getReturnType(expectedType); JetType expectedReturnType = JetStandardClasses.obtainReturnTypeFromFunctionType(expectedType);
if (JetStandardClasses.isUnit(expectedReturnType)) { if (JetStandardClasses.isUnit(expectedReturnType)) {
functionDescriptor.setReturnType(expectedReturnType); functionDescriptor.setReturnType(expectedReturnType);
return DataFlowUtils.checkType(JetStandardClasses.getFunctionType(Collections.<AnnotationDescriptor>emptyList(), effectiveReceiverType, parameterTypes, expectedReturnType), expression, context); return DataFlowUtils.checkType(JetStandardClasses.getFunctionType(Collections.<AnnotationDescriptor>emptyList(), effectiveReceiverType, parameterTypes, expectedReturnType), expression, context);
@@ -1,12 +1,14 @@
package org.jetbrains.jet.lang.types.expressions; package org.jetbrains.jet.lang.types.expressions;
import com.intellij.psi.PsiElement; import com.intellij.psi.PsiElement;
import com.intellij.psi.util.PsiTreeUtil;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor; import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
import org.jetbrains.jet.lang.descriptors.VariableDescriptor; import org.jetbrains.jet.lang.descriptors.VariableDescriptor;
import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.BindingContext; 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.autocasts.DataFlowInfo;
import org.jetbrains.jet.lang.resolve.calls.OverloadResolutionResults; import org.jetbrains.jet.lang.resolve.calls.OverloadResolutionResults;
import org.jetbrains.jet.lang.resolve.scopes.JetScope; 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)); JetType conditionType = facade.getType(condition, context.replaceScope(scope));
if (conditionType != null && !isBoolean(context.semanticServices, conditionType)) { 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)); context.trace.report(TYPE_MISMATCH_IN_CONDITION.on(condition, conditionType));
} }
} }
@@ -201,7 +202,6 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor {
if (expectedParameterType != null && if (expectedParameterType != null &&
actualParameterType != null && actualParameterType != null &&
!context.semanticServices.getTypeChecker().isSubtypeOf(expectedParameterType, actualParameterType)) { !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)); 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; boolean hasNextPropertySupported = hasNextProperty != null;
if (hasNextFunctionSupported && hasNextPropertySupported && !ErrorUtils.isErrorType(iteratorType)) { if (hasNextFunctionSupported && hasNextPropertySupported && !ErrorUtils.isErrorType(iteratorType)) {
// TODO : overload resolution rules impose priorities here??? // 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)); context.trace.report(HAS_NEXT_PROPERTY_AND_FUNCTION_AMBIGUITY.on(loopRangeExpression));
} }
else if (!hasNextFunctionSupported && !hasNextPropertySupported) { 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)); context.trace.report(HAS_NEXT_MISSING.on(loopRangeExpression));
} }
else { else {
@@ -251,10 +249,8 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor {
OverloadResolutionResults<FunctionDescriptor> nextResolutionResults = context.resolveExactSignature(new TransientReceiver(iteratorType), "next", Collections.<JetType>emptyList()); OverloadResolutionResults<FunctionDescriptor> nextResolutionResults = context.resolveExactSignature(new TransientReceiver(iteratorType), "next", Collections.<JetType>emptyList());
if (nextResolutionResults.isAmbiguity()) { if (nextResolutionResults.isAmbiguity()) {
// context.trace.getErrorHandler().genericError(reportErrorsOn, "Method 'iterator().next()' is ambiguous for this expression");
context.trace.report(NEXT_AMBIGUITY.on(loopRangeExpression)); context.trace.report(NEXT_AMBIGUITY.on(loopRangeExpression));
} else if (nextResolutionResults.isNothing()) { } else if (nextResolutionResults.isNothing()) {
// context.trace.getErrorHandler().genericError(reportErrorsOn, "Loop range must have an 'iterator().next()' method");
context.trace.report(NEXT_MISSING.on(loopRangeExpression)); context.trace.report(NEXT_MISSING.on(loopRangeExpression));
} else { } else {
FunctionDescriptor nextFunction = nextResolutionResults.getResult().getResultingDescriptor(); FunctionDescriptor nextFunction = nextResolutionResults.getResult().getResultingDescriptor();
@@ -272,7 +268,6 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor {
context.trace.report(ITERATOR_AMBIGUITY.on(loopRangeExpression, iteratorResolutionResults.getResults())); context.trace.report(ITERATOR_AMBIGUITY.on(loopRangeExpression, iteratorResolutionResults.getResults()));
} }
else { else {
// context.trace.getErrorHandler().genericError(reportErrorsOn, errorMessage);
context.trace.report(ITERATOR_MISSING.on(loopRangeExpression)); 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) { private FunctionDescriptor checkHasNextFunctionSupport(@NotNull JetExpression loopRange, @NotNull JetType iteratorType, ExpressionTypingContext context) {
OverloadResolutionResults<FunctionDescriptor> hasNextResolutionResults = context.resolveExactSignature(new TransientReceiver(iteratorType), "hasNext", Collections.<JetType>emptyList()); OverloadResolutionResults<FunctionDescriptor> hasNextResolutionResults = context.resolveExactSignature(new TransientReceiver(iteratorType), "hasNext", Collections.<JetType>emptyList());
if (hasNextResolutionResults.isAmbiguity()) { 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)); context.trace.report(HAS_NEXT_FUNCTION_AMBIGUITY.on(loopRange));
} else if (hasNextResolutionResults.isNothing()) { } else if (hasNextResolutionResults.isNothing()) {
return null; return null;
@@ -291,7 +285,6 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor {
assert hasNextResolutionResults.isSuccess(); assert hasNextResolutionResults.isSuccess();
JetType hasNextReturnType = hasNextResolutionResults.getResult().getResultingDescriptor().getReturnType(); JetType hasNextReturnType = hasNextResolutionResults.getResult().getResultingDescriptor().getReturnType();
if (!isBoolean(context.semanticServices, hasNextReturnType)) { 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)); context.trace.report(HAS_NEXT_FUNCTION_TYPE_MISMATCH.on(loopRange, hasNextReturnType));
} }
} }
@@ -308,11 +301,9 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor {
JetType hasNextReturnType = hasNextProperty.getOutType(); JetType hasNextReturnType = hasNextProperty.getOutType();
if (hasNextReturnType == null) { if (hasNextReturnType == null) {
// TODO : accessibility // 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)); context.trace.report(HAS_NEXT_MUST_BE_READABLE.on(loopRange));
} }
else if (!isBoolean(context.semanticServices, hasNextReturnType)) { 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)); 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) { public JetType visitReturnExpression(JetReturnExpression expression, ExpressionTypingContext context) {
context.labelResolver.recordLabel(expression, context); context.labelResolver.recordLabel(expression, context);
if (context.expectedReturnType == TypeUtils.FORBIDDEN) { if (context.expectedReturnType == TypeUtils.FORBIDDEN) {
// context.trace.getErrorHandler().genericError(expression.getNode(), "'return' is not allowed here");
context.trace.report(RETURN_NOT_ALLOWED.on(expression)); context.trace.report(RETURN_NOT_ALLOWED.on(expression));
return null; return null;
} }
JetExpression returnedExpression = expression.getReturnedExpression(); JetExpression returnedExpression = expression.getReturnedExpression();
JetType returnedType = JetStandardClasses.getUnitType(); JetType expectedType = context.expectedReturnType;
if (returnedExpression != null) { if (expression.getTargetLabel() == null) {
facade.getType(returnedExpression, context.replaceExpectedType(context.expectedReturnType).replaceScope(context.scope)); 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 { else {
if (context.expectedReturnType != TypeUtils.NO_EXPECTED_TYPE && !JetStandardClasses.isUnit(context.expectedReturnType)) { PsiElement element = context.trace.get(LABEL_TARGET, expression.getTargetLabel());
// context.trace.getErrorHandler().genericError(expression.getNode(), "This function must return a value of type " + context.expectedReturnType); if (element instanceof JetFunction && ((JetFunction) element).getReturnTypeRef() != null) {
context.trace.report(RETURN_TYPE_MISMATCH.on(expression, context.expectedReturnType)); 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); return DataFlowUtils.checkType(JetStandardClasses.getNothingType(), expression, context);
@@ -122,7 +122,9 @@ public class ExpressionTypingServices {
if (function instanceof JetFunctionLiteralExpression) { if (function instanceof JetFunctionLiteralExpression) {
JetFunctionLiteralExpression functionLiteralExpression = (JetFunctionLiteralExpression) function; 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 { else {
expressionTypingFacade.getType(bodyExpression, newContext); expressionTypingFacade.getType(bodyExpression, newContext);
@@ -5,9 +5,12 @@ fun unitEmpty() : Unit {}
fun unitEmptyReturn() : Unit {return} fun unitEmptyReturn() : Unit {return}
fun unitIntReturn() : Unit {return <!TYPE_MISMATCH!>1<!>} fun unitIntReturn() : Unit {return <!TYPE_MISMATCH!>1<!>}
fun unitUnitReturn() : Unit {return ()} fun unitUnitReturn() : Unit {return ()}
fun test1() : Any = {return} fun test1() : Any = {<!RETURN_TYPE_MISMATCH, RETURN_NOT_ALLOWED!>return<!>}
fun test2() : Any = @a {return@a 1} fun test2() : Any = @a {return@a 1}
fun test3() : Any { <!RETURN_TYPE_MISMATCH!>return<!> } fun test3() : Any { <!RETURN_TYPE_MISMATCH!>return<!> }
fun test4(): fun(): Unit = { <!RETURN_TYPE_MISMATCH, RETURN_NOT_ALLOWED!>return@test4<!> }
fun test5(): Any = @{ return@ }
fun test5(): Any = {<!RETURN_NOT_ALLOWED!>return 1<!>}
fun bbb() { fun bbb() {
return <!TYPE_MISMATCH!>1<!> return <!TYPE_MISMATCH!>1<!>
@@ -6,12 +6,12 @@ class A {
if (1 < 2) if (1 < 2)
return@inner return@inner
else else
return@outer <!RETURN_NOT_ALLOWED!>return@outer<!>
} }
if (1 < 2) if (1 < 2)
<!NOT_A_RETURN_LABEL!>return@A<!> <!RETURN_NOT_ALLOWED!>return@A<!>
else if (2 < 3) else if (2 < 3)
<!NOT_A_RETURN_LABEL!>return<!UNRESOLVED_REFERENCE!>@inner<!><!> <!RETURN_NOT_ALLOWED!>return<!UNRESOLVED_REFERENCE!>@inner<!><!>
return@outer return@outer
} }
} }
@@ -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_NOT_ALLOWED!>return "s"<!>
}
return "s"
}
fun t3() : String {
invoker(
@{
if (true) {
<!RETURN_NOT_ALLOWED!>return@t3 "1"<!>
}
else {
<!RETURN_NOT_ALLOWED!>return <!ERROR_COMPILE_TIME_VALUE!>2<!><!>
}
return@ 0
}
)
invoker(
@{ (): Int =>
return@ 1
}
)
invoker(
{
<!RETURN_NOT_ALLOWED!>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
}
@@ -5,7 +5,7 @@ fun unitEmpty() : Unit {}
fun unitEmptyReturn() : Unit {return} fun unitEmptyReturn() : Unit {return}
fun unitIntReturn() : Unit {return <error>1</error>} fun unitIntReturn() : Unit {return <error>1</error>}
fun unitUnitReturn() : Unit {return ()} fun unitUnitReturn() : Unit {return ()}
fun test1() : Any = {return} fun test1() : Any = { <error>return</error> }
fun test2() : Any = @a {return@a 1} fun test2() : Any = @a {return@a 1}
fun test3() : Any { <error>return</error> } fun test3() : Any { <error>return</error> }