Merge remote branch 'origin/master'
This commit is contained in:
@@ -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());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+16
-5
@@ -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
|
||||||
|
|||||||
+1
-1
@@ -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();
|
||||||
|
|||||||
+8
-4
@@ -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);
|
||||||
|
|||||||
+22
-18
@@ -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);
|
||||||
|
|||||||
+3
-1
@@ -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> }
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user