complete inference for inner calls after resolve&inference of outer call finishes
deferredComputationsForArguments stored in ResolvedCallImpl, 'completeValueArgumentsInference' completes inference for inner calls recursively
This commit is contained in:
+13
-7
@@ -157,8 +157,10 @@ public class CallExpressionResolver {
|
||||
if (!results.isNothing()) {
|
||||
checkSuper(receiver, results, context.trace, callExpression);
|
||||
result[0] = true;
|
||||
if (results.isIncomplete()) {
|
||||
return null;
|
||||
if (results.isSingleResult() && resolveMode == ResolveMode.NORMAL) {
|
||||
if (CallResolverUtil.hasReturnTypeDependentOnNotInferredParams(results.getResultingCall())) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return results.isSingleResult() ? results.getResultingCall() : null;
|
||||
}
|
||||
@@ -246,12 +248,14 @@ public class CallExpressionResolver {
|
||||
@Nullable ASTNode callOperationNode, @NotNull ResolutionContext context, @NotNull ResolveMode resolveMode
|
||||
) {
|
||||
TypeInfoForCall typeInfoForCall = getCallExpressionExtendedTypeInfoWithoutFinalTypeCheck(callExpression, receiver, callOperationNode, context, resolveMode);
|
||||
DataFlowUtils.checkType(typeInfoForCall.getType(), callExpression, context, typeInfoForCall.getDataFlowInfo());
|
||||
if (resolveMode == ResolveMode.NORMAL) {
|
||||
DataFlowUtils.checkType(typeInfoForCall.getType(), callExpression, context, typeInfoForCall.getDataFlowInfo());
|
||||
}
|
||||
return typeInfoForCall;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private TypeInfoForCall getCallExpressionExtendedTypeInfoWithoutFinalTypeCheck(
|
||||
public TypeInfoForCall getCallExpressionExtendedTypeInfoWithoutFinalTypeCheck(
|
||||
@NotNull JetCallExpression callExpression, @NotNull ReceiverValue receiver,
|
||||
@Nullable ASTNode callOperationNode, @NotNull ResolutionContext context, @NotNull ResolveMode resolveMode
|
||||
) {
|
||||
@@ -385,8 +389,10 @@ public class CallExpressionResolver {
|
||||
if (selectorReturnType != null) {
|
||||
context.trace.record(BindingContext.EXPRESSION_TYPE, selectorExpression, selectorReturnType);
|
||||
}
|
||||
return TypeInfoForCall.create(
|
||||
DataFlowUtils.checkType(selectorReturnType, expression, context, selectorReturnTypeInfo.getDataFlowInfo()),
|
||||
selectorReturnTypeInfo);
|
||||
JetTypeInfo typeInfo = JetTypeInfo.create(selectorReturnType, selectorReturnTypeInfo.getDataFlowInfo());
|
||||
if (resolveMode == ResolveMode.NORMAL) {
|
||||
DataFlowUtils.checkType(typeInfo.getType(), expression, context, typeInfo.getDataFlowInfo());
|
||||
}
|
||||
return TypeInfoForCall.create(typeInfo, selectorReturnTypeInfo);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -278,85 +278,76 @@ public class CallResolver {
|
||||
}
|
||||
if (results == null) {
|
||||
BasicCallResolutionContext newContext = context.replaceBindingTrace(traceToResolveCall);
|
||||
OverloadResolutionResults<F> resultsWithFixedResolve = doResolveCall(newContext, prioritizedTasks, callTransformer, reference);
|
||||
if (resultsWithFixedResolve instanceof OverloadResolutionResultsImpl) {
|
||||
DelegatingBindingTrace deltasTraceForTypeInference = ((OverloadResolutionResultsImpl) resultsWithFixedResolve).getTrace();
|
||||
results = doResolveCall(newContext, prioritizedTasks, callTransformer, reference);
|
||||
if (results instanceof OverloadResolutionResultsImpl) {
|
||||
DelegatingBindingTrace deltasTraceForTypeInference = ((OverloadResolutionResultsImpl) results).getTrace();
|
||||
if (deltasTraceForTypeInference != null) {
|
||||
deltasTraceForTypeInference.addAllMyDataTo(traceToResolveCall);
|
||||
}
|
||||
}
|
||||
results = completeTypeInferenceDependentOnFunctionLiterals(newContext, resultsWithFixedResolve, TracingStrategy.EMPTY);
|
||||
completeTypeInferenceDependentOnFunctionLiterals(newContext, results, TracingStrategy.EMPTY);
|
||||
cacheResults(resolutionResultsSlice, context, results, traceToResolveCall);
|
||||
}
|
||||
traceToResolveCall.commit();
|
||||
|
||||
if (prioritizedTasks.isEmpty()) {
|
||||
traceToResolveCall.commit();
|
||||
return results;
|
||||
}
|
||||
if (context.resolveMode == ResolveMode.INTERNAL) return results;
|
||||
|
||||
TracingStrategy tracing = prioritizedTasks.iterator().next().tracing;
|
||||
OverloadResolutionResults<F> completeResults = completeTypeInferenceDependentOnExpectedType(
|
||||
context.replaceBindingTrace(traceToResolveCall), results, tracing);
|
||||
traceToResolveCall.commit();
|
||||
return completeResults;
|
||||
return completeTypeInferenceDependentOnExpectedType(context, results, tracing);
|
||||
}
|
||||
|
||||
private <D extends CallableDescriptor> OverloadResolutionResults<D> completeTypeInferenceDependentOnFunctionLiterals(
|
||||
private <D extends CallableDescriptor> void completeTypeInferenceDependentOnFunctionLiterals(
|
||||
@NotNull BasicCallResolutionContext context,
|
||||
@NotNull OverloadResolutionResults<D> resultsWithIncompleteTypeInference,
|
||||
@NotNull OverloadResolutionResults<D> results,
|
||||
@NotNull TracingStrategy tracing
|
||||
) {
|
||||
if (resultsWithIncompleteTypeInference.getResultCode() != OverloadResolutionResults.Code.INCOMPLETE_TYPE_INFERENCE) {
|
||||
return resultsWithIncompleteTypeInference;
|
||||
}
|
||||
if (results.getResultCode() != OverloadResolutionResults.Code.INCOMPLETE_TYPE_INFERENCE) return;
|
||||
|
||||
Set<ResolvedCallWithTrace<D>> candidates = Sets.newLinkedHashSet(
|
||||
(Collection<? extends ResolvedCallWithTrace<D>>) resultsWithIncompleteTypeInference.getResultingCalls());
|
||||
ResolvedCallWithTrace<D> maximallySpecific = OverloadingConflictResolver.INSTANCE.findMaximallySpecific(candidates, false);
|
||||
if (maximallySpecific != null && maximallySpecific instanceof ResolvedCallImpl) {
|
||||
candidateResolver.completeTypeInferenceDependentOnFunctionLiteralsForCall(
|
||||
CallCandidateResolutionContext.createForCallBeingAnalyzed((ResolvedCallImpl<D>) maximallySpecific, context, tracing));
|
||||
for (ResolvedCallWithTrace<D> callWithUnknownTypeParameters : candidates) {
|
||||
if (callWithUnknownTypeParameters != maximallySpecific) {
|
||||
((ResolvedCallImpl<D>) callWithUnknownTypeParameters).addStatus(ResolutionStatus.OTHER_ERROR);
|
||||
}
|
||||
}
|
||||
return OverloadResolutionResultsImpl.incompleteTypeInference(Collections.singleton(maximallySpecific));
|
||||
//todo[ResolvedCallImpl] get rid of instanceof & cast
|
||||
if (!results.isSingleResult() || !(results.getResultingCall() instanceof ResolvedCallImpl)) {
|
||||
argumentTypeResolver.checkTypesWithNoCallee(context, RESOLVE_FUNCTION_ARGUMENTS);
|
||||
return;
|
||||
}
|
||||
for (ResolvedCallWithTrace<D> callWithUnknownTypeParameters : candidates) {
|
||||
ResolvedCallImpl<D> resolvedCall = (ResolvedCallImpl<D>) callWithUnknownTypeParameters;
|
||||
resolvedCall.addStatus(ResolutionStatus.INCOMPLETE_TYPE_INFERENCE);
|
||||
}
|
||||
return OverloadResolutionResultsImpl.incompleteTypeInference(candidates);
|
||||
CallCandidateResolutionContext<D> candidateContext = CallCandidateResolutionContext.createForCallBeingAnalyzed(
|
||||
(ResolvedCallImpl<D>) results.getResultingCall(), context, tracing);
|
||||
candidateResolver.completeTypeInferenceDependentOnFunctionLiteralsForCall(candidateContext);
|
||||
}
|
||||
|
||||
private <D extends CallableDescriptor> OverloadResolutionResults<D> completeTypeInferenceDependentOnExpectedType(
|
||||
@NotNull BasicCallResolutionContext context,
|
||||
@NotNull OverloadResolutionResults<D> resultsWithIncompleteTypeInference,
|
||||
@NotNull OverloadResolutionResults<D> results,
|
||||
@NotNull TracingStrategy tracing
|
||||
) {
|
||||
if (resultsWithIncompleteTypeInference.getResultCode() != OverloadResolutionResults.Code.INCOMPLETE_TYPE_INFERENCE) {
|
||||
return resultsWithIncompleteTypeInference;
|
||||
}
|
||||
|
||||
Set<ResolvedCallWithTrace<D>> resultingCalls = null;
|
||||
if (resultsWithIncompleteTypeInference.isSingleResult()) {
|
||||
ResolvedCallWithTrace<D> resolvedCall = (ResolvedCallWithTrace<D>) resultsWithIncompleteTypeInference.getResultingCall();
|
||||
if (resolvedCall.hasUnknownTypeParameters() && resolvedCall instanceof ResolvedCallImpl) {
|
||||
ResolvedCallImpl<D> copy = CallResolverUtil.copy((ResolvedCallImpl<D>) resolvedCall, context);
|
||||
candidateResolver.completeTypeInferenceDependentOnExpectedTypeForCall(
|
||||
CallCandidateResolutionContext.createForCallBeingAnalyzed(copy, context, tracing));
|
||||
resultingCalls = Collections.<ResolvedCallWithTrace<D>>singleton(copy);
|
||||
if (results.isSingleResult()) {
|
||||
ResolvedCall<D> call = results.getResultingCall();
|
||||
if (call instanceof ResolvedCallImpl) {
|
||||
argumentTypeResolver.checkUnmappedArgumentTypes(context, ((ResolvedCallImpl<D>)call).getUnmappedArguments());
|
||||
}
|
||||
}
|
||||
if (resultingCalls == null) {
|
||||
resultingCalls = (Set<ResolvedCallWithTrace<D>>) resultsWithIncompleteTypeInference.getResultingCalls();
|
||||
|
||||
if (!results.isSingleResult()) return results;
|
||||
|
||||
ResolvedCallWithTrace<D> resolvedCall = (ResolvedCallWithTrace<D>) results.getResultingCall();
|
||||
//todo[ResolvedCallImpl]
|
||||
if (!(resolvedCall instanceof ResolvedCallImpl)) return results;
|
||||
if (!resolvedCall.hasUnknownTypeParameters()) {
|
||||
CallCandidateResolutionContext<D> callCandidateResolutionContext =
|
||||
CallCandidateResolutionContext.createForCallBeingAnalyzed((ResolvedCallImpl<D>) resolvedCall, context, tracing);
|
||||
candidateResolver.completeValueArgumentsInference(callCandidateResolutionContext);
|
||||
return results;
|
||||
}
|
||||
OverloadResolutionResultsImpl<D> results = ResolutionResultsHandler.INSTANCE.computeResultAndReportErrors(
|
||||
context.trace, tracing, resultingCalls);
|
||||
if (!results.isSingleResult()) {
|
||||
argumentTypeResolver.checkTypesWithNoCallee(context, RESOLVE_FUNCTION_ARGUMENTS);
|
||||
ResolvedCallImpl<D> copy = CallResolverUtil.copy((ResolvedCallImpl<D>) resolvedCall, context);
|
||||
CallCandidateResolutionContext<D> callCandidateResolutionContext =
|
||||
CallCandidateResolutionContext.createForCallBeingAnalyzed(copy, context, tracing);
|
||||
candidateResolver.completeTypeInferenceDependentOnExpectedTypeForCall(callCandidateResolutionContext);
|
||||
|
||||
if (copy.getStatus().isSuccess()) {
|
||||
return OverloadResolutionResultsImpl.success(copy);
|
||||
}
|
||||
return results;
|
||||
return OverloadResolutionResultsImpl.incompleteTypeInference(copy);
|
||||
}
|
||||
|
||||
private <F extends CallableDescriptor> void cacheResults(@NotNull WritableSlice<CallKey, OverloadResolutionResults<F>> resolutionResultsSlice,
|
||||
@@ -407,9 +398,8 @@ public class CallResolver {
|
||||
OverloadResolutionResultsImpl<F> resultsForFirstNonemptyCandidateSet = null;
|
||||
for (ResolutionTask<D, F> task : prioritizedTasks) {
|
||||
TemporaryBindingTrace taskTrace = TemporaryBindingTrace.create(context.trace, "trace to resolve a task for", task.reference);
|
||||
OverloadResolutionResultsImpl<F> results = performResolutionGuardedForExtraFunctionLiteralArguments(task.replaceBindingTrace(
|
||||
taskTrace),
|
||||
callTransformer, context.trace);
|
||||
OverloadResolutionResultsImpl<F> results = performResolutionGuardedForExtraFunctionLiteralArguments(
|
||||
task.replaceBindingTrace(taskTrace), callTransformer, context.trace);
|
||||
if (results.isSuccess() || results.isAmbiguity()) {
|
||||
taskTrace.commit();
|
||||
|
||||
|
||||
@@ -21,18 +21,24 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.descriptors.CallableDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor;
|
||||
import org.jetbrains.jet.lang.psi.ValueArgument;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||
import org.jetbrains.jet.lang.resolve.TemporaryBindingTrace;
|
||||
import org.jetbrains.jet.lang.resolve.calls.context.CallResolutionContext;
|
||||
import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintSystem;
|
||||
import org.jetbrains.jet.lang.resolve.calls.inference.ConstraintsUtil;
|
||||
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
|
||||
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCallImpl;
|
||||
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCallWithTrace;
|
||||
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedValueArgument;
|
||||
import org.jetbrains.jet.lang.resolve.calls.tasks.ResolutionCandidate;
|
||||
import org.jetbrains.jet.lang.types.*;
|
||||
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public class CallResolverUtil {
|
||||
|
||||
@@ -74,6 +80,11 @@ public class CallResolverUtil {
|
||||
copy.recordValueArgument(entry.getKey(), entry.getValue());
|
||||
}
|
||||
copy.setInitialDataFlowInfo(call.getDataFlowInfo());
|
||||
for (ResolvedValueArgument resolvedArgument : call.getValueArguments().values()) {
|
||||
for (ValueArgument argument : resolvedArgument.getArguments()) {
|
||||
copy.addDeferredComputationForArgument(argument, call.getDeferredComputationForArgument(argument));
|
||||
}
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
|
||||
@@ -113,4 +124,26 @@ public class CallResolverUtil {
|
||||
newArguments.add(new TypeProjection(Variance.INVARIANT, DONT_CARE));
|
||||
return new JetTypeImpl(type.getAnnotations(), type.getConstructor(), type.isNullable(), newArguments, type.getMemberScope());
|
||||
}
|
||||
|
||||
public static <D extends CallableDescriptor> boolean hasReturnTypeDependentOnNotInferredParams(@NotNull ResolvedCall<D> resolvedCall) {
|
||||
//todo[ResolvedCallImpl]
|
||||
if (!(resolvedCall instanceof ResolvedCallImpl)) return false;
|
||||
ResolvedCallImpl call = (ResolvedCallImpl) resolvedCall;
|
||||
ConstraintSystem constraintSystem = call.getConstraintSystem();
|
||||
if (constraintSystem == null) return false;
|
||||
|
||||
CallableDescriptor candidateDescriptor = call.getCandidateDescriptor();
|
||||
JetType returnType = candidateDescriptor.getReturnType();
|
||||
if (returnType == null) return false;
|
||||
|
||||
for (TypeParameterDescriptor typeVariable : constraintSystem.getTypeVariables()) {
|
||||
JetType inferredValueForTypeVariable = ConstraintsUtil.getValue(constraintSystem.getTypeConstraints(typeVariable));
|
||||
if (inferredValueForTypeVariable == null) {
|
||||
if (TypeUtils.dependsOnTypeParameters(returnType, Collections.singleton(typeVariable))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ import org.jetbrains.jet.lang.resolve.*;
|
||||
import org.jetbrains.jet.lang.resolve.calls.autocasts.*;
|
||||
import org.jetbrains.jet.lang.resolve.calls.context.CallCandidateResolutionContext;
|
||||
import org.jetbrains.jet.lang.resolve.calls.context.CallResolutionContext;
|
||||
import org.jetbrains.jet.lang.resolve.calls.context.ResolveMode;
|
||||
import org.jetbrains.jet.lang.resolve.calls.context.TypeInfoForCall;
|
||||
import org.jetbrains.jet.lang.resolve.calls.inference.*;
|
||||
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
|
||||
@@ -55,6 +56,7 @@ import static org.jetbrains.jet.lang.resolve.calls.CallResolverUtil.ResolveArgum
|
||||
import static org.jetbrains.jet.lang.resolve.calls.CallResolverUtil.ResolveArgumentsMode.SKIP_FUNCTION_ARGUMENTS;
|
||||
import static org.jetbrains.jet.lang.resolve.calls.results.ResolutionStatus.*;
|
||||
import static org.jetbrains.jet.lang.types.TypeUtils.NO_EXPECTED_TYPE;
|
||||
import static org.jetbrains.jet.lang.types.TypeUtils.canHaveSubtypes;
|
||||
|
||||
public class CandidateResolver {
|
||||
@NotNull
|
||||
@@ -107,7 +109,7 @@ public class CandidateResolver {
|
||||
argumentTypeResolver.checkTypesWithNoCallee(context.toBasic());
|
||||
return;
|
||||
}
|
||||
argumentTypeResolver.checkUnmappedArgumentTypes(context.toBasic(), unmappedArguments);
|
||||
candidateCall.setUnmappedArguments(unmappedArguments);
|
||||
}
|
||||
|
||||
List<JetTypeProjection> jetTypeArguments = context.call.getTypeArguments();
|
||||
@@ -138,7 +140,8 @@ public class CandidateResolver {
|
||||
|
||||
Map<TypeConstructor, TypeProjection>
|
||||
substitutionContext = FunctionDescriptorUtil.createSubstitutionContext((FunctionDescriptor)candidate, typeArguments);
|
||||
candidateCall.setResultingSubstitutor(TypeSubstitutor.create(substitutionContext));
|
||||
TypeSubstitutor substitutor = TypeSubstitutor.create(substitutionContext);
|
||||
candidateCall.setResultingSubstitutor(substitutor);
|
||||
|
||||
List<TypeParameterDescriptor> typeParameters = candidateCall.getCandidateDescriptor().getTypeParameters();
|
||||
for (int i = 0; i < typeParameters.size(); i++) {
|
||||
@@ -206,6 +209,7 @@ public class CandidateResolver {
|
||||
addConstraintForFunctionLiteral(valueArgument, valueParameterDescriptor, constraintSystem, context);
|
||||
}
|
||||
}
|
||||
resolvedCall.setResultingSubstitutor(constraintSystem.getResultingSubstitutor());
|
||||
}
|
||||
|
||||
public <D extends CallableDescriptor> void completeTypeInferenceDependentOnExpectedTypeForCall(
|
||||
@@ -224,10 +228,11 @@ public class CandidateResolver {
|
||||
|
||||
if (!constraintSystem.isSuccessful()) {
|
||||
resolvedCall.setResultingSubstitutor(constraintSystemWithoutExpectedTypeConstraint.getResultingSubstitutor());
|
||||
List<JetType> argumentTypes = checkValueArgumentTypes(context, resolvedCall, resolvedCall.getTrace(),
|
||||
completeValueArgumentsInference(context);
|
||||
List<JetType> argumentTypes = checkValueArgumentTypes(context, resolvedCall, context.trace,
|
||||
RESOLVE_FUNCTION_ARGUMENTS).argumentTypes;
|
||||
JetType receiverType = resolvedCall.getReceiverArgument().exists() ? resolvedCall.getReceiverArgument().getType() : null;
|
||||
context.tracing.typeInferenceFailed(resolvedCall.getTrace(),
|
||||
context.tracing.typeInferenceFailed(context.trace,
|
||||
InferenceErrorData
|
||||
.create(descriptor, constraintSystem, argumentTypes, receiverType,
|
||||
context.expectedType),
|
||||
@@ -246,16 +251,52 @@ public class CandidateResolver {
|
||||
}
|
||||
}
|
||||
if (!boundsAreSatisfied) {
|
||||
context.tracing.upperBoundViolated(resolvedCall.getTrace(), InferenceErrorData.create(resolvedCall.getCandidateDescriptor(), constraintSystem));
|
||||
context.tracing.upperBoundViolated(context.trace, InferenceErrorData.create(resolvedCall.getCandidateDescriptor(), constraintSystem));
|
||||
}
|
||||
resolvedCall.setResultingSubstitutor(constraintSystem.getResultingSubstitutor());
|
||||
|
||||
completeValueArgumentsInference(context);
|
||||
// Here we type check the arguments with inferred types expected
|
||||
checkAllValueArguments(context, RESOLVE_FUNCTION_ARGUMENTS);
|
||||
checkAllValueArguments(context, context.trace, RESOLVE_FUNCTION_ARGUMENTS);
|
||||
|
||||
resolvedCall.setHasUnknownTypeParameters(false);
|
||||
if (resolvedCall.getStatus() == ResolutionStatus.UNKNOWN_STATUS) {
|
||||
resolvedCall.addStatus(ResolutionStatus.SUCCESS);
|
||||
ResolutionStatus status = resolvedCall.getStatus();
|
||||
if (status == ResolutionStatus.UNKNOWN_STATUS || status == ResolutionStatus.INCOMPLETE_TYPE_INFERENCE) {
|
||||
resolvedCall.setStatusToSuccess();
|
||||
}
|
||||
}
|
||||
|
||||
public <D extends CallableDescriptor> void completeValueArgumentsInference(
|
||||
@NotNull CallCandidateResolutionContext<D> context
|
||||
) {
|
||||
ResolvedCallImpl<D> resolvedCall = context.candidateCall;
|
||||
ConstraintSystem constraintSystem = context.candidateCall.getConstraintSystem();
|
||||
for (Map.Entry<ValueParameterDescriptor, ResolvedValueArgument> entry : resolvedCall.getValueArguments().entrySet()) {
|
||||
ValueParameterDescriptor parameterDescriptor = entry.getKey();
|
||||
ResolvedValueArgument resolvedArgument = entry.getValue();
|
||||
|
||||
for (ValueArgument argument : resolvedArgument.getArguments()) {
|
||||
JetExpression expression = argument.getArgumentExpression();
|
||||
if (expression == null) continue;
|
||||
|
||||
JetType effectiveExpectedType = getEffectiveExpectedType(parameterDescriptor, argument);
|
||||
JetType expectedType = constraintSystem != null
|
||||
? constraintSystem.getCurrentSubstitutor().substitute(effectiveExpectedType, Variance.INVARIANT)
|
||||
: effectiveExpectedType;
|
||||
|
||||
CallCandidateResolutionContext<FunctionDescriptor> storedContextForArgument =
|
||||
resolvedCall.getDeferredComputationForArgument(argument);
|
||||
if (storedContextForArgument == null) continue;
|
||||
|
||||
CallCandidateResolutionContext<FunctionDescriptor> contextForArgument =
|
||||
storedContextForArgument.replaceResolveMode(ResolveMode.NORMAL).replaceBindingTrace(context.trace).replaceExpectedType(expectedType);
|
||||
if (contextForArgument.candidateCall.hasUnknownTypeParameters()) {
|
||||
completeTypeInferenceDependentOnExpectedTypeForCall(contextForArgument);
|
||||
}
|
||||
else {
|
||||
completeValueArgumentsInference(contextForArgument);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -373,31 +414,21 @@ public class CandidateResolver {
|
||||
// Solution
|
||||
boolean hasContradiction = constraintSystem.hasContradiction();
|
||||
boolean boundsAreSatisfied = ConstraintsUtil.checkBoundsAreSatisfied(constraintSystem, /*substituteOtherTypeParametersInBounds=*/false);
|
||||
candidateCall.setHasUnknownTypeParameters(true);
|
||||
if (!hasContradiction && boundsAreSatisfied) {
|
||||
candidateCall.setHasUnknownTypeParameters(true);
|
||||
return SUCCESS;
|
||||
return INCOMPLETE_TYPE_INFERENCE;
|
||||
}
|
||||
ValueArgumentsCheckingResult checkingResult = checkAllValueArguments(context, SKIP_FUNCTION_ARGUMENTS);
|
||||
ResolutionStatus argumentsStatus = checkingResult.status;
|
||||
List<JetType> argumentTypes = checkingResult.argumentTypes;
|
||||
JetType receiverType = candidateCall.getReceiverArgument().exists() ? candidateCall.getReceiverArgument().getType() : null;
|
||||
InferenceErrorData.ExtendedInferenceErrorData inferenceErrorData = InferenceErrorData
|
||||
.create(candidate, constraintSystemWithRightTypeParameters, argumentTypes, receiverType, context.expectedType);
|
||||
if (hasContradiction) {
|
||||
context.tracing.typeInferenceFailed(candidateCall.getTrace(), inferenceErrorData, constraintSystemWithRightTypeParameters);
|
||||
}
|
||||
else {
|
||||
context.tracing.upperBoundViolated(candidateCall.getTrace(), inferenceErrorData);
|
||||
}
|
||||
return OTHER_ERROR.combine(argumentsStatus);
|
||||
}
|
||||
|
||||
private <C extends CallResolutionContext<C>> void addConstraintForValueArgument(
|
||||
private <D extends CallableDescriptor> void addConstraintForValueArgument(
|
||||
@NotNull ValueArgument valueArgument,
|
||||
@NotNull ValueParameterDescriptor valueParameterDescriptor,
|
||||
@NotNull TypeSubstitutor substitutor,
|
||||
@NotNull ConstraintSystem constraintSystem,
|
||||
@NotNull CallResolutionContext<C> context,
|
||||
@NotNull CallCandidateResolutionContext<D> context,
|
||||
@Nullable boolean[] isErrorType,
|
||||
@NotNull CallResolverUtil.ResolveArgumentsMode resolveFunctionArgumentBodies) {
|
||||
|
||||
@@ -406,13 +437,17 @@ public class CandidateResolver {
|
||||
TemporaryBindingTrace traceToResolveArgument = TemporaryBindingTrace.create(
|
||||
context.trace, "transient trace to resolve argument", argumentExpression);
|
||||
JetType expectedType = substitutor.substitute(effectiveExpectedType, Variance.INVARIANT);
|
||||
CallResolutionContext newContext =
|
||||
context.replaceBindingTrace(traceToResolveArgument).replaceExpectedType(
|
||||
expectedType != null ? expectedType : NO_EXPECTED_TYPE);
|
||||
JetType type = argumentTypeResolver.getArgumentTypeInfo(argumentExpression, newContext, resolveFunctionArgumentBodies).getType();
|
||||
CallResolutionContext newContext = context.replaceBindingTrace(traceToResolveArgument).replaceExpectedType(expectedType);
|
||||
TypeInfoForCall typeInfoForCall = argumentTypeResolver.getArgumentTypeInfo(argumentExpression, newContext,
|
||||
resolveFunctionArgumentBodies);
|
||||
CallCandidateResolutionContext<FunctionDescriptor> contextForArgument = typeInfoForCall.getCallCandidateResolutionContext();
|
||||
if (contextForArgument != null) {
|
||||
context.candidateCall.addDeferredComputationForArgument(valueArgument, contextForArgument);
|
||||
traceToResolveArgument.commit();
|
||||
}
|
||||
JetType type = typeInfoForCall.getType();
|
||||
constraintSystem.addSubtypeConstraint(type, effectiveExpectedType, ConstraintPosition.getValueParameterPosition(
|
||||
valueParameterDescriptor.getIndex()));
|
||||
BindingContextUtils.commitResolutionCacheData(traceToResolveArgument, context.trace);
|
||||
if (isErrorType != null) {
|
||||
isErrorType[0] = type == null || ErrorUtils.isErrorType(type);
|
||||
}
|
||||
@@ -421,8 +456,16 @@ public class CandidateResolver {
|
||||
private <D extends CallableDescriptor> ValueArgumentsCheckingResult checkAllValueArguments(
|
||||
@NotNull CallCandidateResolutionContext<D> context,
|
||||
@NotNull CallResolverUtil.ResolveArgumentsMode resolveFunctionArgumentBodies) {
|
||||
ValueArgumentsCheckingResult checkingResult = checkValueArgumentTypes(context, context.candidateCall,
|
||||
context.candidateCall.getTrace(), resolveFunctionArgumentBodies);
|
||||
return checkAllValueArguments(context, context.candidateCall.getTrace(), resolveFunctionArgumentBodies);
|
||||
}
|
||||
|
||||
private <D extends CallableDescriptor> ValueArgumentsCheckingResult checkAllValueArguments(
|
||||
@NotNull CallCandidateResolutionContext<D> context,
|
||||
@NotNull BindingTrace trace,
|
||||
@NotNull CallResolverUtil.ResolveArgumentsMode resolveFunctionArgumentBodies
|
||||
) {
|
||||
ValueArgumentsCheckingResult checkingResult = checkValueArgumentTypes(
|
||||
context, context.candidateCall, trace, resolveFunctionArgumentBodies);
|
||||
ResolutionStatus resultStatus = checkingResult.status;
|
||||
ResolvedCall<D> candidateCall = context.candidateCall;
|
||||
|
||||
@@ -431,13 +474,17 @@ public class CandidateResolver {
|
||||
// both 'b' (receiver) and 'foo' (this object) might be nullable. In the first case we mark dot, in the second 'foo'.
|
||||
// Class 'CallForImplicitInvoke' helps up to recognise this case, and parameter 'implicitInvokeCheck' helps us to distinguish whether we check receiver or this object.
|
||||
|
||||
resultStatus = resultStatus.combine(checkReceiver(context, candidateCall, candidateCall.getResultingDescriptor().getReceiverParameter(), candidateCall.getReceiverArgument(),
|
||||
candidateCall.getExplicitReceiverKind().isReceiver(), false));
|
||||
resultStatus = resultStatus.combine(checkReceiver(
|
||||
context, candidateCall, trace,
|
||||
candidateCall.getResultingDescriptor().getReceiverParameter(),
|
||||
candidateCall.getReceiverArgument(), candidateCall.getExplicitReceiverKind().isReceiver(), false));
|
||||
|
||||
resultStatus = resultStatus.combine(checkReceiver(context, candidateCall, candidateCall.getResultingDescriptor().getExpectedThisObject(), candidateCall.getThisObject(),
|
||||
candidateCall.getExplicitReceiverKind().isThisObject(),
|
||||
// for the invocation 'foo(1)' where foo is a variable of function type we should mark 'foo' if there is unsafe call error
|
||||
context.call instanceof CallTransformer.CallForImplicitInvoke));
|
||||
resultStatus = resultStatus.combine(checkReceiver(
|
||||
context, candidateCall, trace,
|
||||
candidateCall.getResultingDescriptor().getExpectedThisObject(), candidateCall.getThisObject(),
|
||||
candidateCall.getExplicitReceiverKind().isThisObject(),
|
||||
// for the invocation 'foo(1)' where foo is a variable of function type we should mark 'foo' if there is unsafe call error
|
||||
context.call instanceof CallTransformer.CallForImplicitInvoke));
|
||||
return new ValueArgumentsCheckingResult(resultStatus, checkingResult.argumentTypes);
|
||||
}
|
||||
|
||||
@@ -467,6 +514,7 @@ public class CandidateResolver {
|
||||
expression, newContext, resolveFunctionArgumentBodies);
|
||||
JetType type = typeInfoForCall.getType();
|
||||
candidateCall.addDataFlowInfo(typeInfoForCall.getDataFlowInfo());
|
||||
candidateCall.addDeferredComputationForArgument(argument, typeInfoForCall.getCallCandidateResolutionContext());
|
||||
|
||||
if (type == null || (ErrorUtils.isErrorType(type) && type != PLACEHOLDER_FUNCTION_TYPE)) {
|
||||
candidateCall.argumentHasNoType();
|
||||
@@ -511,11 +559,12 @@ public class CandidateResolver {
|
||||
return null;
|
||||
}
|
||||
|
||||
private <D extends CallableDescriptor> ResolutionStatus checkReceiver(CallCandidateResolutionContext<D> context, ResolvedCall<D> candidateCall,
|
||||
private <D extends CallableDescriptor> ResolutionStatus checkReceiver(
|
||||
CallCandidateResolutionContext<D> context, ResolvedCall<D> candidateCall, BindingTrace trace,
|
||||
ReceiverParameterDescriptor receiverParameter, ReceiverValue receiverArgument,
|
||||
boolean isExplicitReceiver, boolean implicitInvokeCheck) {
|
||||
|
||||
BindingContext bindingContext = context.candidateCall.getTrace().getBindingContext();
|
||||
BindingContext bindingContext = trace.getBindingContext();
|
||||
|
||||
ResolutionStatus result = SUCCESS;
|
||||
if (receiverParameter != null && receiverArgument.exists()) {
|
||||
@@ -524,7 +573,7 @@ public class CandidateResolver {
|
||||
AutoCastServiceImpl autoCastService = new AutoCastServiceImpl(context.dataFlowInfo, bindingContext);
|
||||
if (!safeAccess && !receiverParameter.getType().isNullable() && !autoCastService.isNotNull(receiverArgument)) {
|
||||
|
||||
context.tracing.unsafeCall(context.candidateCall.getTrace(), receiverArgumentType, implicitInvokeCheck);
|
||||
context.tracing.unsafeCall(trace, receiverArgumentType, implicitInvokeCheck);
|
||||
result = UNSAFE_CALL_ERROR;
|
||||
}
|
||||
else {
|
||||
@@ -534,13 +583,13 @@ public class CandidateResolver {
|
||||
if (!TypeUtils.dependsOnTypeParameters(receiverParameter.getType(),
|
||||
candidateCall.getCandidateDescriptor().getTypeParameters()) &&
|
||||
!argumentTypeResolver.isSubtypeOfForArgumentType(effectiveReceiverArgumentType, receiverParameter.getType())) {
|
||||
context.tracing.wrongReceiverType(context.candidateCall.getTrace(), receiverParameter, receiverArgument);
|
||||
context.tracing.wrongReceiverType(trace, receiverParameter, receiverArgument);
|
||||
result = OTHER_ERROR;
|
||||
}
|
||||
}
|
||||
DataFlowValue receiverValue = DataFlowValueFactory.INSTANCE.createDataFlowValue(receiverArgument, bindingContext);
|
||||
if (safeAccess && !context.dataFlowInfo.getNullability(receiverValue).canBeNull()) {
|
||||
context.tracing.unnecessarySafeCall(context.candidateCall.getTrace(), receiverArgumentType);
|
||||
context.tracing.unnecessarySafeCall(trace, receiverArgumentType);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
|
||||
+2
-1
@@ -58,8 +58,9 @@ public class TypeInfoForCall {
|
||||
if (resolvedCall instanceof ResolvedCallImpl) {
|
||||
BasicCallResolutionContext basicCallResolutionContext = BasicCallResolutionContext.create(
|
||||
TRACE_STUB, context.scope, call, TypeUtils.NO_EXPECTED_TYPE, typeInfo.getDataFlowInfo(), resolveMode, context.namespacesAllowed);
|
||||
//todo[ResolvedCallImpl]
|
||||
callCandidateResolutionContext = CallCandidateResolutionContext.createForCallBeingAnalyzed(
|
||||
(ResolvedCallImpl<FunctionDescriptor>) resolvedCall, basicCallResolutionContext, TracingStrategy.EMPTY);
|
||||
(ResolvedCallImpl<FunctionDescriptor>) resolvedCall, basicCallResolutionContext, ((ResolvedCallImpl<FunctionDescriptor>) resolvedCall).getTracing());
|
||||
}
|
||||
else {
|
||||
callCandidateResolutionContext = null;
|
||||
|
||||
+37
-3
@@ -17,14 +17,18 @@
|
||||
package org.jetbrains.jet.lang.resolve.calls.model;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Sets;
|
||||
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.FunctionDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor;
|
||||
import org.jetbrains.jet.lang.psi.ValueArgument;
|
||||
import org.jetbrains.jet.lang.resolve.*;
|
||||
import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo;
|
||||
import org.jetbrains.jet.lang.resolve.calls.context.CallCandidateResolutionContext;
|
||||
import org.jetbrains.jet.lang.resolve.calls.tasks.ExplicitReceiverKind;
|
||||
import org.jetbrains.jet.lang.resolve.calls.tasks.ResolutionCandidate;
|
||||
import org.jetbrains.jet.lang.resolve.calls.results.ResolutionStatus;
|
||||
@@ -34,10 +38,9 @@ import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue;
|
||||
import org.jetbrains.jet.lang.types.JetType;
|
||||
import org.jetbrains.jet.lang.types.TypeSubstitutor;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.*;
|
||||
|
||||
import static org.jetbrains.jet.lang.resolve.calls.results.ResolutionStatus.INCOMPLETE_TYPE_INFERENCE;
|
||||
import static org.jetbrains.jet.lang.resolve.calls.results.ResolutionStatus.UNKNOWN_STATUS;
|
||||
|
||||
public class ResolvedCallImpl<D extends CallableDescriptor> implements ResolvedCallWithTrace<D> {
|
||||
@@ -71,6 +74,8 @@ public class ResolvedCallImpl<D extends CallableDescriptor> implements ResolvedC
|
||||
|
||||
private final Map<TypeParameterDescriptor, JetType> typeArguments = Maps.newLinkedHashMap();
|
||||
private final Map<ValueParameterDescriptor, ResolvedValueArgument> valueArguments = Maps.newLinkedHashMap();
|
||||
private final Map<ValueArgument, CallCandidateResolutionContext<FunctionDescriptor>> deferredComputationsForArguments = Maps.newLinkedHashMap();
|
||||
private final Set<ValueArgument> unmappedArguments = Sets.newLinkedHashSet();
|
||||
private boolean someArgumentHasNoType = false;
|
||||
private final DelegatingBindingTrace trace;
|
||||
private final TracingStrategy tracing;
|
||||
@@ -99,6 +104,11 @@ public class ResolvedCallImpl<D extends CallableDescriptor> implements ResolvedC
|
||||
this.status = this.status.combine(status);
|
||||
}
|
||||
|
||||
public void setStatusToSuccess() {
|
||||
assert status == INCOMPLETE_TYPE_INFERENCE || status == UNKNOWN_STATUS;
|
||||
status = ResolutionStatus.SUCCESS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasUnknownTypeParameters() {
|
||||
return hasUnknownTypeParameters;
|
||||
@@ -168,6 +178,16 @@ public class ResolvedCallImpl<D extends CallableDescriptor> implements ResolvedC
|
||||
valueArguments.put(valueParameter, valueArgument);
|
||||
}
|
||||
|
||||
public void setUnmappedArguments(@NotNull Collection<ValueArgument> unmappedArguments) {
|
||||
this.unmappedArguments.addAll(unmappedArguments);
|
||||
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Set<ValueArgument> getUnmappedArguments() {
|
||||
return unmappedArguments;
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public ReceiverValue getReceiverArgument() {
|
||||
@@ -250,4 +270,18 @@ public class ResolvedCallImpl<D extends CallableDescriptor> implements ResolvedC
|
||||
assert dataFlowInfo != null;
|
||||
dataFlowInfo = dataFlowInfo.and(info);
|
||||
}
|
||||
|
||||
public void addDeferredComputationForArgument(
|
||||
@NotNull ValueArgument valueArgument,
|
||||
@Nullable CallCandidateResolutionContext<FunctionDescriptor> callCandidateResolutionContext
|
||||
) {
|
||||
if (callCandidateResolutionContext != null) {
|
||||
deferredComputationsForArguments.put(valueArgument, callCandidateResolutionContext);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public CallCandidateResolutionContext<FunctionDescriptor> getDeferredComputationForArgument(@NotNull ValueArgument valueArgument) {
|
||||
return deferredComputationsForArguments.get(valueArgument);
|
||||
}
|
||||
}
|
||||
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
package a
|
||||
|
||||
import java.util.ArrayList
|
||||
|
||||
public fun <T> Iterable<T>.withIndices(): List<Pair<Int, T>> {
|
||||
val answer = ArrayList<Pair<Int, T>>()
|
||||
var nextIndex = 1
|
||||
for (e in this) {
|
||||
answer.add(Pair(nextIndex, e))
|
||||
nextIndex++
|
||||
}
|
||||
return answer
|
||||
}
|
||||
|
||||
//from standard library
|
||||
public class Pair<out A, out B>(
|
||||
public val first: A,
|
||||
public val second: B
|
||||
)
|
||||
@@ -1993,7 +1993,7 @@ public class JetDiagnosticsTestGenerated extends AbstractDiagnosticsTestWithEage
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/diagnostics/tests/inference")
|
||||
@InnerTestClasses({Inference.Regressions.class, Inference.ReportingImprovements.class, Inference.UpperBounds.class, Inference.Varargs.class})
|
||||
@InnerTestClasses({Inference.Complicated.class, Inference.Regressions.class, Inference.ReportingImprovements.class, Inference.UpperBounds.class, Inference.Varargs.class})
|
||||
public static class Inference extends AbstractDiagnosticsTestWithEagerResolve {
|
||||
public void testAllFilesPresentInInference() throws Exception {
|
||||
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.GenerateTests", new File("compiler/testData/diagnostics/tests/inference"), Pattern.compile("^(.+)\\.kt$"), true);
|
||||
@@ -2119,6 +2119,19 @@ public class JetDiagnosticsTestGenerated extends AbstractDiagnosticsTestWithEage
|
||||
doTest("compiler/testData/diagnostics/tests/inference/typeInferenceExpectedTypeMismatch.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/diagnostics/tests/inference/complicated")
|
||||
public static class Complicated extends AbstractDiagnosticsTestWithEagerResolve {
|
||||
public void testAllFilesPresentInComplicated() throws Exception {
|
||||
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.GenerateTests", new File("compiler/testData/diagnostics/tests/inference/complicated"), "kt", true);
|
||||
}
|
||||
|
||||
@TestMetadata("completeValueArgumentsInference.kt")
|
||||
public void testCompleteValueArgumentsInference() throws Exception {
|
||||
doTest("compiler/testData/diagnostics/tests/inference/complicated/completeValueArgumentsInference.kt");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/diagnostics/tests/inference/regressions")
|
||||
public static class Regressions extends AbstractDiagnosticsTestWithEagerResolve {
|
||||
public void testAllFilesPresentInRegressions() throws Exception {
|
||||
@@ -2399,6 +2412,7 @@ public class JetDiagnosticsTestGenerated extends AbstractDiagnosticsTestWithEage
|
||||
public static Test innerSuite() {
|
||||
TestSuite suite = new TestSuite("Inference");
|
||||
suite.addTestSuite(Inference.class);
|
||||
suite.addTestSuite(Complicated.class);
|
||||
suite.addTestSuite(Regressions.class);
|
||||
suite.addTestSuite(ReportingImprovements.class);
|
||||
suite.addTestSuite(UpperBounds.class);
|
||||
|
||||
Reference in New Issue
Block a user