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:
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user