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 60b84cfa87b..35071baa1a8 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 @@ -313,86 +313,119 @@ public class CandidateResolver { @NotNull CallCandidateResolutionContext context ) { ResolvedCallImpl resolvedCall = context.candidateCall; - ConstraintSystem constraintSystem = context.candidateCall.getConstraintSystem(); for (Map.Entry entry : resolvedCall.getValueArguments().entrySet()) { ValueParameterDescriptor parameterDescriptor = entry.getKey(); ResolvedValueArgument resolvedArgument = entry.getValue(); for (ValueArgument argument : resolvedArgument.getArguments()) { - JetExpression expression = argument.getArgumentExpression(); - if (expression == null) continue; - - JetType effectiveExpectedType = getEffectiveExpectedType(parameterDescriptor, argument); - JetType expectedType = constraintSystem != null - ? constraintSystem.getCurrentSubstitutor().substitute(effectiveExpectedType, Variance.INVARIANT) - : effectiveExpectedType; - - JetVisitor selectorExpressionFinder = new JetVisitor() { - @Override - public JetExpression visitQualifiedExpression(JetQualifiedExpression expression, Void data) { - JetExpression selector = expression.getSelectorExpression(); - return selector != null ? selector.accept(this, null) : null; - } - - @Override - public JetExpression visitExpression(JetExpression expression, Void data) { - return expression; - } - }; - JetExpression selectorExpression = expression.accept(selectorExpressionFinder, null); - - CallCandidateResolutionContext storedContextForArgument = - context.resolutionResultsCache.getDeferredComputation(CallKey.create(Call.CallType.DEFAULT, selectorExpression)); - //todo assert storedContextForArgument != null - if (storedContextForArgument == null) { - PsiElement parent = expression.getParent(); - if (parent instanceof JetWhenExpression && expression == ((JetWhenExpression) parent).getSubjectExpression() - || (expression instanceof JetFunctionLiteralExpression)) { - continue; - } - JetType type = context.trace.get(BindingContext.EXPRESSION_TYPE, expression); - DataFlowInfo dataFlowInfoForValueArgument = resolvedCall.getDataFlowInfoForValueArgument(argument); - ResolutionContext newContext = context.replaceExpectedType(expectedType); - if (dataFlowInfoForValueArgument != null) { - newContext = newContext.replaceDataFlowInfo(dataFlowInfoForValueArgument); - } - if (type != null && !type.getConstructor().isDenotable()) { - if (type.getConstructor() instanceof NumberValueTypeConstructor) { - NumberValueTypeConstructor constructor = (NumberValueTypeConstructor) type.getConstructor(); - type = ConstantUtils.updateConstantValueType(constructor, expectedType, expression, context); - } - } - if (expression instanceof JetConstantExpression && !KotlinBuiltIns.getInstance().isUnit(expectedType)) { - CompileTimeConstant value = - new CompileTimeConstantResolver().getCompileTimeConstant((JetConstantExpression) expression, expectedType); - if (value instanceof ErrorValue) { - context.trace.report(ERROR_COMPILE_TIME_VALUE.on(expression, ((ErrorValue) value).getMessage())); - } - } - else { - DataFlowUtils.checkType(type, expression, newContext); - } - continue; - } - - CallCandidateResolutionContext contextForArgument = - storedContextForArgument.replaceResolveMode(ResolveMode.TOP_LEVEL_CALL).replaceBindingTrace(context.trace).replaceExpectedType(expectedType); - JetType type; - if (contextForArgument.candidateCall.hasIncompleteTypeParameters()) { - type = completeTypeInferenceDependentOnExpectedTypeForCall(contextForArgument, true); - } - else { - type = completeNestedCallsInference(contextForArgument); - checkValueArgumentTypes(contextForArgument); - } - - DataFlowUtils.checkType(type, expression, contextForArgument); + completeInferenceForArgument(argument, parameterDescriptor, context); } } recordReferenceForInvokeFunction(context); return resolvedCall.getResultingDescriptor().getReturnType(); } + private void completeInferenceForArgument( + @NotNull ValueArgument argument, + @NotNull ValueParameterDescriptor parameterDescriptor, + @NotNull CallCandidateResolutionContext context + ) { + ConstraintSystem constraintSystem = context.candidateCall.getConstraintSystem(); + + JetExpression expression = argument.getArgumentExpression(); + if (expression == null) return; + + JetType effectiveExpectedType = getEffectiveExpectedType(parameterDescriptor, argument); + JetType expectedType = constraintSystem != null + ? constraintSystem.getCurrentSubstitutor().substitute(effectiveExpectedType, Variance.INVARIANT) + : effectiveExpectedType; + context = context.replaceExpectedType(expectedType); + + JetExpression keyExpression = getDeferredComputationKeyExpression(expression); + CallCandidateResolutionContext storedContextForArgument = + context.resolutionResultsCache.getDeferredComputation(CallKey.create(Call.CallType.DEFAULT, keyExpression)); + + if (storedContextForArgument == null) { + PsiElement parent = expression.getParent(); + if (parent instanceof JetWhenExpression && expression == ((JetWhenExpression) parent).getSubjectExpression() + || (expression instanceof JetFunctionLiteralExpression)) { + return; + } + JetType type = updateResultTypeIfNotDenotable(context, expression); + checkResultType(type, argument, context); + return; + } + + CallCandidateResolutionContext contextForArgument = storedContextForArgument + .replaceResolveMode(ResolveMode.TOP_LEVEL_CALL).replaceBindingTrace(context.trace).replaceExpectedType(expectedType); + JetType type; + if (contextForArgument.candidateCall.hasIncompleteTypeParameters()) { + type = completeTypeInferenceDependentOnExpectedTypeForCall(contextForArgument, true); + } + else { + type = completeNestedCallsInference(contextForArgument); + checkValueArgumentTypes(contextForArgument); + } + + DataFlowUtils.checkType(type, expression, contextForArgument); + } + + @NotNull + private JetExpression getDeferredComputationKeyExpression(@NotNull JetExpression expression) { + JetVisitor selectorExpressionFinder = new JetVisitor() { + @Override + public JetExpression visitQualifiedExpression(JetQualifiedExpression expression, Void data) { + JetExpression selector = expression.getSelectorExpression(); + return selector != null ? selector.accept(this, null) : null; + } + + @Override + public JetExpression visitExpression(JetExpression expression, Void data) { + return expression; + } + }; + return expression.accept(selectorExpressionFinder, null); + } + + @Nullable + private JetType updateResultTypeIfNotDenotable( + @NotNull CallCandidateResolutionContext context, + @NotNull JetExpression expression + ) { + JetType type = context.trace.get(BindingContext.EXPRESSION_TYPE, expression); + if (type != null && !type.getConstructor().isDenotable()) { + if (type.getConstructor() instanceof NumberValueTypeConstructor) { + NumberValueTypeConstructor constructor = (NumberValueTypeConstructor) type.getConstructor(); + type = ConstantUtils.updateConstantValueType(constructor, context.expectedType, expression, context); + } + } + return type; + } + + private void checkResultType( + @Nullable JetType type, + @NotNull ValueArgument argument, + @NotNull CallCandidateResolutionContext context + ) { + JetExpression expression = argument.getArgumentExpression(); + if (expression == null) return; + + if (expression instanceof JetConstantExpression && !KotlinBuiltIns.getInstance().isUnit(context.expectedType)) { + CompileTimeConstant value = + new CompileTimeConstantResolver().getCompileTimeConstant((JetConstantExpression) expression, context.expectedType); + if (value instanceof ErrorValue) { + context.trace.report(ERROR_COMPILE_TIME_VALUE.on(expression, ((ErrorValue) value).getMessage())); + } + return; + } + DataFlowInfo dataFlowInfoForValueArgument = context.candidateCall.getDataFlowInfoForValueArgument(argument); + ResolutionContext newContext = context.replaceExpectedType(context.expectedType); + if (dataFlowInfoForValueArgument != null) { + newContext = newContext.replaceDataFlowInfo(dataFlowInfoForValueArgument); + } + DataFlowUtils.checkType(type, expression, newContext); + } + private static void recordReferenceForInvokeFunction(CallCandidateResolutionContext context) { PsiElement callElement = context.call.getCallElement(); if (!(callElement instanceof JetCallExpression)) return;