inference using new constraint system

final type parameters inference and substitution are made after expected type is known (should be redone with caches for performance)
This commit is contained in:
Svetlana Isakova
2012-07-03 12:43:01 +04:00
parent 83ec7d9c68
commit f270f9e90a
@@ -20,7 +20,6 @@ import com.google.common.base.Predicate;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
import com.google.common.collect.Sets; import com.google.common.collect.Sets;
import com.intellij.openapi.util.Pair;
import com.intellij.psi.PsiElement; import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
@@ -30,10 +29,7 @@ import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.*; import org.jetbrains.jet.lang.resolve.*;
import org.jetbrains.jet.lang.resolve.calls.autocasts.AutoCastServiceImpl; import org.jetbrains.jet.lang.resolve.calls.autocasts.AutoCastServiceImpl;
import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo; import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo;
import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintSystem; import org.jetbrains.jet.lang.resolve.calls.inference.*;
import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintSystemSolution;
import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintSystemWithPriorities;
import org.jetbrains.jet.lang.resolve.calls.inference.DebugConstraintResolutionListener;
import org.jetbrains.jet.lang.resolve.name.Name; import org.jetbrains.jet.lang.resolve.name.Name;
import org.jetbrains.jet.lang.resolve.scopes.JetScope; import org.jetbrains.jet.lang.resolve.scopes.JetScope;
import org.jetbrains.jet.lang.resolve.scopes.receivers.ExpressionReceiver; import org.jetbrains.jet.lang.resolve.scopes.receivers.ExpressionReceiver;
@@ -53,7 +49,6 @@ import static org.jetbrains.jet.lang.resolve.BindingContext.*;
import static org.jetbrains.jet.lang.resolve.calls.ResolutionStatus.*; import static org.jetbrains.jet.lang.resolve.calls.ResolutionStatus.*;
import static org.jetbrains.jet.lang.resolve.calls.ResolvedCallImpl.MAP_TO_CANDIDATE; import static org.jetbrains.jet.lang.resolve.calls.ResolvedCallImpl.MAP_TO_CANDIDATE;
import static org.jetbrains.jet.lang.resolve.calls.ResolvedCallImpl.MAP_TO_RESULT; import static org.jetbrains.jet.lang.resolve.calls.ResolvedCallImpl.MAP_TO_RESULT;
import static org.jetbrains.jet.lang.resolve.calls.inference.ConstraintType.*;
import static org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor.NO_RECEIVER; import static org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor.NO_RECEIVER;
import static org.jetbrains.jet.lang.types.TypeUtils.NO_EXPECTED_TYPE; import static org.jetbrains.jet.lang.types.TypeUtils.NO_EXPECTED_TYPE;
@@ -61,8 +56,6 @@ import static org.jetbrains.jet.lang.types.TypeUtils.NO_EXPECTED_TYPE;
* @author abreslav * @author abreslav
*/ */
public class CallResolver { public class CallResolver {
private static final JetType DONT_CARE = ErrorUtils.createErrorTypeWithCustomDebugName("DONT_CARE");
private final JetTypeChecker typeChecker = JetTypeChecker.INSTANCE; private final JetTypeChecker typeChecker = JetTypeChecker.INSTANCE;
@NotNull @NotNull
@@ -274,14 +267,153 @@ public class CallResolver {
} }
} }
TemporaryBindingTrace delegatingBindingTrace = TemporaryBindingTrace.create(context.trace); TemporaryBindingTrace delegatingBindingTrace = TemporaryBindingTrace.create(context.trace);
OverloadResolutionResults<F> results = doResolveCall(context.replaceTrace(delegatingBindingTrace), BasicResolutionContext newContext = context.replaceTrace(delegatingBindingTrace);
OverloadResolutionResults<F> results = doResolveCall(newContext,
prioritizedTasks, prioritizedTasks,
callTransformer, reference); callTransformer, reference);
DelegatingBindingTrace cloneDelta = new DelegatingBindingTrace(new BindingTraceContext().getBindingContext()); DelegatingBindingTrace cloneDelta = new DelegatingBindingTrace(new BindingTraceContext().getBindingContext());
delegatingBindingTrace.addAllMyDataTo(cloneDelta); delegatingBindingTrace.addAllMyDataTo(cloneDelta);
cacheResults(resolutionResultsSlice, context, results, cloneDelta); cacheResults(resolutionResultsSlice, context, results, cloneDelta);
TemporaryBindingTrace temporaryBindingTrace = null;
if (results instanceof OverloadResolutionResultsImpl) {
temporaryBindingTrace = ((OverloadResolutionResultsImpl) results).getTrace();
if (temporaryBindingTrace != null) {
newContext = newContext.replaceTrace(temporaryBindingTrace);
}
}
OverloadResolutionResults<F> completeResults = completeTypeInferenceDependentOnExpectedType(newContext, results,
!prioritizedTasks.isEmpty() ? prioritizedTasks.iterator().next().tracing : null);
if (temporaryBindingTrace != null) {
temporaryBindingTrace.commit();
}
delegatingBindingTrace.commit(); delegatingBindingTrace.commit();
return results; return completeResults;
}
private <D extends CallableDescriptor> OverloadResolutionResults<D> completeTypeInferenceDependentOnExpectedType(
BasicResolutionContext context,
OverloadResolutionResults<D> results,
@Nullable TracingStrategy tracing) {
if (results.getResultCode() != OverloadResolutionResults.Code.DIRTY) return results;
Set<ResolvedCallWithTrace<D>> successful = Sets.newLinkedHashSet();
Set<ResolvedCallWithTrace<D>> failed = Sets.newLinkedHashSet();
for (ResolvedCall<? extends D> resolvedCall : results.getResultingCalls()) {
if (!(resolvedCall instanceof ResolvedCallImpl)) continue;
ResolvedCallImpl<D> call = (ResolvedCallImpl<D>) resolvedCall;
if (!call.hasUnknownTypeParameters()) {
if (call.getStatus().isSuccess()) {
successful.add(call);
}
else {
failed.add(call);
}
continue;
}
ConstraintSystem constraintSystem = new ConstraintSystemImpl();
D descriptor = call.getCandidateDescriptor();
Map<TypeParameterDescriptor, TypeBounds> typeArgumentBounds = call.getTypeArgumentBounds();
for (TypeParameterDescriptor typeParameterDescriptor : descriptor.getTypeParameters()) {
if (typeArgumentBounds.containsKey(typeParameterDescriptor)) {
constraintSystem.registerTypeVariable(typeParameterDescriptor, typeArgumentBounds.get(typeParameterDescriptor));
}
else {
constraintSystem.registerTypeVariable(typeParameterDescriptor, Variance.INVARIANT);
}
}
constraintSystem.addConstraint(ConstraintSystemImpl.ConstraintType.SUPER_TYPE, context.expectedType, descriptor.getReturnType());
// constraints for function literals
// Value parameters
for (Map.Entry<ValueParameterDescriptor, ResolvedValueArgument> entry : call.getValueArguments().entrySet()) {
ResolvedValueArgument resolvedValueArgument = entry.getValue();
ValueParameterDescriptor valueParameterDescriptor = entry.getKey();
for (ValueArgument valueArgument : resolvedValueArgument.getArguments()) {
if (!JetPsiUtil.isFunctionLiteralWithoutDeclaredParameterTypes(valueArgument.getArgumentExpression())) continue;
// TODO : more attempts, with different expected types
JetType effectiveExpectedType = getEffectiveExpectedType(valueParameterDescriptor, valueArgument);
// Here we type check expecting an error type (that is a subtype of any type and a supertype of any type
// and throw the results away
// We'll type check the arguments later, with the inferred types expected
TemporaryBindingTrace traceForUnknown = TemporaryBindingTrace.create(context.trace);
JetExpression argumentExpression = valueArgument.getArgumentExpression();
JetType type = argumentExpression != null ? expressionTypingServices.getType(context.scope, argumentExpression,
constraintSystem.getSubstitutor().substitute(valueParameterDescriptor.getType(), Variance.INVARIANT),
context.dataFlowInfo, traceForUnknown) : null;
if (type != null && !ErrorUtils.isErrorType(type)) {
constraintSystem.addSubtypingConstraint(type, effectiveExpectedType);
}
}
}
if (constraintSystem.isSuccessful()) {
D substitute = (D) descriptor.substitute(constraintSystem.getSubstitutor());
assert substitute != null;
replaceValueParametersWithSubstitutedOnes(call, substitute);
call.setResultingDescriptor(substitute); //replacement
// Here we type check the arguments with inferred types expected
checkValueArgumentTypes(context, call, context.trace);
checkBounds(call, constraintSystem, context);
call.setHasUnknownTypeParameters(false);
if (call.getStatus().isSuccess() || call.getStatus() == ResolutionStatus.UNKNOWN_STATUS) {
call.addStatus(ResolutionStatus.SUCCESS);
successful.add(call);
}
else {
failed.add(call);
}
}
else {
context.trace.report(TYPE_INFERENCE_FAILED.on(context.call.getCallElement(), new SolutionStatus() {
@Override
public boolean isSuccessful() {
return false;
}
@Override
public String toString() {
return "Type inference failed";
}
}));
call.addStatus(ResolutionStatus.TYPE_INFERENCE_ERROR);
checkValueArgumentTypes(context, call, context.trace);
failed.add(call);
}
}
if (results.getResultingCalls().size() > 1) {
for (ResolvedCallWithTrace<D> call : successful) {
if (call instanceof ResolvedCallImpl) {
((ResolvedCallImpl)call).addStatus(ResolutionStatus.OTHER_ERROR);
failed.add(call);
}
}
successful.clear();
}
return computeResultAndReportErrors(context.trace, tracing, successful, failed);
}
private <D extends CallableDescriptor> void checkBounds(ResolvedCallImpl<D> call, ConstraintSystem constraintSystem, BasicResolutionContext context) {
for (TypeParameterDescriptor typeParameter : call.getCandidateDescriptor().getTypeParameters()) {
JetType type = constraintSystem.getValue(typeParameter);
JetType upperBound = typeParameter.getUpperBoundsAsType();
JetType substitute = constraintSystem.getSubstitutor().substitute(upperBound, Variance.INVARIANT);
if (type != null) {
if (substitute == null || !JetTypeChecker.INSTANCE.isSubtypeOf(type, substitute)) {
context.trace.report(Errors.TYPE_INFERENCE_UPPER_BOUND_VIOLATED.on(context.call.getCallElement(), type, substitute != null ? substitute : upperBound));
}
}
}
} }
private <F extends CallableDescriptor> void cacheResults(@NotNull WritableSlice<CallKey, OverloadResolutionResults<F>> resolutionResultsSlice, private <F extends CallableDescriptor> void cacheResults(@NotNull WritableSlice<CallKey, OverloadResolutionResults<F>> resolutionResultsSlice,
@@ -338,6 +470,10 @@ public class CallResolver {
return results; return results;
} }
if (results.getResultCode() == OverloadResolutionResults.Code.DIRTY) {
results.setTrace(taskTrace);
return results;
}
if (traceForFirstNonemptyCandidateSet == null && !task.getCandidates().isEmpty() && !results.isNothing()) { if (traceForFirstNonemptyCandidateSet == null && !task.getCandidates().isEmpty() && !results.isNothing()) {
traceForFirstNonemptyCandidateSet = taskTrace; traceForFirstNonemptyCandidateSet = taskTrace;
resultsForFirstNonemptyCandidateSet = results; resultsForFirstNonemptyCandidateSet = results;
@@ -454,8 +590,9 @@ public class CallResolver {
} }
} }
OverloadResolutionResultsImpl<F> results = computeResultAndReportErrors(task.trace, task.tracing, successfulCandidates, failedCandidates); OverloadResolutionResultsImpl<F> results = computeResultAndReportErrors(task.trace, task.tracing, successfulCandidates,
if (!results.isSingleResult()) { failedCandidates);
if (!results.isSingleResult() && results.getResultCode() != OverloadResolutionResults.Code.DIRTY) {
checkTypesWithNoCallee(task.toBasic()); checkTypesWithNoCallee(task.toBasic());
} }
return results; return results;
@@ -490,7 +627,8 @@ public class CallResolver {
else { else {
candidateCall.addStatus(OTHER_ERROR); candidateCall.addStatus(OTHER_ERROR);
} }
if (argumentMappingStatus != ValueArgumentsToParametersMapper.Status.WEAK_ERROR) { if ((argumentMappingStatus == ValueArgumentsToParametersMapper.Status.ERROR && candidate.getTypeParameters().isEmpty()) ||
argumentMappingStatus == ValueArgumentsToParametersMapper.Status.STRONG_ERROR) {
checkTypesWithNoCallee(context.toBasic()); checkTypesWithNoCallee(context.toBasic());
return; return;
} }
@@ -500,7 +638,8 @@ public class CallResolver {
List<JetTypeProjection> jetTypeArguments = context.call.getTypeArguments(); List<JetTypeProjection> jetTypeArguments = context.call.getTypeArguments();
if (jetTypeArguments.isEmpty()) { if (jetTypeArguments.isEmpty()) {
if (!candidate.getTypeParameters().isEmpty()) { if (!candidate.getTypeParameters().isEmpty()) {
candidateCall.addStatus(inferTypeArguments(context)); ResolutionStatus status = inferTypeArguments(context);
candidateCall.addStatus(status);
} }
else { else {
candidateCall.addStatus(checkAllValueArguments(context)); candidateCall.addStatus(checkAllValueArguments(context));
@@ -567,7 +706,7 @@ public class CallResolver {
ResolutionDebugInfo.Data debugInfo = context.trace.get(ResolutionDebugInfo.RESOLUTION_DEBUG_INFO, context.call.getCallElement()); ResolutionDebugInfo.Data debugInfo = context.trace.get(ResolutionDebugInfo.RESOLUTION_DEBUG_INFO, context.call.getCallElement());
ConstraintSystem constraintSystem = new ConstraintSystemWithPriorities(new DebugConstraintResolutionListener(candidateCall, debugInfo)); ConstraintSystem constraintSystem = new ConstraintSystemImpl();
// If the call is recursive, e.g. // If the call is recursive, e.g.
// fun foo<T>(t : T) : T = foo(t) // fun foo<T>(t : T) : T = foo(t)
@@ -583,7 +722,7 @@ public class CallResolver {
} }
TypeSubstitutor substituteDontCare = ConstraintSystemWithPriorities TypeSubstitutor substituteDontCare = ConstraintSystemWithPriorities
.makeConstantSubstitutor(candidateWithFreshVariables.getTypeParameters(), DONT_CARE); .makeConstantSubstitutor(candidateWithFreshVariables.getTypeParameters(), ConstraintSystem.DONT_CARE);
// Value parameters // Value parameters
for (Map.Entry<ValueParameterDescriptor, ResolvedValueArgument> entry : candidateCall.getValueArguments().entrySet()) { for (Map.Entry<ValueParameterDescriptor, ResolvedValueArgument> entry : candidateCall.getValueArguments().entrySet()) {
@@ -592,6 +731,7 @@ public class CallResolver {
for (ValueArgument valueArgument : resolvedValueArgument.getArguments()) { for (ValueArgument valueArgument : resolvedValueArgument.getArguments()) {
if (JetPsiUtil.isFunctionLiteralWithoutDeclaredParameterTypes(valueArgument.getArgumentExpression())) continue;
// TODO : more attempts, with different expected types // TODO : more attempts, with different expected types
JetType effectiveExpectedType = getEffectiveExpectedType(valueParameterDescriptor, valueArgument); JetType effectiveExpectedType = getEffectiveExpectedType(valueParameterDescriptor, valueArgument);
@@ -605,7 +745,7 @@ public class CallResolver {
context.scope, argumentExpression, substituteDontCare.substitute(valueParameterDescriptor.getType(), Variance.INVARIANT), context.scope, argumentExpression, substituteDontCare.substitute(valueParameterDescriptor.getType(), Variance.INVARIANT),
context.dataFlowInfo, traceForUnknown) : null; context.dataFlowInfo, traceForUnknown) : null;
if (type != null && !ErrorUtils.isErrorType(type)) { if (type != null && !ErrorUtils.isErrorType(type)) {
constraintSystem.addSubtypingConstraint(VALUE_ARGUMENT.assertSubtyping(type, effectiveExpectedType)); constraintSystem.addSubtypingConstraint(type, effectiveExpectedType);
} }
else { else {
candidateCall.argumentHasNoType(); candidateCall.argumentHasNoType();
@@ -618,34 +758,32 @@ public class CallResolver {
ReceiverDescriptor receiverArgument = candidateCall.getReceiverArgument(); ReceiverDescriptor receiverArgument = candidateCall.getReceiverArgument();
ReceiverDescriptor receiverParameter = candidateWithFreshVariables.getReceiverParameter(); ReceiverDescriptor receiverParameter = candidateWithFreshVariables.getReceiverParameter();
if (receiverArgument.exists() && receiverParameter.exists()) { if (receiverArgument.exists() && receiverParameter.exists()) {
constraintSystem.addSubtypingConstraint(RECEIVER.assertSubtyping(receiverArgument.getType(), receiverParameter.getType())); constraintSystem.addSubtypingConstraint(receiverArgument.getType(), receiverParameter.getType());
} }
// Return type for (TypeParameterDescriptor typeParameterDescriptor : candidate.getTypeParameters()) {
if (context.expectedType != NO_EXPECTED_TYPE) { candidateCall.recordTypeBounds(typeParameterDescriptor, constraintSystem.getTypeBounds(
constraintSystem.addSubtypingConstraint(EXPECTED_TYPE.assertSubtyping(candidateWithFreshVariables.getReturnType(), context.expectedType)); candidateWithFreshVariables.getTypeParameters().get(typeParameterDescriptor.getIndex())));
} }
// Solution // Solution
ConstraintSystemSolution solution = constraintSystem.solve(); if (!constraintSystem.hasContradiction()) {
if (solution.getStatus().isSuccessful()) { candidateCall.setHasUnknownTypeParameters(true);
D substitute = (D) candidateWithFreshVariables.substitute(solution.getSubstitutor());
assert substitute != null;
replaceValueParametersWithSubstitutedOnes(candidateCall, substitute);
candidateCall.setResultingDescriptor(substitute);
for (TypeParameterDescriptor typeParameterDescriptor : candidateCall.getCandidateDescriptor().getTypeParameters()) {
candidateCall.recordTypeArgument(typeParameterDescriptor, solution.getValue(candidateWithFreshVariables.getTypeParameters().get(typeParameterDescriptor.getIndex())));
}
// Here we type check the arguments with inferred types expected
checkValueArgumentTypes(context);
return SUCCESS; return SUCCESS;
} }
else { else {
context.tracing.typeInferenceFailed(context.trace, solution.getStatus()); context.tracing.typeInferenceFailed(context.trace, new SolutionStatus() {
return OTHER_ERROR.combine(checkAllValueArguments(context)); @Override
public boolean isSuccessful() {
return false;
}
@Override
public String toString() {
return "Type inference failed";
}
});
return TYPE_INFERENCE_ERROR.combine(checkAllValueArguments(context));
} }
} }
@@ -719,7 +857,7 @@ public class CallResolver {
} }
private <D extends CallableDescriptor, F extends D> ResolutionStatus checkAllValueArguments(CallResolutionContext<D, F> context) { private <D extends CallableDescriptor, F extends D> ResolutionStatus checkAllValueArguments(CallResolutionContext<D, F> context) {
ResolutionStatus result = checkValueArgumentTypes(context); ResolutionStatus result = checkValueArgumentTypes(context, context.candidateCall);
ResolvedCall<D> candidateCall = context.candidateCall; ResolvedCall<D> candidateCall = context.candidateCall;
// Comment about a very special case. // Comment about a very special case.
@@ -767,10 +905,14 @@ public class CallResolver {
return result; return result;
} }
private <D extends CallableDescriptor, F extends D> ResolutionStatus checkValueArgumentTypes(CallResolutionContext<D, F> context) { private <D extends CallableDescriptor> ResolutionStatus checkValueArgumentTypes(ResolutionContext context, ResolvedCallImpl<D> candidateCall) {
return checkValueArgumentTypes(context, candidateCall, candidateCall.getTrace());
}
private <D extends CallableDescriptor> ResolutionStatus checkValueArgumentTypes(ResolutionContext context, ResolvedCallImpl<D> candidateCall, BindingTrace trace) {
ResolutionStatus result = SUCCESS; ResolutionStatus result = SUCCESS;
DataFlowInfo dataFlowInfo = context.dataFlowInfo; DataFlowInfo dataFlowInfo = context.dataFlowInfo;
for (Map.Entry<ValueParameterDescriptor, ResolvedValueArgument> entry : context.candidateCall.getValueArguments().entrySet()) { for (Map.Entry<ValueParameterDescriptor, ResolvedValueArgument> entry : candidateCall.getValueArguments().entrySet()) {
ValueParameterDescriptor parameterDescriptor = entry.getKey(); ValueParameterDescriptor parameterDescriptor = entry.getKey();
ResolvedValueArgument resolvedArgument = entry.getValue(); ResolvedValueArgument resolvedArgument = entry.getValue();
@@ -780,11 +922,12 @@ public class CallResolver {
if (expression == null) continue; if (expression == null) continue;
JetType expectedType = getEffectiveExpectedType(parameterDescriptor, argument); JetType expectedType = getEffectiveExpectedType(parameterDescriptor, argument);
JetTypeInfo typeInfo = expressionTypingServices.getTypeInfo(context.scope, expression, expectedType, dataFlowInfo, context.candidateCall.getTrace()); JetTypeInfo typeInfo = expressionTypingServices.getTypeInfo(context.scope, expression, expectedType, dataFlowInfo,
trace);
JetType type = typeInfo.getType(); JetType type = typeInfo.getType();
dataFlowInfo = dataFlowInfo.and(typeInfo.getDataFlowInfo()); dataFlowInfo = dataFlowInfo.and(typeInfo.getDataFlowInfo());
if (type == null || ErrorUtils.isErrorType(type)) { if (type == null || ErrorUtils.isErrorType(type)) {
context.candidateCall.argumentHasNoType(); candidateCall.argumentHasNoType();
} }
else if (!typeChecker.isSubtypeOf(type, expectedType)) { else if (!typeChecker.isSubtypeOf(type, expectedType)) {
// VariableDescriptor variableDescriptor = AutoCastUtils.getVariableDescriptorFromSimpleName(temporaryTrace.getBindingContext(), argument); // VariableDescriptor variableDescriptor = AutoCastUtils.getVariableDescriptorFromSimpleName(temporaryTrace.getBindingContext(), argument);
@@ -819,7 +962,7 @@ public class CallResolver {
if (argument.getSpreadElement() != null) { if (argument.getSpreadElement() != null) {
if (parameterDescriptor.getVarargElementType() == null) { if (parameterDescriptor.getVarargElementType() == null) {
// Spread argument passed to a non-vararg parameter, an error is already reported by ValueArgumentsToParametersMapper // Spread argument passed to a non-vararg parameter, an error is already reported by ValueArgumentsToParametersMapper
return ErrorUtils.createErrorType("Don't care"); return ConstraintSystem.DONT_CARE;
} }
else { else {
return parameterDescriptor.getType(); return parameterDescriptor.getType();
@@ -898,6 +1041,9 @@ public class CallResolver {
ResolvedCallWithTrace<D> failed = failedCandidates.iterator().next(); ResolvedCallWithTrace<D> failed = failedCandidates.iterator().next();
failed.getTrace().commit(); failed.getTrace().commit();
if (failed.getStatus() != ResolutionStatus.STRONG_ERROR && failed.hasUnknownTypeParameters()) {
return OverloadResolutionResultsImpl.dirty(failed);
}
return OverloadResolutionResultsImpl.singleFailedCandidate(failed); return OverloadResolutionResultsImpl.singleFailedCandidate(failed);
} }
else { else {
@@ -915,9 +1061,13 @@ public class CallResolver {
private <D extends CallableDescriptor> OverloadResolutionResultsImpl<D> chooseAndReportMaximallySpecific(Set<ResolvedCallWithTrace<D>> candidates, boolean discriminateGenerics) { private <D extends CallableDescriptor> OverloadResolutionResultsImpl<D> chooseAndReportMaximallySpecific(Set<ResolvedCallWithTrace<D>> candidates, boolean discriminateGenerics) {
if (candidates.size() != 1) { if (candidates.size() != 1) {
boolean dirty = false;
Set<ResolvedCallWithTrace<D>> cleanCandidates = Sets.newLinkedHashSet(candidates); Set<ResolvedCallWithTrace<D>> cleanCandidates = Sets.newLinkedHashSet(candidates);
for (Iterator<ResolvedCallWithTrace<D>> iterator = cleanCandidates.iterator(); iterator.hasNext(); ) { for (Iterator<ResolvedCallWithTrace<D>> iterator = cleanCandidates.iterator(); iterator.hasNext(); ) {
ResolvedCallWithTrace<D> candidate = iterator.next(); ResolvedCallWithTrace<D> candidate = iterator.next();
if (candidate.hasUnknownTypeParameters()) {
dirty = true;
}
if (candidate.isDirty()) { if (candidate.isDirty()) {
iterator.remove(); iterator.remove();
} }
@@ -940,6 +1090,10 @@ public class CallResolver {
Set<ResolvedCallWithTrace<D>> noOverrides = OverridingUtil.filterOverrides(candidates, MAP_TO_RESULT); Set<ResolvedCallWithTrace<D>> noOverrides = OverridingUtil.filterOverrides(candidates, MAP_TO_RESULT);
if (dirty) {
return OverloadResolutionResultsImpl.dirty(candidates);
}
return OverloadResolutionResultsImpl.ambiguity(noOverrides); return OverloadResolutionResultsImpl.ambiguity(noOverrides);
} }
else { else {
@@ -947,6 +1101,9 @@ public class CallResolver {
TemporaryBindingTrace temporaryTrace = result.getTrace(); TemporaryBindingTrace temporaryTrace = result.getTrace();
temporaryTrace.commit(); temporaryTrace.commit();
if (result.hasUnknownTypeParameters()) {
return OverloadResolutionResultsImpl.dirty(result);
}
return OverloadResolutionResultsImpl.success(result); return OverloadResolutionResultsImpl.success(result);
} }