Change logic of constructor delegation call resolution

- If class has type arguments (A<T1,..>) then
  resolve it's delegation call to `this` as for expression A<T1, ..>()
  like type arguments are explicitly specified.

- Same logic works for `super` delegation calls.

- It could be just enough to substitute all candidates before resolve
  but diagnostic messages looks more correct when substitution is
  performed within CandidateResolver.performResolutionForCandidateCall
  because it works the same way as when resolving A<T1, ..>().

 #KT-6992 Fixed
 #KT-6993 Fixed
 #KT-6994 Fixed
This commit is contained in:
Denis Zharkov
2015-03-15 21:40:01 +03:00
parent e37cf6b6a1
commit 36665fe3b8
31 changed files with 392 additions and 20 deletions
@@ -44,6 +44,7 @@ import org.jetbrains.kotlin.resolve.scopes.JetScope;
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver;
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue;
import org.jetbrains.kotlin.types.JetType;
import org.jetbrains.kotlin.types.TypeSubstitutor;
import org.jetbrains.kotlin.types.expressions.ExpressionTypingContext;
import org.jetbrains.kotlin.types.expressions.ExpressionTypingServices;
@@ -296,12 +297,10 @@ public class CallResolver {
// when super call should be conventional enum constructor and super call should be empty
if (call == null) return null;
JetType superClassType = DescriptorUtils.getSuperClassType(constructorDescriptor.getContainingDeclaration());
BasicCallResolutionContext context = BasicCallResolutionContext.create(
trace, scope,
CallMaker.makeCall(ReceiverValue.NO_RECEIVER, null, call),
superClassType != null ? superClassType : NO_EXPECTED_TYPE,
NO_EXPECTED_TYPE,
dataFlowInfo, ContextDependency.INDEPENDENT, CheckValueArgumentsMode.ENABLED,
expressionTypingServices.getCallChecker(), expressionTypingServices.getAdditionalTypeChecker(), false);
@@ -353,11 +352,16 @@ public class CallResolver {
((ClassDescriptor) delegateClassDescriptor.getContainingDeclaration()).
getThisAsReceiverParameter().getValue();
JetType expectedType = isThisCall ?
calleeConstructor.getContainingDeclaration().getDefaultType() :
DescriptorUtils.getSuperClassType(currentClassDescriptor);
TypeSubstitutor knownTypeParametersSubstitutor = TypeSubstitutor.create(expectedType);
for (CallableDescriptor descriptor : constructors) {
candidates.add(ResolutionCandidate.create(
context.call, descriptor, constructorDispatchReceiver, ReceiverValue.NO_RECEIVER,
ExplicitReceiverKind.NO_EXPLICIT_RECEIVER
));
ExplicitReceiverKind.NO_EXPLICIT_RECEIVER,
knownTypeParametersSubstitutor));
}
return computeTasksFromCandidatesAndResolvedCall(context, calleeExpression, candidates, CallTransformer.FUNCTION_CALL_TRANSFORMER);
@@ -114,8 +114,8 @@ public class CallTransformer<D extends CallableDescriptor, F extends D> {
candidate.getDescriptor(),
candidate.getDispatchReceiver(),
candidate.getExtensionReceiver(),
candidate.getExplicitReceiverKind()
);
candidate.getExplicitReceiverKind(),
null);
if (!hasReceiver) {
CallCandidateResolutionContext<CallableDescriptor> context = CallCandidateResolutionContext.create(
ResolvedCallImpl.create(variableCandidate, candidateTrace, task.tracing, task.dataFlowInfoForArguments),
@@ -131,7 +131,7 @@ public class CallTransformer<D extends CallableDescriptor, F extends D> {
candidate.getDescriptor(),
candidate.getDispatchReceiver(),
ReceiverValue.NO_RECEIVER,
ExplicitReceiverKind.NO_EXPLICIT_RECEIVER);
ExplicitReceiverKind.NO_EXPLICIT_RECEIVER, null);
CallCandidateResolutionContext<CallableDescriptor> contextWithoutReceiver = createContextWithChainedTrace(
candidateWithoutReceiver, variableCallWithoutReceiver, candidateTrace, task, variableCall.getExplicitReceiver());
@@ -153,8 +153,13 @@ public class CandidateResolver {
candidateCall.setResultingSubstitutor(substitutor);
}
else if (candidateCall.getKnownTypeParametersSubstitutor() != null) {
candidateCall.setResultingSubstitutor(candidateCall.getKnownTypeParametersSubstitutor());
}
if (jetTypeArguments.isEmpty() && !candidate.getTypeParameters().isEmpty()) {
if (jetTypeArguments.isEmpty() &&
!candidate.getTypeParameters().isEmpty() &&
candidateCall.getKnownTypeParametersSubstitutor() == null) {
candidateCall.addStatus(inferTypeArguments(context));
}
else {
@@ -56,6 +56,9 @@ public interface MutableResolvedCall<D extends CallableDescriptor> extends Resol
void setResultingSubstitutor(@NotNull TypeSubstitutor substitutor);
@Nullable
TypeSubstitutor getKnownTypeParametersSubstitutor();
//todo remove: use value to parameter map status
boolean hasInferredReturnType();
}
@@ -77,6 +77,7 @@ public class ResolvedCallImpl<D extends CallableDescriptor> implements MutableRe
private final ReceiverValue dispatchReceiver; // receiver object of a method
private final ReceiverValue extensionReceiver; // receiver of an extension function
private final ExplicitReceiverKind explicitReceiverKind;
private final TypeSubstitutor knownTypeParametersSubstitutor;
private final Map<TypeParameterDescriptor, JetType> typeArguments = Maps.newLinkedHashMap();
private final Map<ValueParameterDescriptor, ResolvedValueArgument> valueArguments = Maps.newLinkedHashMap();
@@ -101,6 +102,7 @@ public class ResolvedCallImpl<D extends CallableDescriptor> implements MutableRe
this.dispatchReceiver = candidate.getDispatchReceiver();
this.extensionReceiver = candidate.getExtensionReceiver();
this.explicitReceiverKind = candidate.getExplicitReceiverKind();
this.knownTypeParametersSubstitutor = candidate.getKnownTypeParametersResultingSubstitutor();
this.trace = trace;
this.tracing = tracing;
this.dataFlowInfoForArguments = dataFlowInfoForArguments;
@@ -323,4 +325,10 @@ public class ResolvedCallImpl<D extends CallableDescriptor> implements MutableRe
private void assertNotCompleted(String elementName) {
assert !completed: elementName + " is erased after resolution completion.";
}
@Override
@Nullable
public TypeSubstitutor getKnownTypeParametersSubstitutor() {
return knownTypeParametersSubstitutor;
}
}
@@ -16,46 +16,49 @@
package org.jetbrains.kotlin.resolve.calls.tasks;
import com.google.common.collect.Lists;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.descriptors.CallableDescriptor;
import org.jetbrains.kotlin.psi.Call;
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue;
import java.util.Collection;
import java.util.List;
import org.jetbrains.kotlin.types.TypeSubstitutor;
import static org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue.NO_RECEIVER;
public class ResolutionCandidate<D extends CallableDescriptor> {
private final Call call;
private final D candidateDescriptor;
private final TypeSubstitutor knownTypeParametersResultingSubstitutor;
private ReceiverValue dispatchReceiver; // receiver object of a method
private ReceiverValue extensionReceiver; // receiver of an extension function
private ExplicitReceiverKind explicitReceiverKind;
private ResolutionCandidate(
@NotNull Call call, @NotNull D descriptor, @NotNull ReceiverValue dispatchReceiver,
@NotNull ReceiverValue extensionReceiver, @NotNull ExplicitReceiverKind explicitReceiverKind
@NotNull ReceiverValue extensionReceiver, @NotNull ExplicitReceiverKind explicitReceiverKind,
@Nullable TypeSubstitutor knownTypeParametersResultingSubstitutor
) {
this.call = call;
this.candidateDescriptor = descriptor;
this.dispatchReceiver = dispatchReceiver;
this.extensionReceiver = extensionReceiver;
this.explicitReceiverKind = explicitReceiverKind;
this.knownTypeParametersResultingSubstitutor = knownTypeParametersResultingSubstitutor;
}
public static <D extends CallableDescriptor> ResolutionCandidate<D> create(
@NotNull Call call, @NotNull D descriptor
) {
return new ResolutionCandidate<D>(call, descriptor, NO_RECEIVER, NO_RECEIVER, ExplicitReceiverKind.NO_EXPLICIT_RECEIVER);
return new ResolutionCandidate<D>(call, descriptor, NO_RECEIVER, NO_RECEIVER, ExplicitReceiverKind.NO_EXPLICIT_RECEIVER, null);
}
public static <D extends CallableDescriptor> ResolutionCandidate<D> create(
@NotNull Call call, @NotNull D descriptor, @NotNull ReceiverValue dispatchReceiver,
@NotNull ReceiverValue receiverArgument, @NotNull ExplicitReceiverKind explicitReceiverKind
@NotNull ReceiverValue receiverArgument, @NotNull ExplicitReceiverKind explicitReceiverKind,
@Nullable TypeSubstitutor knownTypeParametersResultingSubstitutor
) {
return new ResolutionCandidate<D>(call, descriptor, dispatchReceiver, receiverArgument, explicitReceiverKind);
return new ResolutionCandidate<D>(call, descriptor, dispatchReceiver, receiverArgument, explicitReceiverKind,
knownTypeParametersResultingSubstitutor);
}
public void setDispatchReceiver(@NotNull ReceiverValue dispatchReceiver) {
@@ -95,6 +98,11 @@ public class ResolutionCandidate<D extends CallableDescriptor> {
return explicitReceiverKind;
}
@Nullable
public TypeSubstitutor getKnownTypeParametersResultingSubstitutor() {
return knownTypeParametersResultingSubstitutor;
}
@Override
public String toString() {
return candidateDescriptor.toString();
@@ -424,7 +424,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
Call call = CallMaker.makeCall(expression, NO_RECEIVER, null, expression, Collections.<ValueArgument>emptyList());
ResolutionCandidate<ReceiverParameterDescriptor> resolutionCandidate =
ResolutionCandidate.create(
call, descriptor, NO_RECEIVER, NO_RECEIVER, ExplicitReceiverKind.NO_EXPLICIT_RECEIVER);
call, descriptor, NO_RECEIVER, NO_RECEIVER, ExplicitReceiverKind.NO_EXPLICIT_RECEIVER, null);
ResolvedCallImpl<ReceiverParameterDescriptor> resolvedCall =
ResolvedCallImpl.create(resolutionCandidate,