diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallExpressionResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallExpressionResolver.java index 89654ce164e..ac358fd9a2d 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallExpressionResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallExpressionResolver.java @@ -375,8 +375,10 @@ public class CallExpressionResolver { // TODO : functions as values JetExpression selectorExpression = expression.getSelectorExpression(); JetExpression receiverExpression = expression.getReceiverExpression(); - JetTypeInfo receiverTypeInfo = expressionTypingServices.getTypeInfoWithNamespaces( - receiverExpression, context.scope, NO_EXPECTED_TYPE, context.dataFlowInfo, context.trace); + ResolutionContext contextForReceiver = context + .replaceExpectedType(NO_EXPECTED_TYPE).replaceExpressionPosition(ExpressionPosition.LHS_OF_DOT) + .replaceContextDependency(ContextDependency.INDEPENDENT); + JetTypeInfo receiverTypeInfo = expressionTypingServices.getTypeInfo(receiverExpression, contextForReceiver); JetType receiverType = receiverTypeInfo.getType(); if (selectorExpression == null) return JetTypeInfo.create(null, context.dataFlowInfo); if (receiverType == null) receiverType = ErrorUtils.createErrorType("Type for " + expression.getText()); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CandidateResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CandidateResolver.java index 0ad8f62c61b..cd1b630c9d5 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CandidateResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CandidateResolver.java @@ -363,7 +363,8 @@ public class CandidateResolver { } CallCandidateResolutionContext contextForArgument = storedContextForArgument - .replaceContextDependency(ContextDependency.INDEPENDENT).replaceBindingTrace(context.trace).replaceExpectedType(expectedType); + .replaceContextDependency(ContextDependency.INDEPENDENT).replaceBindingTrace(context.trace).replaceExpectedType( + expectedType); JetType type; if (contextForArgument.candidateCall.hasIncompleteTypeParameters()) { type = completeTypeInferenceDependentOnExpectedTypeForCall(contextForArgument, true); @@ -402,16 +403,29 @@ public class CandidateResolver { return baseExpression != null ? baseExpression : expression; } + @Override + public JetExpression visitBlockExpression(JetBlockExpression expression, Void data) { + JetElement lastStatement = JetPsiUtil.getLastStatementInABlock(expression); + if (lastStatement != null) { + return lastStatement.accept(this, data); + } + return expression; + } + + @SuppressWarnings("SuspiciousMethodCalls") @Override public JetExpression visitBinaryExpression(JetBinaryExpression expression, Void data) { IElementType operationType = expression.getOperationReference().getReferencedNameElementType(); - //noinspection SuspiciousMethodCalls if (OperatorConventions.COMPARISON_OPERATIONS.contains(operationType)) { //Result type of comparison doesn't depend on expected type: //it's 'Boolean', but 'compareTo' should return 'Int'. //So we shouldn't check result type of such a call('Int') at completion phase. return null; } + if (OperatorConventions.ASSIGNMENT_OPERATIONS.containsKey(operationType)) { + //the same, result type is always 'Unit' + return null; + } return super.visitBinaryExpression(expression, data); } }; diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java index dffdb857f30..13b3bccb0ea 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java @@ -65,6 +65,8 @@ import static org.jetbrains.jet.lang.descriptors.ReceiverParameterDescriptor.NO_ import static org.jetbrains.jet.lang.diagnostics.Errors.*; import static org.jetbrains.jet.lang.resolve.BindingContext.*; import static org.jetbrains.jet.lang.resolve.DescriptorUtils.getStaticNestedClassesScope; +import static org.jetbrains.jet.lang.resolve.calls.context.ContextDependency.DEPENDENT; +import static org.jetbrains.jet.lang.resolve.calls.context.ContextDependency.INDEPENDENT; import static org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue.NO_RECEIVER; import static org.jetbrains.jet.lang.types.TypeUtils.NO_EXPECTED_TYPE; import static org.jetbrains.jet.lang.types.TypeUtils.UNKNOWN_EXPECTED_TYPE; @@ -152,7 +154,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { @Override public JetTypeInfo visitBinaryWithTypeRHSExpression(JetBinaryExpressionWithTypeRHS expression, ExpressionTypingContext context) { ExpressionTypingContext contextWithNoExpectedType = - context.replaceExpectedType(NO_EXPECTED_TYPE).replaceContextDependency(ContextDependency.INDEPENDENT); + context.replaceExpectedType(NO_EXPECTED_TYPE).replaceContextDependency(INDEPENDENT); JetExpression left = expression.getLeft(); JetTypeReference right = expression.getRight(); if (right == null) { @@ -658,11 +660,10 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { } ReceiverValue receiver = new TransientReceiver(lhsType); - TemporaryTraceAndCache temporaryWithReceiver = TemporaryTraceAndCache.create(context, - "trace to resolve callable reference with receiver", reference); - FunctionDescriptor descriptor = - resolveCallableNotCheckingArguments( - reference, receiver, context.replaceTraceAndCache(temporaryWithReceiver), result); + TemporaryTraceAndCache temporaryWithReceiver = TemporaryTraceAndCache.create( + context, "trace to resolve callable reference with receiver", reference); + FunctionDescriptor descriptor = resolveCallableNotCheckingArguments( + reference, receiver, context.replaceTraceAndCache(temporaryWithReceiver), result); if (result[0]) { temporaryWithReceiver.commit(); return descriptor; @@ -743,7 +744,8 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { } // Type check the base expression - JetTypeInfo typeInfo = facade.getTypeInfo(baseExpression, context.replaceExpectedType(NO_EXPECTED_TYPE)); + JetTypeInfo typeInfo = facade.getTypeInfo( + baseExpression, context.replaceExpectedType(NO_EXPECTED_TYPE).replaceContextDependency(INDEPENDENT)); JetType type = typeInfo.getType(); if (type == null) { return typeInfo; @@ -882,8 +884,8 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { } @Override - public JetTypeInfo visitBinaryExpression(JetBinaryExpression expression, ExpressionTypingContext contextWithExpectedType) { - ExpressionTypingContext context = contextWithExpectedType.replaceExpectedType(NO_EXPECTED_TYPE); + public JetTypeInfo visitBinaryExpression(JetBinaryExpression expression, ExpressionTypingContext context) { + ExpressionTypingContext independentContext = context.replaceContextDependency(INDEPENDENT).replaceExpectedType(NO_EXPECTED_TYPE); JetSimpleNameExpression operationSign = expression.getOperationReference(); JetExpression left = expression.getLeft(); @@ -906,15 +908,14 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { dataFlowInfo = typeInfo.getDataFlowInfo(); } else if (operationType == JetTokens.EQ) { - result = visitAssignment(expression, contextWithExpectedType); + result = visitAssignment(expression, context); } else if (OperatorConventions.ASSIGNMENT_OPERATIONS.containsKey(operationType)) { - result = visitAssignmentOperation(expression, contextWithExpectedType); + result = visitAssignmentOperation(expression, context); } else if (OperatorConventions.COMPARISON_OPERATIONS.contains(operationType)) { //we don't complete 'compareTo' call, because we change its result type from 'Int' to 'Boolean' - JetTypeInfo typeInfo = getTypeInfoForBinaryCall( - context.scope, OperatorConventions.COMPARE_TO, context.replaceContextDependency(ContextDependency.INDEPENDENT), expression); + JetTypeInfo typeInfo = getTypeInfoForBinaryCall(context.scope, OperatorConventions.COMPARE_TO, independentContext, expression); dataFlowInfo = typeInfo.getDataFlowInfo(); JetType compareToReturnType = typeInfo.getType(); if (compareToReturnType != null && !ErrorUtils.isErrorType(compareToReturnType)) { @@ -933,12 +934,12 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { JetType booleanType = KotlinBuiltIns.getInstance().getBooleanType(); if (OperatorConventions.EQUALS_OPERATIONS.contains(operationType)) { if (right != null && left != null) { - ExpressionReceiver receiver = ExpressionTypingUtils.safeGetExpressionReceiver(facade, left, context); + ExpressionReceiver receiver = ExpressionTypingUtils.safeGetExpressionReceiver(facade, left, independentContext); - JetTypeInfo leftTypeInfo = getTypeInfoOrNullType(left, context, facade); + JetTypeInfo leftTypeInfo = getTypeInfoOrNullType(left, independentContext, facade); dataFlowInfo = leftTypeInfo.getDataFlowInfo(); - ExpressionTypingContext contextWithDataFlow = context.replaceDataFlowInfo(dataFlowInfo); + ExpressionTypingContext contextWithDataFlow = independentContext.replaceDataFlowInfo(dataFlowInfo); OverloadResolutionResults resolutionResults = resolveFakeCall( contextWithDataFlow, receiver, OperatorConventions.EQUALS, KotlinBuiltIns.getInstance().getNullableAnyType()); @@ -950,7 +951,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { context.trace.record(REFERENCE_TARGET, operationSign, equals); context.trace.record(RESOLVED_CALL, operationSign, resolutionResults.getResultingCall()); if (ensureBooleanResult(operationSign, OperatorConventions.EQUALS, equals.getReturnType(), context)) { - ensureNonemptyIntersectionOfOperandTypes(expression, context); + ensureNonemptyIntersectionOfOperandTypes(expression, independentContext); } } else { @@ -965,7 +966,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { result = booleanType; } else if (operationType == JetTokens.EQEQEQ || operationType == JetTokens.EXCLEQEQEQ) { - ensureNonemptyIntersectionOfOperandTypes(expression, context); + ensureNonemptyIntersectionOfOperandTypes(expression, independentContext); // TODO : Check comparison pointlessness result = booleanType; @@ -974,12 +975,12 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { if (right == null) { return JetTypeInfo.create(null, dataFlowInfo); } - JetTypeInfo typeInfo = checkInExpression(expression, expression.getOperationReference(), left, right, context); + JetTypeInfo typeInfo = checkInExpression(expression, expression.getOperationReference(), left, right, independentContext); dataFlowInfo = typeInfo.getDataFlowInfo(); result = typeInfo.getType(); } else if (OperatorConventions.BOOLEAN_OPERATIONS.containsKey(operationType)) { - JetTypeInfo leftTypeInfo = getTypeInfoOrNullType(left, context, facade); + JetTypeInfo leftTypeInfo = getTypeInfoOrNullType(left, independentContext, facade); JetType leftType = leftTypeInfo.getType(); dataFlowInfo = leftTypeInfo.getDataFlowInfo(); @@ -991,9 +992,8 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { WritableScopeImpl rightScope = operationType == JetTokens.ANDAND ? leftScope : newWritableScopeImpl(context, "Right scope of && or ||"); - JetType rightType = right == null - ? null - : facade.getTypeInfo(right, context.replaceDataFlowInfo(flowInfoLeft).replaceScope(rightScope)).getType(); + ExpressionTypingContext contextForRightExpr = independentContext.replaceDataFlowInfo(flowInfoLeft).replaceScope(rightScope); + JetType rightType = right != null ? facade.getTypeInfo(right, contextForRightExpr).getType() : null; if (left != null && leftType != null && !isBoolean(leftType)) { context.trace.report(TYPE_MISMATCH.on(left, booleanType, leftType)); } @@ -1003,13 +1003,13 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { result = booleanType; } else if (operationType == JetTokens.ELVIS) { - return visitElvisExpression(expression, contextWithExpectedType); + return visitElvisExpression(expression, context); } else { context.trace.report(UNSUPPORTED.on(operationSign, "Unknown operation")); } } - return DataFlowUtils.checkType(result, expression, contextWithExpectedType, dataFlowInfo); + return DataFlowUtils.checkType(result, expression, context, dataFlowInfo); } @NotNull @@ -1134,7 +1134,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { } private JetType assignmentIsNotAnExpressionError(JetBinaryExpression expression, ExpressionTypingContext context) { - facade.checkStatementType(expression, context.replaceExpectedType(NO_EXPECTED_TYPE)); + facade.checkStatementType(expression, context.replaceExpectedType(NO_EXPECTED_TYPE).replaceContextDependency(INDEPENDENT)); context.trace.report(ASSIGNMENT_IN_EXPRESSION_CONTEXT.on(expression)); return null; } @@ -1156,7 +1156,9 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { JetExpression left = binaryExpression.getLeft(); DataFlowInfo dataFlowInfo = context.dataFlowInfo; if (left != null) { - dataFlowInfo = facade.getTypeInfo(left, context).getDataFlowInfo(); + //left here is a receiver, so it doesn't depend on context + dataFlowInfo = facade.getTypeInfo( + left, context.replaceContextDependency(INDEPENDENT).replaceExpectedType(NO_EXPECTED_TYPE)).getDataFlowInfo(); } ExpressionTypingContext contextWithDataFlow = context.replaceDataFlowInfo(dataFlowInfo); @@ -1212,7 +1214,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { @Override public JetTypeInfo visitStringTemplateExpression(JetStringTemplateExpression expression, ExpressionTypingContext contextWithExpectedType) { - final ExpressionTypingContext context = contextWithExpectedType.replaceExpectedType(NO_EXPECTED_TYPE); + final ExpressionTypingContext context = contextWithExpectedType.replaceExpectedType(NO_EXPECTED_TYPE).replaceContextDependency(INDEPENDENT); final StringBuilder builder = new StringBuilder(); final CompileTimeConstant[] value = new CompileTimeConstant[1]; final DataFlowInfo[] dataFlowInfo = new DataFlowInfo[1]; @@ -1291,7 +1293,8 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { JetExpression arrayExpression = arrayAccessExpression.getArrayExpression(); if (arrayExpression == null) return JetTypeInfo.create(null, oldContext.dataFlowInfo); - JetTypeInfo arrayTypeInfo = facade.getTypeInfo(arrayExpression, oldContext.replaceExpectedType(NO_EXPECTED_TYPE)); + JetTypeInfo arrayTypeInfo = facade.getTypeInfo(arrayExpression, oldContext.replaceExpectedType(NO_EXPECTED_TYPE) + .replaceContextDependency(INDEPENDENT)); JetType arrayType = arrayTypeInfo.getType(); if (arrayType == null) return arrayTypeInfo; 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 f19845db898..2a150a3c62b 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 @@ -43,6 +43,7 @@ import java.util.List; import static org.jetbrains.jet.lang.diagnostics.Errors.*; import static org.jetbrains.jet.lang.resolve.BindingContext.*; +import static org.jetbrains.jet.lang.resolve.calls.context.ContextDependency.*; import static org.jetbrains.jet.lang.types.TypeUtils.NO_EXPECTED_TYPE; import static org.jetbrains.jet.lang.types.TypeUtils.noExpectedType; import static org.jetbrains.jet.lang.types.expressions.CoercionStrategy.COERCION_TO_UNIT; @@ -84,7 +85,7 @@ public class ClosureExpressionsTypingVisitor extends ExpressionTypingVisitor { }; ObservableBindingTrace traceAdapter = new ObservableBindingTrace(temporaryTrace); traceAdapter.addHandler(CLASS, handler); - TopDownAnalyzer.processClassOrObject(context.replaceBindingTrace(traceAdapter), + TopDownAnalyzer.processClassOrObject(context.replaceBindingTrace(traceAdapter).replaceContextDependency(INDEPENDENT), context.scope.getContainingDeclaration(), expression.getObjectDeclaration()); 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 5183ed44524..508762c9868 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 @@ -52,8 +52,10 @@ import java.util.*; import static org.jetbrains.jet.lang.diagnostics.Errors.*; import static org.jetbrains.jet.lang.resolve.BindingContext.*; -import static org.jetbrains.jet.lang.types.TypeUtils.UNKNOWN_EXPECTED_TYPE; +import static org.jetbrains.jet.lang.resolve.calls.context.ContextDependency.INDEPENDENT; +import static org.jetbrains.jet.lang.types.TypeUtils.NO_EXPECTED_TYPE; import static org.jetbrains.jet.lang.types.TypeUtils.noExpectedType; +import static org.jetbrains.jet.lang.types.TypeUtils.UNKNOWN_EXPECTED_TYPE; import static org.jetbrains.jet.lang.types.expressions.ControlStructureTypingUtils.*; import static org.jetbrains.jet.lang.types.expressions.ExpressionTypingUtils.*; @@ -69,7 +71,7 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor { private DataFlowInfo checkCondition(@NotNull JetScope scope, @Nullable JetExpression condition, ExpressionTypingContext context) { if (condition != null) { JetTypeInfo typeInfo = facade.getTypeInfo(condition, context.replaceScope(scope) - .replaceExpectedType(KotlinBuiltIns.getInstance().getBooleanType())); + .replaceExpectedType(KotlinBuiltIns.getInstance().getBooleanType()).replaceContextDependency(INDEPENDENT)); JetType conditionType = typeInfo.getType(); if (conditionType != null && !isBoolean(conditionType)) { @@ -90,7 +92,7 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor { } public JetTypeInfo visitIfExpression(JetIfExpression ifExpression, ExpressionTypingContext contextWithExpectedType, boolean isStatement) { - ExpressionTypingContext context = contextWithExpectedType.replaceExpectedType(TypeUtils.NO_EXPECTED_TYPE); + ExpressionTypingContext context = contextWithExpectedType.replaceExpectedType(NO_EXPECTED_TYPE); JetExpression condition = ifExpression.getCondition(); DataFlowInfo conditionDataFlowInfo = checkCondition(context.scope, condition, context); @@ -171,8 +173,10 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor { @NotNull JetIfExpression ifExpression, boolean isStatement ) { - JetTypeInfo typeInfo = context.expressionTypingServices.getBlockReturnedTypeWithWritableScope(presentScope, Collections - .singletonList(presentBranch), CoercionStrategy.NO_COERCION, context.replaceDataFlowInfo(presentInfo), context.trace); + ExpressionTypingContext newContext = context.replaceDataFlowInfo(presentInfo).replaceExpectedType(NO_EXPECTED_TYPE) + .replaceContextDependency(INDEPENDENT); + JetTypeInfo typeInfo = context.expressionTypingServices.getBlockReturnedTypeWithWritableScope( + presentScope, Collections.singletonList(presentBranch), CoercionStrategy.NO_COERCION, newContext, context.trace); JetType type = typeInfo.getType(); DataFlowInfo dataFlowInfo; if (type != null && KotlinBuiltIns.getInstance().isNothing(type)) { @@ -192,7 +196,8 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor { public JetTypeInfo visitWhileExpression(JetWhileExpression expression, ExpressionTypingContext contextWithExpectedType, boolean isStatement) { if (!isStatement) return DataFlowUtils.illegalStatementType(expression, contextWithExpectedType, facade); - ExpressionTypingContext context = contextWithExpectedType.replaceExpectedType(TypeUtils.NO_EXPECTED_TYPE); + ExpressionTypingContext context = contextWithExpectedType.replaceExpectedType(NO_EXPECTED_TYPE).replaceContextDependency( + INDEPENDENT); JetExpression condition = expression.getCondition(); DataFlowInfo dataFlowInfo = checkCondition(context.scope, condition, context); @@ -200,7 +205,9 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor { if (body != null) { WritableScopeImpl scopeToExtend = newWritableScopeImpl(context, "Scope extended in while's condition"); DataFlowInfo conditionInfo = DataFlowUtils.extractDataFlowInfoFromCondition(condition, true, context).and(dataFlowInfo); - context.expressionTypingServices.getBlockReturnedTypeWithWritableScope(scopeToExtend, Collections.singletonList(body), CoercionStrategy.NO_COERCION, context.replaceDataFlowInfo(conditionInfo), context.trace); + context.expressionTypingServices.getBlockReturnedTypeWithWritableScope( + scopeToExtend, Collections.singletonList(body), + CoercionStrategy.NO_COERCION, context.replaceDataFlowInfo(conditionInfo), context.trace); } if (!containsJumpOutOfLoop(expression, context)) { @@ -255,7 +262,8 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor { public JetTypeInfo visitDoWhileExpression(JetDoWhileExpression expression, ExpressionTypingContext contextWithExpectedType, boolean isStatement) { if (!isStatement) return DataFlowUtils.illegalStatementType(expression, contextWithExpectedType, facade); - ExpressionTypingContext context = contextWithExpectedType.replaceExpectedType(TypeUtils.NO_EXPECTED_TYPE); + ExpressionTypingContext context = + contextWithExpectedType.replaceExpectedType(NO_EXPECTED_TYPE).replaceContextDependency(INDEPENDENT); JetExpression body = expression.getBody(); JetScope conditionScope = context.scope; if (body instanceof JetFunctionLiteralExpression) { @@ -304,7 +312,8 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor { public JetTypeInfo visitForExpression(JetForExpression expression, ExpressionTypingContext contextWithExpectedType, boolean isStatement) { if (!isStatement) return DataFlowUtils.illegalStatementType(expression, contextWithExpectedType, facade); - ExpressionTypingContext context = contextWithExpectedType.replaceExpectedType(TypeUtils.NO_EXPECTED_TYPE); + ExpressionTypingContext context = + contextWithExpectedType.replaceExpectedType(NO_EXPECTED_TYPE).replaceContextDependency(INDEPENDENT); JetExpression loopRange = expression.getLoopRange(); JetType expectedParameterType = null; DataFlowInfo dataFlowInfo = context.dataFlowInfo; @@ -453,7 +462,8 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor { } @Override - public JetTypeInfo visitTryExpression(JetTryExpression expression, ExpressionTypingContext context) { + public JetTypeInfo visitTryExpression(JetTryExpression expression, ExpressionTypingContext typingContext) { + ExpressionTypingContext context = typingContext.replaceContextDependency(INDEPENDENT); JetExpression tryBlock = expression.getTryBlock(); List catchClauses = expression.getCatchClauses(); JetFinallySection finallyBlock = expression.getFinallyBlock(); @@ -483,7 +493,7 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor { DataFlowInfo dataFlowInfo = context.dataFlowInfo; if (finallyBlock != null) { dataFlowInfo = facade.getTypeInfo(finallyBlock.getFinalExpression(), - context.replaceExpectedType(TypeUtils.NO_EXPECTED_TYPE)).getDataFlowInfo(); + context.replaceExpectedType(NO_EXPECTED_TYPE)).getDataFlowInfo(); } JetType type = facade.getTypeInfo(tryBlock, context).getType(); @@ -503,7 +513,8 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor { JetExpression thrownExpression = expression.getThrownExpression(); if (thrownExpression != null) { JetType throwableType = KotlinBuiltIns.getInstance().getThrowable().getDefaultType(); - facade.getTypeInfo(thrownExpression, context.replaceExpectedType(throwableType).replaceScope(context.scope)); + facade.getTypeInfo(thrownExpression, context + .replaceExpectedType(throwableType).replaceScope(context.scope).replaceContextDependency(INDEPENDENT)); } return DataFlowUtils.checkType(KotlinBuiltIns.getInstance().getNothingType(), expression, context, context.dataFlowInfo); } @@ -514,7 +525,7 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor { JetExpression returnedExpression = expression.getReturnedExpression(); - JetType expectedType = TypeUtils.NO_EXPECTED_TYPE; + JetType expectedType = NO_EXPECTED_TYPE; JetType resultType = KotlinBuiltIns.getInstance().getNothingType(); JetDeclaration parentDeclaration = PsiTreeUtil.getParentOfType(expression, JetDeclaration.class); @@ -558,7 +569,7 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor { context.trace.report(RETURN_NOT_ALLOWED.on(expression)); resultType = ErrorUtils.createErrorType(RETURN_NOT_ALLOWED_MESSAGE); } - else if (expectedType == TypeUtils.NO_EXPECTED_TYPE) { + else if (expectedType == NO_EXPECTED_TYPE) { // 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)); @@ -569,7 +580,8 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor { } } if (returnedExpression != null) { - facade.getTypeInfo(returnedExpression, context.replaceExpectedType(expectedType).replaceScope(context.scope)); + facade.getTypeInfo(returnedExpression, context.replaceExpectedType(expectedType).replaceScope(context.scope) + .replaceContextDependency(INDEPENDENT)); } else { if (expectedType != null && !noExpectedType(expectedType) && !KotlinBuiltIns.getInstance().isUnit(expectedType)) { diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/DataFlowUtils.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/DataFlowUtils.java index 4f9d887a8fb..2c0f07f8d28 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/DataFlowUtils.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/DataFlowUtils.java @@ -23,6 +23,7 @@ import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.BindingTrace; +import org.jetbrains.jet.lang.resolve.calls.context.ContextDependency; import org.jetbrains.jet.lang.resolve.calls.context.ResolutionContext; import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo; import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowValue; @@ -202,7 +203,8 @@ public class DataFlowUtils { @NotNull public static JetTypeInfo illegalStatementType(@NotNull JetExpression expression, @NotNull ExpressionTypingContext context, @NotNull ExpressionTypingInternals facade) { - facade.checkStatementType(expression, context.replaceExpectedType(TypeUtils.NO_EXPECTED_TYPE)); + facade.checkStatementType( + expression, context.replaceExpectedType(TypeUtils.NO_EXPECTED_TYPE).replaceContextDependency(ContextDependency.INDEPENDENT)); context.trace.report(EXPRESSION_EXPECTED.on(expression, expression)); return JetTypeInfo.create(null, context.dataFlowInfo); } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingVisitorForStatements.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingVisitorForStatements.java index 4478cf35ecb..9095103ea46 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingVisitorForStatements.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/ExpressionTypingVisitorForStatements.java @@ -29,6 +29,7 @@ import org.jetbrains.jet.lang.resolve.ModifiersChecker; import org.jetbrains.jet.lang.resolve.TemporaryBindingTrace; import org.jetbrains.jet.lang.resolve.TopDownAnalyzer; import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo; +import org.jetbrains.jet.lang.resolve.calls.context.ContextDependency; import org.jetbrains.jet.lang.resolve.calls.context.TemporaryTraceAndCache; import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall; import org.jetbrains.jet.lang.resolve.calls.results.OverloadResolutionResults; @@ -48,6 +49,8 @@ import java.util.Collection; import static org.jetbrains.jet.lang.diagnostics.Errors.*; import static org.jetbrains.jet.lang.resolve.BindingContext.AMBIGUOUS_REFERENCE_TARGET; import static org.jetbrains.jet.lang.resolve.BindingContext.VARIABLE_REASSIGNMENT; +import static org.jetbrains.jet.lang.resolve.calls.context.ContextDependency.*; +import static org.jetbrains.jet.lang.types.TypeUtils.NO_EXPECTED_TYPE; import static org.jetbrains.jet.lang.types.TypeUtils.noExpectedType; @SuppressWarnings("SuspiciousMethodCalls") @@ -86,7 +89,8 @@ public class ExpressionTypingVisitorForStatements extends ExpressionTypingVisito @Override public JetTypeInfo visitObjectDeclaration(JetObjectDeclaration declaration, ExpressionTypingContext context) { - TopDownAnalyzer.processClassOrObject(context.replaceScope(scope), scope.getContainingDeclaration(), declaration); + TopDownAnalyzer.processClassOrObject( + context.replaceScope(scope).replaceContextDependency(INDEPENDENT), scope.getContainingDeclaration(), declaration); ClassDescriptor classDescriptor = context.trace.getBindingContext().get(BindingContext.CLASS, declaration); if (classDescriptor != null) { VariableDescriptor variableDescriptor = context.expressionTypingServices.getDescriptorResolver() @@ -97,7 +101,8 @@ public class ExpressionTypingVisitorForStatements extends ExpressionTypingVisito } @Override - public JetTypeInfo visitProperty(JetProperty property, ExpressionTypingContext context) { + public JetTypeInfo visitProperty(JetProperty property, ExpressionTypingContext typingContext) { + ExpressionTypingContext context = typingContext.replaceContextDependency(INDEPENDENT).replaceScope(scope); JetTypeReference receiverTypeRef = property.getReceiverTypeRef(); if (receiverTypeRef != null) { context.trace.report(LOCAL_EXTENSION_PROPERTY.on(receiverTypeRef)); @@ -115,7 +120,7 @@ public class ExpressionTypingVisitorForStatements extends ExpressionTypingVisito JetExpression delegateExpression = property.getDelegateExpression(); if (delegateExpression != null) { - context.expressionTypingServices.getType(scope, delegateExpression, TypeUtils.NO_EXPECTED_TYPE, context.dataFlowInfo, context.trace); + context.expressionTypingServices.getTypeInfo(delegateExpression, context); context.trace.report(LOCAL_VARIABLE_WITH_DELEGATE.on(property.getDelegate())); } @@ -125,10 +130,10 @@ public class ExpressionTypingVisitorForStatements extends ExpressionTypingVisito DataFlowInfo dataFlowInfo = context.dataFlowInfo; if (initializer != null) { JetType outType = propertyDescriptor.getType(); - JetTypeInfo typeInfo = facade.getTypeInfo(initializer, context.replaceExpectedType(outType).replaceScope(scope)); + JetTypeInfo typeInfo = facade.getTypeInfo(initializer, context.replaceExpectedType(outType)); dataFlowInfo = typeInfo.getDataFlowInfo(); } - + { VariableDescriptor olderVariable = scope.getLocalVariable(propertyDescriptor.getName()); ExpressionTypingUtils.checkVariableShadowing(context, propertyDescriptor, olderVariable); @@ -146,8 +151,8 @@ public class ExpressionTypingVisitorForStatements extends ExpressionTypingVisito context.trace.report(INITIALIZER_REQUIRED_FOR_MULTIDECLARATION.on(multiDeclaration)); return JetTypeInfo.create(null, context.dataFlowInfo); } - ExpressionReceiver expressionReceiver = - ExpressionTypingUtils.getExpressionReceiver(facade, initializer, context.replaceExpectedType(TypeUtils.NO_EXPECTED_TYPE)); + ExpressionReceiver expressionReceiver = ExpressionTypingUtils.getExpressionReceiver( + facade, initializer, context.replaceExpectedType(NO_EXPECTED_TYPE).replaceContextDependency(INDEPENDENT)); DataFlowInfo dataFlowInfo = facade.getTypeInfo(initializer, context).getDataFlowInfo(); if (expressionReceiver == null) { return JetTypeInfo.create(null, dataFlowInfo); @@ -171,7 +176,8 @@ public class ExpressionTypingVisitorForStatements extends ExpressionTypingVisito @Override public JetTypeInfo visitClass(JetClass klass, ExpressionTypingContext context) { - TopDownAnalyzer.processClassOrObject(context.replaceScope(scope), scope.getContainingDeclaration(), klass); + TopDownAnalyzer.processClassOrObject( + context.replaceScope(scope).replaceContextDependency(INDEPENDENT), scope.getContainingDeclaration(), klass); ClassDescriptor classDescriptor = context.trace.getBindingContext().get(BindingContext.CLASS, klass); if (classDescriptor != null) { scope.addClassifierDescriptor(classDescriptor); @@ -211,8 +217,8 @@ public class ExpressionTypingVisitorForStatements extends ExpressionTypingVisito //There is a temporary binding trace for an opportunity to resolve set method for array if needed (the initial trace should be used there) TemporaryTraceAndCache temporary = TemporaryTraceAndCache.create( contextWithExpectedType, "trace to resolve array set method for binary expression", expression); - ExpressionTypingContext context = contextWithExpectedType.replaceExpectedType(TypeUtils.NO_EXPECTED_TYPE) - .replaceTraceAndCache(temporary); + ExpressionTypingContext context = contextWithExpectedType.replaceExpectedType(NO_EXPECTED_TYPE) + .replaceTraceAndCache(temporary).replaceContextDependency(INDEPENDENT); JetSimpleNameExpression operationSign = expression.getOperationReference(); IElementType operationType = operationSign.getReferencedNameElementType(); @@ -291,7 +297,8 @@ public class ExpressionTypingVisitorForStatements extends ExpressionTypingVisito @NotNull protected JetTypeInfo visitAssignment(JetBinaryExpression expression, ExpressionTypingContext contextWithExpectedType) { - ExpressionTypingContext context = contextWithExpectedType.replaceExpectedType(TypeUtils.NO_EXPECTED_TYPE).replaceScope(scope); + ExpressionTypingContext context = + contextWithExpectedType.replaceExpectedType(NO_EXPECTED_TYPE).replaceScope(scope).replaceContextDependency(INDEPENDENT); JetExpression leftOperand = expression.getLeft(); JetExpression left = leftOperand == null ? null : context.expressionTypingServices.deparenthesize(leftOperand, context); JetExpression right = expression.getRight(); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/PatternMatchingTypingVisitor.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/PatternMatchingTypingVisitor.java index 073de6551ce..7a8f4a52c4e 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/PatternMatchingTypingVisitor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/PatternMatchingTypingVisitor.java @@ -35,6 +35,8 @@ import java.util.Collections; import java.util.Set; import static org.jetbrains.jet.lang.diagnostics.Errors.*; +import static org.jetbrains.jet.lang.resolve.calls.context.ContextDependency.*; +import static org.jetbrains.jet.lang.types.TypeUtils.*; import static org.jetbrains.jet.lang.types.expressions.ExpressionTypingUtils.newWritableScopeImpl; public class PatternMatchingTypingVisitor extends ExpressionTypingVisitor { @@ -44,7 +46,7 @@ public class PatternMatchingTypingVisitor extends ExpressionTypingVisitor { @Override public JetTypeInfo visitIsExpression(JetIsExpression expression, ExpressionTypingContext contextWithExpectedType) { - ExpressionTypingContext context = contextWithExpectedType.replaceExpectedType(TypeUtils.NO_EXPECTED_TYPE); + ExpressionTypingContext context = contextWithExpectedType.replaceExpectedType(NO_EXPECTED_TYPE).replaceContextDependency(INDEPENDENT); JetExpression leftHandSide = expression.getLeftHandSide(); JetTypeInfo typeInfo = facade.safeGetTypeInfo(leftHandSide, context.replaceScope(context.scope)); JetType knownType = typeInfo.getType(); @@ -64,7 +66,7 @@ public class PatternMatchingTypingVisitor extends ExpressionTypingVisitor { } public JetTypeInfo visitWhenExpression(JetWhenExpression expression, ExpressionTypingContext contextWithExpectedType, boolean isStatement) { - ExpressionTypingContext context = contextWithExpectedType.replaceExpectedType(TypeUtils.NO_EXPECTED_TYPE); + ExpressionTypingContext context = contextWithExpectedType.replaceExpectedType(NO_EXPECTED_TYPE).replaceContextDependency(INDEPENDENT); // TODO :change scope according to the bound value in the when header JetExpression subjectExpression = expression.getSubjectExpression(); @@ -304,7 +306,7 @@ public class PatternMatchingTypingVisitor extends ExpressionTypingVisitor { if (type == null) { return; } - if (TypeUtils.isIntersectionEmpty(type, subjectType)) { + if (isIntersectionEmpty(type, subjectType)) { context.trace.report(INCOMPATIBLE_TYPES.on(reportErrorOn, type, subjectType)); return; } diff --git a/compiler/testData/diagnostics/tests/inference/nestedCalls/binaryExpressions.kt b/compiler/testData/diagnostics/tests/inference/nestedCalls/binaryExpressions.kt new file mode 100644 index 00000000000..0fb771d5223 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/nestedCalls/binaryExpressions.kt @@ -0,0 +1,71 @@ +package h + +trait A {} + +fun newA(): A = throw Exception() + +trait Z + +fun id(t: T): T = t + +//binary expressions +//identifier +fun Z.foo(a: A): A = a + +fun test(z: Z) { + z foo newA() + val a: A = id(z foo newA()) + val b: A = id(z.foo(newA())) + use(a, b) +} + +//binary operation expression +fun Z.plus(a: A): A = a + +fun test1(z: Z) { + id(z + newA()) + val a: A = z + newA() + val b: A = z.plus(newA()) + val c: A = id(z + newA()) + val d: A = id(z.plus(newA())) + use(a, b, c, d) +} + +//comparison operation +fun Z.compareTo(a: A): Int { use(a); return 1 } + +fun test2(z: Z) { + val a: Boolean = id(z < newA()) + val b: Boolean = id(z < newA()) + use(a, b) +} + +//'equals' operation +fun Z.equals(any: Any): Int { use(any); return 1 } + +fun test3(z: Z) { + z == newA() + z == newA() + id(z == newA()) + id(z == newA()) + + id(z === newA()) + id(z === newA()) +} + +//'in' operation +fun test4(collection: Collection>) { + id(newA() in collection) + id(newA() in collection) +} + +//boolean operations +fun toBeOrNot(): Boolean = throw Exception() + +fun test5() { + if (toBeOrNot() && toBeOrNot()) {} + if (toBeOrNot() && toBeOrNot()) {} +} + +//use +fun use(vararg a: Any?) = a \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java index a31145c215f..dd077dee827 100644 --- a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java @@ -2831,6 +2831,11 @@ public class JetDiagnosticsTestGenerated extends AbstractDiagnosticsTestWithEage doTest("compiler/testData/diagnostics/tests/inference/nestedCalls/arrayAccess.kt"); } + @TestMetadata("binaryExpressions.kt") + public void testBinaryExpressions() throws Exception { + doTest("compiler/testData/diagnostics/tests/inference/nestedCalls/binaryExpressions.kt"); + } + @TestMetadata("checkTypesForQualifiedProperties.kt") public void testCheckTypesForQualifiedProperties() throws Exception { doTest("compiler/testData/diagnostics/tests/inference/nestedCalls/checkTypesForQualifiedProperties.kt");