diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java index 763c7fbb739..997e4b90afb 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java @@ -19,7 +19,6 @@ package org.jetbrains.jet.lang.resolve.calls; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.intellij.openapi.progress.ProgressIndicatorProvider; -import com.intellij.psi.PsiElement; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.*; @@ -44,7 +43,6 @@ import org.jetbrains.jet.lang.resolve.scopes.receivers.ExpressionReceiver; import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.lang.types.expressions.ExpressionTypingContext; import org.jetbrains.jet.lang.types.expressions.ExpressionTypingServices; -import org.jetbrains.jet.lang.types.expressions.ExpressionTypingUtils; import org.jetbrains.jet.lexer.JetTokens; import javax.inject.Inject; @@ -181,6 +179,19 @@ public class CallResolver { return doResolveCallOrGetCachedResults(context, tasks, callTransformer, tracing); } + @NotNull + private OverloadResolutionResults computeTasksFromCandidatesAndResolvedCall( + @NotNull BasicCallResolutionContext context, + @NotNull JetReferenceExpression referenceExpression, + @NotNull Collection> candidates, + @NotNull CallTransformer callTransformer + ) { + TracingStrategy tracing = TracingStrategyImpl.create(referenceExpression, context.call); + List> prioritizedTasks = + taskPrioritizer.computePrioritizedTasksFromCandidates(context, candidates, tracing); + return doResolveCallOrGetCachedResults(context, prioritizedTasks, callTransformer, tracing); + } + @NotNull public OverloadResolutionResults resolveBinaryCall( ExpressionTypingContext context, @@ -214,94 +225,88 @@ public class CallResolver { @NotNull public OverloadResolutionResults resolveFunctionCall(@NotNull BasicCallResolutionContext context) { - ProgressIndicatorProvider.checkCanceled(); - List> prioritizedTasks; - JetExpression calleeExpression = context.call.getCalleeExpression(); - JetReferenceExpression functionReference; if (calleeExpression instanceof JetSimpleNameExpression) { JetSimpleNameExpression expression = (JetSimpleNameExpression) calleeExpression; - Name name = expression.getReferencedNameAsName(); - return computeTasksAndResolveCall(context, name, expression, CallableDescriptorCollectors.FUNCTIONS_AND_VARIABLES, - CallTransformer.FUNCTION_CALL_TRANSFORMER); + return computeTasksAndResolveCall( + context, expression.getReferencedNameAsName(), expression, + CallableDescriptorCollectors.FUNCTIONS_AND_VARIABLES, CallTransformer.FUNCTION_CALL_TRANSFORMER); } - else { - JetValueArgumentList valueArgumentList = context.call.getValueArgumentList(); - PsiElement reportAbsenceOn = valueArgumentList == null ? context.call.getCallElement() : valueArgumentList; - if (calleeExpression instanceof JetConstructorCalleeExpression) { - assert !context.call.getExplicitReceiver().exists(); - - JetConstructorCalleeExpression expression = (JetConstructorCalleeExpression) calleeExpression; - functionReference = expression.getConstructorReferenceExpression(); - if (functionReference == null) { - return checkArgumentTypesAndFail(context); // No type there - } - JetTypeReference typeReference = expression.getTypeReference(); - assert typeReference != null; - JetType constructedType = typeResolver.resolveType(context.scope, typeReference, context.trace, true); - - if (constructedType.isError()) { - return checkArgumentTypesAndFail(context); - } - - DeclarationDescriptor declarationDescriptor = constructedType.getConstructor().getDeclarationDescriptor(); - if (declarationDescriptor instanceof ClassDescriptor) { - ClassDescriptor classDescriptor = (ClassDescriptor) declarationDescriptor; - Collection constructors = classDescriptor.getConstructors(); - if (constructors.isEmpty()) { - context.trace.report(NO_CONSTRUCTOR.on(reportAbsenceOn)); - return checkArgumentTypesAndFail(context); - } - Collection> candidates = - taskPrioritizer.convertWithImpliedThisAndNoReceiver( - context.scope, constructors, context.call); - prioritizedTasks = taskPrioritizer.computePrioritizedTasksFromCandidates( - context, candidates, TracingStrategyImpl.create(functionReference, context.call)); - } - else { - context.trace.report(NOT_A_CLASS.on(calleeExpression)); - return checkArgumentTypesAndFail(context); - } - } - else if (calleeExpression instanceof JetThisReferenceExpression) { - functionReference = (JetThisReferenceExpression) calleeExpression; - DeclarationDescriptor containingDeclaration = context.scope.getContainingDeclaration(); - if (containingDeclaration instanceof ConstructorDescriptor) { - containingDeclaration = containingDeclaration.getContainingDeclaration(); - } - assert containingDeclaration instanceof ClassDescriptor; - ClassDescriptor classDescriptor = (ClassDescriptor) containingDeclaration; - - Collection constructors = classDescriptor.getConstructors(); - if (constructors.isEmpty()) { - context.trace.report(NO_CONSTRUCTOR.on(reportAbsenceOn)); - return checkArgumentTypesAndFail(context); - } - List> candidates = - ResolutionCandidate.convertCollection(context.call, constructors); - prioritizedTasks = Collections.singletonList(new ResolutionTask(candidates, functionReference, context)); // !! DataFlowInfo.EMPTY - } - else if (calleeExpression != null) { - - // Here we handle the case where the callee expression must be something of type function, e.g. (foo.bar())(1, 2) - JetType calleeType = expressionTypingServices.safeGetType(context.scope, calleeExpression, NO_EXPECTED_TYPE, context.dataFlowInfo, context.trace); - ExpressionReceiver expressionReceiver = new ExpressionReceiver(calleeExpression, calleeType); - - Call call = new CallTransformer.CallForImplicitInvoke( - context.call.getExplicitReceiver(), expressionReceiver, context.call); - TracingStrategyForInvoke tracingForInvoke = new TracingStrategyForInvoke( - calleeExpression, call, calleeType); - return resolveCallForInvoke(context.replaceCall(call), tracingForInvoke); - } - else { - return checkArgumentTypesAndFail(context); - } + if (calleeExpression instanceof JetConstructorCalleeExpression) { + return resolveCallForConstructor(context, (JetConstructorCalleeExpression) calleeExpression); + } + else if (calleeExpression instanceof JetThisReferenceExpression) { + return resolveCallForThisExpression(context, (JetThisReferenceExpression) calleeExpression); + } + else if (calleeExpression == null) { + return checkArgumentTypesAndFail(context); } - TracingStrategy tracing = TracingStrategyImpl.create(functionReference, context.call); - return doResolveCallOrGetCachedResults(context, prioritizedTasks, CallTransformer.FUNCTION_CALL_TRANSFORMER, tracing); + // Here we handle the case where the callee expression must be something of type function, e.g. (foo.bar())(1, 2) + JetType calleeType = expressionTypingServices.safeGetType( + context.scope, calleeExpression, NO_EXPECTED_TYPE, context.dataFlowInfo, context.trace); + ExpressionReceiver expressionReceiver = new ExpressionReceiver(calleeExpression, calleeType); + + Call call = new CallTransformer.CallForImplicitInvoke(context.call.getExplicitReceiver(), expressionReceiver, context.call); + TracingStrategyForInvoke tracingForInvoke = new TracingStrategyForInvoke(calleeExpression, call, calleeType); + return resolveCallForInvoke(context.replaceCall(call), tracingForInvoke); + } + + private OverloadResolutionResults resolveCallForConstructor( + @NotNull BasicCallResolutionContext context, + @NotNull JetConstructorCalleeExpression expression + ) { + assert !context.call.getExplicitReceiver().exists() : + "Constructor can't be invoked with explicit receiver: " + context.call.getCallElement().getText(); + + JetReferenceExpression functionReference = expression.getConstructorReferenceExpression(); + JetTypeReference typeReference = expression.getTypeReference(); + if (functionReference == null || typeReference == null) { + return checkArgumentTypesAndFail(context); // No type there + } + JetType constructedType = typeResolver.resolveType(context.scope, typeReference, context.trace, true); + if (constructedType.isError()) { + return checkArgumentTypesAndFail(context); + } + + DeclarationDescriptor declarationDescriptor = constructedType.getConstructor().getDeclarationDescriptor(); + if (!(declarationDescriptor instanceof ClassDescriptor)) { + context.trace.report(NOT_A_CLASS.on(expression)); + return checkArgumentTypesAndFail(context); + } + ClassDescriptor classDescriptor = (ClassDescriptor) declarationDescriptor; + Collection constructors = classDescriptor.getConstructors(); + if (constructors.isEmpty()) { + context.trace.report(NO_CONSTRUCTOR.on(CallUtilPackage.getValueArgumentListOrElement(context.call))); + return checkArgumentTypesAndFail(context); + } + Collection> candidates = + taskPrioritizer.convertWithImpliedThisAndNoReceiver(context.scope, constructors, context.call); + + return computeTasksFromCandidatesAndResolvedCall(context, functionReference, candidates, CallTransformer.FUNCTION_CALL_TRANSFORMER); + } + + private OverloadResolutionResults resolveCallForThisExpression( + @NotNull BasicCallResolutionContext context, + @NotNull JetThisReferenceExpression calleeExpression + ) { + DeclarationDescriptor containingDeclaration = context.scope.getContainingDeclaration(); + if (containingDeclaration instanceof ConstructorDescriptor) { + containingDeclaration = containingDeclaration.getContainingDeclaration(); + } + assert containingDeclaration instanceof ClassDescriptor; + + Collection constructors = ((ClassDescriptor) containingDeclaration).getConstructors(); + if (constructors.isEmpty()) { + context.trace.report(NO_CONSTRUCTOR.on(CallUtilPackage.getValueArgumentListOrElement(context.call))); + return checkArgumentTypesAndFail(context); + } + List> candidates = + ResolutionCandidate.convertCollection(context.call, constructors); + + return computeTasksFromCandidatesAndResolvedCall(context, calleeExpression, candidates, CallTransformer.FUNCTION_CALL_TRANSFORMER); } public OverloadResolutionResults resolveCallWithKnownCandidate( @@ -315,9 +320,9 @@ public class CallResolver { BasicCallResolutionContext.create(context, call, CheckValueArgumentsMode.ENABLED, dataFlowInfoForArguments); List> tasks = - taskPrioritizer.computePrioritizedTasksFromCandidates(basicCallResolutionContext, Collections.singleton(candidate), tracing); - return doResolveCallOrGetCachedResults( - basicCallResolutionContext, tasks, CallTransformer.FUNCTION_CALL_TRANSFORMER, tracing); + taskPrioritizer.computePrioritizedTasksFromCandidates( + basicCallResolutionContext, Collections.singleton(candidate), tracing); + return doResolveCallOrGetCachedResults(basicCallResolutionContext, tasks, CallTransformer.FUNCTION_CALL_TRANSFORMER, tracing); } private OverloadResolutionResultsImpl doResolveCallOrGetCachedResults( diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/tasks/AbstractTracingStrategy.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/tasks/AbstractTracingStrategy.java index 62cec8d0bf3..16f795b67dd 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/tasks/AbstractTracingStrategy.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/tasks/AbstractTracingStrategy.java @@ -24,6 +24,7 @@ import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.BindingTrace; import org.jetbrains.jet.lang.resolve.DescriptorUtils; +import org.jetbrains.jet.lang.resolve.calls.callUtil.CallUtilPackage; import org.jetbrains.jet.lang.resolve.calls.inference.*; import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall; import org.jetbrains.jet.lang.resolve.descriptorUtil.DescriptorUtilPackage; @@ -66,14 +67,7 @@ public abstract class AbstractTracingStrategy implements TracingStrategy { @Override public void noValueForParameter(@NotNull BindingTrace trace, @NotNull ValueParameterDescriptor valueParameter) { - JetElement reportOn; - JetValueArgumentList valueArgumentList = call.getValueArgumentList(); - if (valueArgumentList != null) { - reportOn = valueArgumentList; - } - else { - reportOn = reference; - } + JetElement reportOn = CallUtilPackage.getValueArgumentListOrElement(call); trace.report(NO_VALUE_FOR_PARAMETER.on(reportOn, valueParameter)); } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/util/callUtil.kt b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/util/callUtil.kt index 8af22f09083..96d5b1de73d 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/util/callUtil.kt +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/util/callUtil.kt @@ -49,6 +49,7 @@ import org.jetbrains.jet.lang.psi.JetCallExpression import org.jetbrains.jet.lang.psi.JetFunctionLiteralArgument import org.jetbrains.jet.lang.psi.JetFunctionLiteralExpression import org.jetbrains.jet.lang.psi.JetFunctionLiteral +import org.jetbrains.jet.lang.psi.JetValueArgumentList // resolved call @@ -95,6 +96,8 @@ public fun Call.getValueArgumentsInParentheses(): List = getValue public fun JetCallExpression.getValueArgumentsInParentheses(): List = getValueArguments().filterArgsInParentheses() +public fun Call.getValueArgumentListOrElement(): JetElement = getValueArgumentList() ?: getCalleeExpression() ?: getCallElement() + [suppress("UNCHECKED_CAST")] private fun List.filterArgsInParentheses() = filter { it !is JetFunctionLiteralArgument } as List