From 114763b0b2abeac6a783f4440ceef0ca38bed041 Mon Sep 17 00:00:00 2001 From: Andrey Breslav Date: Thu, 6 Oct 2011 20:20:10 +0400 Subject: [PATCH] Refactoring autocasts --- .../jet/lang/diagnostics/Errors.java | 3 +- .../jet/lang/resolve/BindingContext.java | 6 +- .../jet/lang/resolve/calls/AutoCastUtils.java | 2 +- .../jet/lang/resolve/calls/CallResolver.java | 101 +++++++++------- .../resolve/calls/DefaultValueArgument.java | 10 ++ .../calls/ExpressionValueArgument.java | 20 +++ .../lang/resolve/calls/ResolutionTask.java | 26 ++-- .../jet/lang/resolve/calls/ResolvedCall.java | 11 +- .../lang/resolve/calls/TaskPrioritizer.java | 114 +++++++++++------- .../lang/resolve/calls/TaskPrioritizers.java | 22 +--- .../lang/resolve/calls/TracingStrategy.java | 4 +- .../resolve/calls/VarargValueArgument.java | 19 +++ 12 files changed, 207 insertions(+), 131 deletions(-) create mode 100644 compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/DefaultValueArgument.java create mode 100644 compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ExpressionValueArgument.java create mode 100644 compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/VarargValueArgument.java diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java index ff09318972b..f3c486994ac 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java @@ -7,7 +7,6 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.psi.*; -import org.jetbrains.jet.lang.resolve.calls.ResolvedCall; import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.lexer.JetKeywordToken; import org.jetbrains.jet.resolve.DescriptorRenderer; @@ -351,7 +350,7 @@ public interface Errors { }; ParameterizedDiagnosticFactory3 RESULT_TYPE_MISMATCH = ParameterizedDiagnosticFactory3.create(ERROR, "{0} must return {1} but returns {2}"); - ParameterizedDiagnosticFactory3 UNSAFE_INFIX_CALL = ParameterizedDiagnosticFactory3.create(ERROR, "Infix call corresponds to a dot-qualified call ''{0}.{1}({2})' which is not allowed on a nullable receiver ''{0}''. Use '?.'-qualified call instead"); + ParameterizedDiagnosticFactory3 UNSAFE_INFIX_CALL = ParameterizedDiagnosticFactory3.create(ERROR, "Infix call corresponds to a dot-qualified call ''{0}.{1}({2})'' which is not allowed on a nullable receiver ''{0}''. Use '?.'-qualified call instead"); AmbiguousDescriptorDiagnosticFactory OVERLOAD_RESOLUTION_AMBIGUITY = new AmbiguousDescriptorDiagnosticFactory("Overload resolution ambiguity: {0}"); AmbiguousDescriptorDiagnosticFactory NONE_APPLICABLE = new AmbiguousDescriptorDiagnosticFactory("None of the following functions can be called with the arguments supplied: {0}"); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingContext.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingContext.java index d436f9bcdb2..dd77c5069a5 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingContext.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingContext.java @@ -9,7 +9,6 @@ import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.calls.ResolvedCall; import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant; import org.jetbrains.jet.lang.resolve.scopes.JetScope; -import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor; import org.jetbrains.jet.lang.types.DeferredType; import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.util.CommonSuppliers; @@ -21,14 +20,15 @@ import java.util.Collection; * @author abreslav */ public interface BindingContext { - WritableSlice RECEIVER = Slices.createSimpleSlice("RECEIVER"); - WritableSlice ANNOTATION = Slices.createSimpleSlice("ANNOTATION"); + WritableSlice> COMPILE_TIME_VALUE = Slices.createSimpleSlice("COMPILE_TIME_VALUE"); WritableSlice TYPE = Slices.createSimpleSlice("TYPE"); WritableSlice EXPRESSION_TYPE = new BasicWritableSlice("EXPRESSION_TYPE", RewritePolicy.DO_NOTHING); WritableSlice REFERENCE_TARGET = new BasicWritableSlice("REFERENCE_TARGET", RewritePolicy.DO_NOTHING); + WritableSlice> RESOLVED_CALL = new BasicWritableSlice>("RESOLVED_CALL", RewritePolicy.DO_NOTHING); + WritableSlice>> AMBIGUOUS_REFERENCE_TARGET = new BasicWritableSlice>>("AMBIGUOUS_REFERENCE_TARGET", RewritePolicy.DO_NOTHING); WritableSlice LOOP_RANGE_ITERATOR = Slices.createSimpleSlice("LOOP_RANGE_ITERATOR"); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/AutoCastUtils.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/AutoCastUtils.java index 3d3fdbe817b..52444691797 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/AutoCastUtils.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/AutoCastUtils.java @@ -26,7 +26,7 @@ public class AutoCastUtils { private AutoCastUtils() {} - public static List getAutocastVariants(@NotNull final BindingContext bindingContext, @NotNull final DataFlowInfo dataFlowInfo, @NotNull ReceiverDescriptor receiverToCast) { + public static List getAutoCastVariants(@NotNull final BindingContext bindingContext, @NotNull final DataFlowInfo dataFlowInfo, @NotNull ReceiverDescriptor receiverToCast) { return receiverToCast.accept(new ReceiverDescriptorVisitor, Object>() { @Override public List visitNoReceiver(ReceiverDescriptor noReceiver, Object data) { 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 092bec6faf1..dbd4505e471 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 @@ -25,7 +25,6 @@ import static org.jetbrains.jet.lang.diagnostics.Errors.*; import static org.jetbrains.jet.lang.resolve.BindingContext.*; import static org.jetbrains.jet.lang.resolve.calls.ResolvedCall.MAP_TO_CANDIDATE; import static org.jetbrains.jet.lang.resolve.calls.ResolvedCall.MAP_TO_RESULT; -import static org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor.NO_RECEIVER; import static org.jetbrains.jet.lang.types.JetTypeInferrer.NO_EXPECTED_TYPE; /** @@ -150,7 +149,7 @@ public class CallResolver { trace.report(NO_CONSTRUCTOR.on(reportAbsenceOn)); return checkArgumentTypesAndFail(trace, scope, call); } - prioritizedTasks.add(new ResolutionTask(ResolvedCall.convertCollection(constructors), NO_RECEIVER, call)); + prioritizedTasks.add(new ResolutionTask(ResolvedCall.convertCollection(constructors), call, DataFlowInfo.getEmpty())); } else { // trace.getErrorHandler().genericError(calleeExpression.getNode(), "Not a class"); @@ -170,7 +169,7 @@ public class CallResolver { trace.report(NO_CONSTRUCTOR.on(reportAbsenceOn)); return checkArgumentTypesAndFail(trace, scope, call); } - prioritizedTasks = Collections.singletonList(new ResolutionTask(ResolvedCall.convertCollection(constructors), NO_RECEIVER, call)); + prioritizedTasks = Collections.singletonList(new ResolutionTask(ResolvedCall.convertCollection(constructors), call, DataFlowInfo.getEmpty())); } else { throw new UnsupportedOperationException("Type argument inference not implemented for " + call.getText()); @@ -211,17 +210,16 @@ public class CallResolver { OverloadResolutionResults resultsForFirstNonemptyCandidateSet = null; TracingStrategy tracing = new TracingStrategy() { @Override - public void bindReference(@NotNull BindingTrace trace, @NotNull ReceiverDescriptor receiver, @NotNull CallableDescriptor descriptor) { - trace.record(REFERENCE_TARGET, reference, descriptor); - trace.record(RECEIVER, reference, receiver); - if (receiver instanceof AutoCastReceiver) { - AutoCastReceiver autoCastReceiver = (AutoCastReceiver) receiver; - ReceiverDescriptor original = autoCastReceiver.getOriginal(); - if (original instanceof ExpressionReceiver) { - ExpressionReceiver expressionReceiver = (ExpressionReceiver) original; - trace.record(AUTOCAST, expressionReceiver.getExpression(), autoCastReceiver.getType()); - } - } + public void bindReference(@NotNull BindingTrace trace, @NotNull ResolvedCall resolvedCall) { + D descriptor = resolvedCall.getCandidateDescriptor(); +// if (descriptor instanceof VariableAsFunctionDescriptor) { +// VariableAsFunctionDescriptor variableAsFunctionDescriptor = (VariableAsFunctionDescriptor) descriptor; +// trace.record(REFERENCE_TARGET, reference, variableAsFunctionDescriptor.getVariableDescriptor()); +// } +// else { + trace.record(REFERENCE_TARGET, reference, descriptor); +// } + trace.record(RESOLVED_CALL, reference, resolvedCall); } @Override @@ -334,7 +332,7 @@ public class CallResolver { TemporaryBindingTrace temporaryTrace = TemporaryBindingTrace.create(trace); candidateCall.setTrace(temporaryTrace); - tracing.bindReference(temporaryTrace, task.getReceiver(), candidate); + tracing.bindReference(temporaryTrace, candidateCall); if (ErrorUtils.isError(candidate)) { successfulCandidates.add(candidateCall.setResultingDescriptor(candidate)); @@ -356,7 +354,7 @@ public class CallResolver { if (task.getTypeArguments().isEmpty()) { if (candidate.getTypeParameters().isEmpty()) { if (checkValueArgumentTypes(scope, temporaryTrace, argumentsToParameters, dirty, Functions.identity()) - && checkReceiver(task, tracing, candidate, temporaryTrace)) { + && checkReceiver(candidateCall, tracing, candidate, temporaryTrace)) { successfulCandidates.add(candidateCall.setResultingDescriptor(candidate)); } else { @@ -387,12 +385,12 @@ public class CallResolver { } } - checkReceiverAbsence(task, tracing, candidate, temporaryTrace); + checkReceiverAbsence(candidateCall, tracing, candidate, temporaryTrace); // Error is already reported if something is missing - ReceiverDescriptor receiver = task.getReceiver(); + ReceiverDescriptor receiverParameter = candidateCall.getReceiverParameter(); ReceiverDescriptor candidateReceiver = candidate.getReceiver(); - if (receiver.exists() && candidateReceiver.exists()) { - constraintSystem.addSubtypingConstraint(receiver.getType(), candidateReceiver.getType()); + if (receiverParameter.exists() && candidateReceiver.exists()) { + constraintSystem.addSubtypingConstraint(receiverParameter.getType(), candidateReceiver.getType()); } if (expectedType != NO_EXPECTED_TYPE) { @@ -442,7 +440,7 @@ public class CallResolver { Function mapFunction = createMapFunction(substitutedFunctionDescriptor); if (checkValueArgumentTypes(scope, temporaryTrace, argumentsToParameters, dirty, mapFunction) - && checkReceiver(task, tracing, substitutedFunctionDescriptor, temporaryTrace)) { + && checkReceiver(candidateCall, tracing, substitutedFunctionDescriptor, temporaryTrace)) { successfulCandidates.add(candidateCall.setResultingDescriptor(substitutedFunctionDescriptor)); } else { @@ -460,6 +458,9 @@ public class CallResolver { dirtyCandidates.add(candidateCall); } task.performAdvancedChecks(candidate, temporaryTrace, tracing); + + recordAutoCastIfNecessary(candidateCall.getReceiverParameter(), candidateCall.getTrace()); + recordAutoCastIfNecessary(candidateCall.getThisObject(), candidateCall.getTrace()); } OverloadResolutionResults results = computeResultAndReportErrors(trace, tracing, successfulCandidates, failedCandidates, dirtyCandidates); @@ -469,6 +470,17 @@ public class CallResolver { return results; } + private void recordAutoCastIfNecessary(ReceiverDescriptor receiver, BindingTrace trace) { + if (receiver instanceof AutoCastReceiver) { + AutoCastReceiver autoCastReceiver = (AutoCastReceiver) receiver; + ReceiverDescriptor original = autoCastReceiver.getOriginal(); + if (original instanceof ExpressionReceiver) { + ExpressionReceiver expressionReceiver = (ExpressionReceiver) original; + trace.record(AUTOCAST, expressionReceiver.getExpression(), autoCastReceiver.getType()); + } + } + } + private void checkTypesWithNoCallee(BindingTrace trace, JetScope scope, List typeArguments, List valueArguments, List functionLiteralArguments) { for (ValueArgument valueArgument : valueArguments) { JetExpression argumentExpression = valueArgument.getArgumentExpression(); @@ -501,9 +513,9 @@ public class CallResolver { }; } - private boolean checkReceiver(ResolutionTask task, TracingStrategy tracing, D candidate, TemporaryBindingTrace temporaryTrace) { - if (!checkReceiverAbsence(task, tracing, candidate, temporaryTrace)) return false; - ReceiverDescriptor receiver = task.getReceiver(); + private boolean checkReceiver(ResolvedCall resolvedCall, TracingStrategy tracing, D candidate, TemporaryBindingTrace temporaryTrace) { + if (!checkReceiverAbsence(resolvedCall, tracing, candidate, temporaryTrace)) return false; + ReceiverDescriptor receiver = resolvedCall.getReceiverParameter(); ReceiverDescriptor candidateReceiver = candidate.getReceiver(); if (receiver.exists() && candidateReceiver.exists() @@ -514,8 +526,8 @@ public class CallResolver { return true; } - private boolean checkReceiverAbsence(ResolutionTask task, TracingStrategy tracing, D candidate, TemporaryBindingTrace temporaryTrace) { - ReceiverDescriptor receiver = task.getReceiver(); + private boolean checkReceiverAbsence(ResolvedCall resolvedCall, TracingStrategy tracing, D candidate, TemporaryBindingTrace temporaryTrace) { + ReceiverDescriptor receiver = resolvedCall.getReceiverParameter(); ReceiverDescriptor candidateReceiver = candidate.getReceiver(); if (receiver.exists()) { if (!candidateReceiver.exists()) { @@ -669,25 +681,24 @@ public class CallResolver { @NotNull public OverloadResolutionResults resolveExactSignature(@NotNull JetScope scope, @NotNull ReceiverDescriptor receiver, @NotNull String name, @NotNull List parameterTypes) { - List result = findCandidatesByExactSignature(scope, receiver, name, parameterTypes); + List> result = findCandidatesByExactSignature(scope, receiver, name, parameterTypes); BindingTraceContext trace = new BindingTraceContext(); TemporaryBindingTrace temporaryBindingTrace = TemporaryBindingTrace.create(trace); Set> candidates = Sets.newLinkedHashSet(); - for (FunctionDescriptor functionDescriptor : result) { - ResolvedCall resolvedCall = ResolvedCall.create(functionDescriptor); - candidates.add(resolvedCall.setResultingDescriptor(functionDescriptor)); - resolvedCall.setTrace(temporaryBindingTrace); + for (ResolvedCall call : result) { + call.setTrace(temporaryBindingTrace); + candidates.add(call); } return computeResultAndReportErrors(trace, TracingStrategy.EMPTY, candidates, Collections.>emptySet(), Collections.>emptySet()); } - private List findCandidatesByExactSignature(JetScope scope, ReceiverDescriptor receiver, String name, List parameterTypes) { - List result = Lists.newArrayList(); + private List> findCandidatesByExactSignature(JetScope scope, ReceiverDescriptor receiver, String name, List parameterTypes) { + List> result = Lists.newArrayList(); if (receiver.exists()) { - Set extensionFunctionDescriptors = scope.getFunctions(name); - List nonlocal = Lists.newArrayList(); - List local = Lists.newArrayList(); + Collection> extensionFunctionDescriptors = ResolvedCall.convertCollection(scope.getFunctions(name)); + List> nonlocal = Lists.newArrayList(); + List> local = Lists.newArrayList(); TaskPrioritizer.splitLexicallyLocalDescriptors(extensionFunctionDescriptors, scope.getContainingDeclaration(), local, nonlocal); @@ -695,7 +706,7 @@ public class CallResolver { return result; } - Set functionDescriptors = receiver.getType().getMemberScope().getFunctions(name); + Collection> functionDescriptors = ResolvedCall.convertCollection(receiver.getType().getMemberScope().getFunctions(name)); if (lookupExactSignature(functionDescriptors, parameterTypes, result)) { return result; @@ -704,32 +715,34 @@ public class CallResolver { return result; } else { - lookupExactSignature(scope.getFunctions(name), parameterTypes, result); + lookupExactSignature(ResolvedCall.convertCollection(scope.getFunctions(name)), parameterTypes, result); return result; } } - private boolean lookupExactSignature(Set candidates, List parameterTypes, List result) { + private boolean lookupExactSignature(Collection> candidates, List parameterTypes, List> result) { boolean found = false; - for (FunctionDescriptor functionDescriptor : candidates) { + for (ResolvedCall resolvedCall : candidates) { + FunctionDescriptor functionDescriptor = resolvedCall.getResultingDescriptor(); if (functionDescriptor.getReceiver().exists()) continue; if (!functionDescriptor.getTypeParameters().isEmpty()) continue; if (!checkValueParameters(functionDescriptor, parameterTypes)) continue; - result.add(functionDescriptor); + result.add(resolvedCall); found = true; } return found; } - private boolean findExtensionFunctions(Collection candidates, ReceiverDescriptor receiver, List parameterTypes, List result) { + private boolean findExtensionFunctions(Collection> candidates, ReceiverDescriptor receiver, List parameterTypes, List> result) { boolean found = false; - for (FunctionDescriptor functionDescriptor : candidates) { + for (ResolvedCall resolvedCall : candidates) { + FunctionDescriptor functionDescriptor = resolvedCall.getResultingDescriptor(); ReceiverDescriptor functionReceiver = functionDescriptor.getReceiver(); if (!functionReceiver.exists()) continue; if (!functionDescriptor.getTypeParameters().isEmpty()) continue; if (!semanticServices.getTypeChecker().isSubtypeOf(receiver.getType(), functionReceiver.getType())) continue; if (!checkValueParameters(functionDescriptor, parameterTypes))continue; - result.add(functionDescriptor); + result.add(resolvedCall); found = true; } return found; diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/DefaultValueArgument.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/DefaultValueArgument.java new file mode 100644 index 00000000000..07aeb6be9f2 --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/DefaultValueArgument.java @@ -0,0 +1,10 @@ +package org.jetbrains.jet.lang.resolve.calls; + +/** +* @author abreslav +*/ +public class DefaultValueArgument implements ResolvedValueArgument { + public static final DefaultValueArgument DEFAULT = new DefaultValueArgument(); + + DefaultValueArgument() {} +} diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ExpressionValueArgument.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ExpressionValueArgument.java new file mode 100644 index 00000000000..045d4c4f1c0 --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ExpressionValueArgument.java @@ -0,0 +1,20 @@ +package org.jetbrains.jet.lang.resolve.calls; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.lang.psi.JetExpression; + +/** +* @author abreslav +*/ +public class ExpressionValueArgument implements ResolvedValueArgument { + private final JetExpression expression; + + public ExpressionValueArgument(@NotNull JetExpression expression) { + this.expression = expression; + } + + @NotNull + public JetExpression getExpression() { + return expression; + } +} diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ResolutionTask.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ResolutionTask.java index b9560678fba..a8dbede8e64 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ResolutionTask.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ResolutionTask.java @@ -7,7 +7,7 @@ import org.jetbrains.jet.lang.psi.JetExpression; import org.jetbrains.jet.lang.psi.JetTypeProjection; import org.jetbrains.jet.lang.psi.ValueArgument; import org.jetbrains.jet.lang.resolve.BindingTrace; -import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor; +import org.jetbrains.jet.lang.types.DataFlowInfo; import java.util.Collection; import java.util.List; @@ -17,31 +17,36 @@ import java.util.List; */ /*package*/ class ResolutionTask { private final Collection> candidates; - private final ReceiverDescriptor receiver; private final List typeArguments; private final List valueArguments; private final List functionLiteralArguments; + private final DataFlowInfo dataFlowInfo; private DescriptorCheckStrategy checkingStrategy; public ResolutionTask( @NotNull Collection> candidates, - @NotNull ReceiverDescriptor receiver, @NotNull List typeArguments, @NotNull List valueArguments, - @NotNull List functionLiteralArguments) { + @NotNull List functionLiteralArguments, + @NotNull DataFlowInfo dataFlowInfo) { this.candidates = candidates; - this.receiver = receiver; this.typeArguments = typeArguments; this.valueArguments = valueArguments; this.functionLiteralArguments = functionLiteralArguments; + this.dataFlowInfo = dataFlowInfo; } public ResolutionTask( @NotNull Collection> candidates, - @NotNull ReceiverDescriptor receiver, - @NotNull Call call + @NotNull Call call, + @NotNull DataFlowInfo dataFlowInfo ) { - this(candidates, receiver, call.getTypeArguments(), call.getValueArguments(), call.getFunctionLiteralArguments()); + this(candidates, call.getTypeArguments(), call.getValueArguments(), call.getFunctionLiteralArguments(), dataFlowInfo); + } + + @NotNull + public DataFlowInfo getDataFlowInfo() { + return dataFlowInfo; } @NotNull @@ -49,11 +54,6 @@ import java.util.List; return candidates; } - @NotNull - public ReceiverDescriptor getReceiver() { - return receiver; - } - @NotNull public List getTypeArguments() { return typeArguments; diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ResolvedCall.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ResolvedCall.java index b18d967ecf6..88ef0180dfc 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ResolvedCall.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ResolvedCall.java @@ -4,7 +4,6 @@ import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.intellij.util.Function; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.CallableDescriptor; import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor; import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor; @@ -16,6 +15,8 @@ import java.util.Collection; import java.util.List; import java.util.Map; +import static org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor.NO_RECEIVER; + /** * @author abreslav */ @@ -51,8 +52,8 @@ public class ResolvedCall { private final D candidateDescriptor; private D resultingDescriptor; // Probably substituted - private ReceiverDescriptor thisObject; // receiver object of a method - private ReceiverDescriptor receiverParameter; // receiver of an extension function + private ReceiverDescriptor thisObject = NO_RECEIVER; // receiver object of a method + private ReceiverDescriptor receiverParameter = NO_RECEIVER; // receiver of an extension function private final Map typeArguments = Maps.newHashMap(); private final Map autoCasts = Maps.newHashMap(); private final Map valueArguments = Maps.newHashMap(); @@ -101,7 +102,7 @@ public class ResolvedCall { autoCasts.put(parameter, target); } - @Nullable + @NotNull public ReceiverDescriptor getReceiverParameter() { return receiverParameter; } @@ -110,7 +111,7 @@ public class ResolvedCall { this.receiverParameter = receiverParameter; } - @Nullable + @NotNull public ReceiverDescriptor getThisObject() { return thisObject; } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/TaskPrioritizer.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/TaskPrioritizer.java index a71578341df..a7a1036d579 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/TaskPrioritizer.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/TaskPrioritizer.java @@ -2,15 +2,13 @@ package org.jetbrains.jet.lang.resolve.calls; import com.google.common.collect.Lists; import org.jetbrains.annotations.NotNull; -import org.jetbrains.jet.lang.descriptors.CallableDescriptor; -import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; -import org.jetbrains.jet.lang.descriptors.FunctionDescriptor; -import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor; +import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.psi.Call; import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.scopes.JetScope; import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor; import org.jetbrains.jet.lang.types.DataFlowInfo; +import org.jetbrains.jet.lang.types.JetType; import java.util.Collection; import java.util.List; @@ -22,15 +20,15 @@ import static org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor */ /*package*/ abstract class TaskPrioritizer { - public static void splitLexicallyLocalDescriptors( - Collection allDescriptors, DeclarationDescriptor containerOfTheCurrentLocality, List local, List nonlocal) { + public static void splitLexicallyLocalDescriptors( + Collection> allDescriptors, DeclarationDescriptor containerOfTheCurrentLocality, Collection> local, Collection> nonlocal) { - for (T descriptor : allDescriptors) { - if (isLocal(containerOfTheCurrentLocality, descriptor)) { - local.add(descriptor); + for (ResolvedCall resolvedCall : allDescriptors) { + if (isLocal(containerOfTheCurrentLocality, resolvedCall.getCandidateDescriptor())) { + local.add(resolvedCall); } else { - nonlocal.add(descriptor); + nonlocal.add(resolvedCall); } } } @@ -47,7 +45,7 @@ import static org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor * * local extension prevail over members (and members prevail over all non-local extensions) */ - public static boolean isLocal(DeclarationDescriptor containerOfTheCurrentLocality, DeclarationDescriptor candidate) { + private static boolean isLocal(DeclarationDescriptor containerOfTheCurrentLocality, DeclarationDescriptor candidate) { if (candidate instanceof ValueParameterDescriptor) { return true; } @@ -72,75 +70,105 @@ import static org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor // return result; // } - public List> computePrioritizedTasks(@NotNull JetScope scope, @NotNull ReceiverDescriptor receiver, @NotNull Call call, @NotNull String name, @NotNull BindingContext bindingContext, @NotNull DataFlowInfo dataFlowInfo) { + public List> computePrioritizedTasks(@NotNull JetScope scope, @NotNull ReceiverDescriptor explicitReceiver, @NotNull Call call, @NotNull String name, @NotNull BindingContext bindingContext, @NotNull DataFlowInfo dataFlowInfo) { List> result = Lists.newArrayList(); - doComputeTasks(scope, receiver, call, name, result); + doComputeTasks(scope, explicitReceiver, call, name, result, DataFlowInfo.getEmpty()); -// ReceiverDescriptor receiverToCast = receiver.exists() ? receiver : scope.getImplicitReceiver(); -// if (receiverToCast.exists()) { -// for (ReceiverDescriptor castReceiver : AutoCastUtils.getAutocastVariants(bindingContext, dataFlowInfo, receiverToCast)) { -// doComputeTasks(scope, castReceiver, call, name, result); -// } -// } + ReceiverDescriptor receiverToCast = explicitReceiver.exists() ? explicitReceiver : scope.getImplicitReceiver(); + if (receiverToCast.exists()) { + doComputeTasks(scope, receiverToCast, call, name, result, dataFlowInfo); + } return result; } - private void doComputeTasks(JetScope scope, ReceiverDescriptor receiver, Call call, String name, List> result) { + private void doComputeTasks(JetScope scope, ReceiverDescriptor explicitReceiver, Call call, String name, List> result, @NotNull DataFlowInfo dataFlowInfo) { List implicitReceivers = Lists.newArrayList(); scope.getImplicitReceiversHierarchy(implicitReceivers); - if (receiver.exists()) { - Collection extensionFunctions = getExtensionsByName(scope, name); - List nonlocals = Lists.newArrayList(); - List locals = Lists.newArrayList(); + if (explicitReceiver.exists()) { + Collection> extensionFunctions = convertWithImpliedThis(explicitReceiver, getExtensionsByName(scope, name)); + List> nonlocals = Lists.newArrayList(); + List> locals = Lists.newArrayList(); //noinspection unchecked,RedundantTypeArguments TaskPrioritizer.splitLexicallyLocalDescriptors(extensionFunctions, scope.getContainingDeclaration(), locals, nonlocals); - Collection members = getMembersByName(receiver, name); + // AutoCastUtils.getAutoCastVariants(bindingContext, dataFlowInfo, receiverToCast) + Collection members = getMembersByName(explicitReceiver.getType(), name); - addTask(result, receiver, call, locals); - addTask(result, NO_RECEIVER, call, members); + addTask(result, call, locals, dataFlowInfo); + addTask(result, call, convertWithReceivers(members, explicitReceiver, NO_RECEIVER), dataFlowInfo); for (ReceiverDescriptor implicitReceiver : implicitReceivers) { Collection memberExtensions = getExtensionsByName(implicitReceiver.getType().getMemberScope(), name); - addTask(result, receiver, call, memberExtensions); + addTask(result, call, convertWithReceivers(memberExtensions, implicitReceiver, explicitReceiver), dataFlowInfo); } - addTask(result, receiver, call, nonlocals); + addTask(result, call, nonlocals, dataFlowInfo); } else { - Collection functions = getNonExtensionsByName(scope, name); + Collection> functions = convertWithImpliedThis(explicitReceiver, getNonExtensionsByName(scope, name)); - List nonlocals = Lists.newArrayList(); - List locals = Lists.newArrayList(); + List> nonlocals = Lists.newArrayList(); + List> locals = Lists.newArrayList(); //noinspection unchecked,RedundantTypeArguments TaskPrioritizer.splitLexicallyLocalDescriptors(functions, scope.getContainingDeclaration(), locals, nonlocals); - addTask(result, receiver, call, locals); + addTask(result, call, locals, dataFlowInfo); for (ReceiverDescriptor implicitReceiver : implicitReceivers) { - doComputeTasks(scope, implicitReceiver, call, name, result); + doComputeTasks(scope, implicitReceiver, call, name, result, dataFlowInfo); } - addTask(result, receiver, call, nonlocals); + addTask(result, call, nonlocals, dataFlowInfo); } } - private void addTask(@NotNull List> result, @NotNull ReceiverDescriptor receiver, @NotNull Call call, @NotNull Collection candidateDescriptors) { - if (candidateDescriptors.isEmpty()) return; - result.add(createTask(receiver, call, ResolvedCall.convertCollection(candidateDescriptors))); + private Collection> convertWithReceivers(Collection descriptors, ReceiverDescriptor thisObject, ReceiverDescriptor receiverParameter) { + Collection> result = Lists.newArrayList(); + for (D extension : descriptors) { + ResolvedCall resolvedCall = ResolvedCall.create(extension); + resolvedCall.setThisObject(thisObject); + resolvedCall.setReceiverParameter(receiverParameter); + result.add(resolvedCall); + } + return result; + } + + private Collection> convertWithImpliedThis(ReceiverDescriptor receiverParameter, Collection descriptors) { + Collection> result = Lists.newArrayList(); + for (D extension : descriptors) { + ResolvedCall resolvedCall = ResolvedCall.create(extension); + resolvedCall.setReceiverParameter(receiverParameter); + setImpliedThis(resolvedCall); + result.add(resolvedCall); + } + return result; + } + + private void setImpliedThis(ResolvedCall resolvedCall) { + ReceiverDescriptor thisObject; + DeclarationDescriptor containingDeclaration = resolvedCall.getCandidateDescriptor().getContainingDeclaration(); + if (containingDeclaration instanceof ClassDescriptor) { + ClassDescriptor classDescriptor = (ClassDescriptor) containingDeclaration; + thisObject = classDescriptor.getImplicitReceiver(); + } + else { + thisObject = NO_RECEIVER; + } + resolvedCall.setThisObject(thisObject); + } + + private void addTask(@NotNull List> result, @NotNull Call call, @NotNull Collection> candidates, @NotNull DataFlowInfo dataFlowInfo) { + if (candidates.isEmpty()) return; + result.add(new ResolutionTask(candidates, call, dataFlowInfo)); } @NotNull protected abstract Collection getNonExtensionsByName(JetScope scope, String name); @NotNull - protected abstract Collection getMembersByName(@NotNull ReceiverDescriptor receiver, String name); + protected abstract Collection getMembersByName(@NotNull JetType receiver, String name); @NotNull protected abstract Collection getExtensionsByName(JetScope scope, String name); - - @NotNull - protected abstract ResolutionTask createTask(ReceiverDescriptor receiver, Call call, Collection> candidates); - } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/TaskPrioritizers.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/TaskPrioritizers.java index fce2259c2a2..943493fa76c 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/TaskPrioritizers.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/TaskPrioritizers.java @@ -3,9 +3,7 @@ package org.jetbrains.jet.lang.resolve.calls; import com.google.common.collect.Sets; import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.lang.descriptors.*; -import org.jetbrains.jet.lang.psi.Call; import org.jetbrains.jet.lang.resolve.scopes.JetScope; -import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor; import org.jetbrains.jet.lang.types.ErrorUtils; import org.jetbrains.jet.lang.types.JetStandardClasses; import org.jetbrains.jet.lang.types.JetType; @@ -41,8 +39,8 @@ public class TaskPrioritizers { @NotNull @Override - protected Collection getMembersByName(@NotNull ReceiverDescriptor receiver, String name) { - JetScope receiverScope = receiver.getType().getMemberScope(); + protected Collection getMembersByName(@NotNull JetType receiverType, String name) { + JetScope receiverScope = receiverType.getMemberScope(); Set members = Sets.newHashSet(receiverScope.getFunctions(name)); addConstructors(receiverScope, name, members); addVariableAsFunction(receiverScope, name, members, false); @@ -63,12 +61,6 @@ public class TaskPrioritizers { return extensionFunctions; } - @NotNull - @Override - protected ResolutionTask createTask(@NotNull ReceiverDescriptor receiver, Call call, Collection> candidates) { - return new ResolutionTask(candidates, receiver, call); - } - private void addConstructors(JetScope scope, String name, Collection functions) { ClassifierDescriptor classifier = scope.getClassifier(name); if (classifier instanceof ClassDescriptor && !ErrorUtils.isError(classifier.getTypeConstructor())) { @@ -105,8 +97,8 @@ public class TaskPrioritizers { @NotNull @Override - protected Collection getMembersByName(@NotNull ReceiverDescriptor receiver, String name) { - VariableDescriptor variable = receiver.getType().getMemberScope().getVariable(name); + protected Collection getMembersByName(@NotNull JetType receiverType, String name) { + VariableDescriptor variable = receiverType.getMemberScope().getVariable(name); if (variable != null) { return Collections.singleton(variable); } @@ -122,11 +114,5 @@ public class TaskPrioritizers { } return Collections.emptyList(); } - - @NotNull - @Override - protected ResolutionTask createTask(@NotNull ReceiverDescriptor receiver, Call call, Collection> candidates) { - return new ResolutionTask(candidates, receiver, call); - } }; } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/TracingStrategy.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/TracingStrategy.java index 028df0226b6..2a8e81158c1 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/TracingStrategy.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/TracingStrategy.java @@ -15,7 +15,7 @@ import java.util.Set; /*package*/ interface TracingStrategy { TracingStrategy EMPTY = new TracingStrategy() { @Override - public void bindReference(@NotNull BindingTrace trace, @NotNull ReceiverDescriptor receiver, @NotNull CallableDescriptor descriptor) {} + public void bindReference(@NotNull BindingTrace trace, @NotNull ResolvedCall resolvedCall) {} @Override public void unresolvedReference(@NotNull BindingTrace trace) {} @@ -48,7 +48,7 @@ import java.util.Set; public void typeInferenceFailed(@NotNull BindingTrace trace) {} }; - void bindReference(@NotNull BindingTrace trace, @NotNull ReceiverDescriptor receiver, @NotNull CallableDescriptor descriptor); + void bindReference(@NotNull BindingTrace trace, @NotNull ResolvedCall resolvedCall); void unresolvedReference(@NotNull BindingTrace trace); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/VarargValueArgument.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/VarargValueArgument.java new file mode 100644 index 00000000000..483400bba7a --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/VarargValueArgument.java @@ -0,0 +1,19 @@ +package org.jetbrains.jet.lang.resolve.calls; + +import com.google.common.collect.Lists; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.lang.psi.JetExpression; + +import java.util.List; + +/** +* @author abreslav +*/ +public class VarargValueArgument implements ResolvedValueArgument { + private final List values = Lists.newArrayList(); + + @NotNull + public List getValues() { + return values; + } +}