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:
Svetlana Isakova
2013-02-05 20:04:13 +04:00
parent 0d0441ebd8
commit 3eee19578a
8 changed files with 252 additions and 106 deletions
@@ -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;
@@ -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;
@@ -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);
}
}
@@ -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);