added CandidateResolver
(that took some methods from CallResolver)
This commit is contained in:
+7
-1
@@ -35,6 +35,7 @@ import org.jetbrains.jet.lang.resolve.NamespaceFactoryImpl;
|
||||
import org.jetbrains.jet.lang.resolve.DeclarationResolver;
|
||||
import org.jetbrains.jet.lang.resolve.AnnotationResolver;
|
||||
import org.jetbrains.jet.lang.resolve.calls.CallResolver;
|
||||
import org.jetbrains.jet.lang.resolve.calls.CandidateResolver;
|
||||
import org.jetbrains.jet.lang.types.expressions.ExpressionTypingServices;
|
||||
import org.jetbrains.jet.lang.resolve.TypeResolver;
|
||||
import org.jetbrains.jet.lang.resolve.QualifiedExpressionResolver;
|
||||
@@ -83,6 +84,7 @@ public class InjectorForTopDownAnalyzerForJvm implements InjectorForTopDownAnaly
|
||||
private DeclarationResolver declarationResolver;
|
||||
private AnnotationResolver annotationResolver;
|
||||
private CallResolver callResolver;
|
||||
private CandidateResolver candidateResolver;
|
||||
private ExpressionTypingServices expressionTypingServices;
|
||||
private TypeResolver typeResolver;
|
||||
private QualifiedExpressionResolver qualifiedExpressionResolver;
|
||||
@@ -132,6 +134,7 @@ public class InjectorForTopDownAnalyzerForJvm implements InjectorForTopDownAnaly
|
||||
this.declarationResolver = new DeclarationResolver();
|
||||
this.annotationResolver = new AnnotationResolver();
|
||||
this.callResolver = new CallResolver();
|
||||
this.candidateResolver = new CandidateResolver();
|
||||
this.expressionTypingServices = new ExpressionTypingServices();
|
||||
this.typeResolver = new TypeResolver();
|
||||
this.qualifiedExpressionResolver = new QualifiedExpressionResolver();
|
||||
@@ -216,11 +219,14 @@ public class InjectorForTopDownAnalyzerForJvm implements InjectorForTopDownAnaly
|
||||
annotationResolver.setCallResolver(callResolver);
|
||||
annotationResolver.setExpressionTypingServices(expressionTypingServices);
|
||||
|
||||
callResolver.setDescriptorResolver(descriptorResolver);
|
||||
callResolver.setCandidateResolver(candidateResolver);
|
||||
callResolver.setExpressionTypingServices(expressionTypingServices);
|
||||
callResolver.setResolutionResultsHandler(resolutionResultsHandler);
|
||||
callResolver.setTypeResolver(typeResolver);
|
||||
|
||||
candidateResolver.setExpressionTypingServices(expressionTypingServices);
|
||||
candidateResolver.setTypeResolver(typeResolver);
|
||||
|
||||
expressionTypingServices.setCallResolver(callResolver);
|
||||
expressionTypingServices.setDescriptorResolver(descriptorResolver);
|
||||
expressionTypingServices.setProject(project);
|
||||
|
||||
@@ -24,9 +24,10 @@ import org.jetbrains.jet.lang.resolve.BindingTrace;
|
||||
import org.jetbrains.jet.lang.resolve.BodiesResolveContext;
|
||||
import org.jetbrains.jet.lang.ModuleConfiguration;
|
||||
import org.jetbrains.jet.lang.resolve.calls.CallResolver;
|
||||
import org.jetbrains.jet.lang.resolve.calls.CandidateResolver;
|
||||
import org.jetbrains.jet.lang.types.expressions.ExpressionTypingServices;
|
||||
import org.jetbrains.jet.lang.resolve.DescriptorResolver;
|
||||
import org.jetbrains.jet.lang.resolve.AnnotationResolver;
|
||||
import org.jetbrains.jet.lang.types.expressions.ExpressionTypingServices;
|
||||
import org.jetbrains.jet.lang.resolve.TypeResolver;
|
||||
import org.jetbrains.jet.lang.resolve.QualifiedExpressionResolver;
|
||||
import org.jetbrains.jet.lang.resolve.calls.results.ResolutionResultsHandler;
|
||||
@@ -48,9 +49,10 @@ public class InjectorForBodyResolve {
|
||||
private final BodiesResolveContext bodiesResolveContext;
|
||||
private final ModuleConfiguration moduleConfiguration;
|
||||
private CallResolver callResolver;
|
||||
private CandidateResolver candidateResolver;
|
||||
private ExpressionTypingServices expressionTypingServices;
|
||||
private DescriptorResolver descriptorResolver;
|
||||
private AnnotationResolver annotationResolver;
|
||||
private ExpressionTypingServices expressionTypingServices;
|
||||
private TypeResolver typeResolver;
|
||||
private QualifiedExpressionResolver qualifiedExpressionResolver;
|
||||
private ResolutionResultsHandler resolutionResultsHandler;
|
||||
@@ -74,9 +76,10 @@ public class InjectorForBodyResolve {
|
||||
this.bodiesResolveContext = bodiesResolveContext;
|
||||
this.moduleConfiguration = moduleConfiguration;
|
||||
this.callResolver = new CallResolver();
|
||||
this.candidateResolver = new CandidateResolver();
|
||||
this.expressionTypingServices = new ExpressionTypingServices();
|
||||
this.descriptorResolver = new DescriptorResolver();
|
||||
this.annotationResolver = new AnnotationResolver();
|
||||
this.expressionTypingServices = new ExpressionTypingServices();
|
||||
this.typeResolver = new TypeResolver();
|
||||
this.qualifiedExpressionResolver = new QualifiedExpressionResolver();
|
||||
this.resolutionResultsHandler = new ResolutionResultsHandler();
|
||||
@@ -96,11 +99,19 @@ public class InjectorForBodyResolve {
|
||||
this.bodyResolver.setTopDownAnalysisParameters(topDownAnalysisParameters);
|
||||
this.bodyResolver.setTrace(bindingTrace);
|
||||
|
||||
callResolver.setDescriptorResolver(descriptorResolver);
|
||||
callResolver.setCandidateResolver(candidateResolver);
|
||||
callResolver.setExpressionTypingServices(expressionTypingServices);
|
||||
callResolver.setResolutionResultsHandler(resolutionResultsHandler);
|
||||
callResolver.setTypeResolver(typeResolver);
|
||||
|
||||
candidateResolver.setExpressionTypingServices(expressionTypingServices);
|
||||
candidateResolver.setTypeResolver(typeResolver);
|
||||
|
||||
expressionTypingServices.setCallResolver(callResolver);
|
||||
expressionTypingServices.setDescriptorResolver(descriptorResolver);
|
||||
expressionTypingServices.setProject(project);
|
||||
expressionTypingServices.setTypeResolver(typeResolver);
|
||||
|
||||
descriptorResolver.setAnnotationResolver(annotationResolver);
|
||||
descriptorResolver.setExpressionTypingServices(expressionTypingServices);
|
||||
descriptorResolver.setTypeResolver(typeResolver);
|
||||
@@ -108,11 +119,6 @@ public class InjectorForBodyResolve {
|
||||
annotationResolver.setCallResolver(callResolver);
|
||||
annotationResolver.setExpressionTypingServices(expressionTypingServices);
|
||||
|
||||
expressionTypingServices.setCallResolver(callResolver);
|
||||
expressionTypingServices.setDescriptorResolver(descriptorResolver);
|
||||
expressionTypingServices.setProject(project);
|
||||
expressionTypingServices.setTypeResolver(typeResolver);
|
||||
|
||||
typeResolver.setAnnotationResolver(annotationResolver);
|
||||
typeResolver.setDescriptorResolver(descriptorResolver);
|
||||
typeResolver.setModuleConfiguration(moduleConfiguration);
|
||||
|
||||
@@ -28,6 +28,7 @@ import org.jetbrains.jet.lang.resolve.lazy.ScopeProvider;
|
||||
import org.jetbrains.jet.lang.resolve.AnnotationResolver;
|
||||
import org.jetbrains.jet.lang.resolve.QualifiedExpressionResolver;
|
||||
import org.jetbrains.jet.lang.resolve.calls.CallResolver;
|
||||
import org.jetbrains.jet.lang.resolve.calls.CandidateResolver;
|
||||
import org.jetbrains.jet.lang.resolve.calls.results.ResolutionResultsHandler;
|
||||
import org.jetbrains.jet.lang.resolve.calls.results.OverloadingConflictResolver;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -47,6 +48,7 @@ public class InjectorForLazyResolve {
|
||||
private AnnotationResolver annotationResolver;
|
||||
private QualifiedExpressionResolver qualifiedExpressionResolver;
|
||||
private CallResolver callResolver;
|
||||
private CandidateResolver candidateResolver;
|
||||
private ResolutionResultsHandler resolutionResultsHandler;
|
||||
private OverloadingConflictResolver overloadingConflictResolver;
|
||||
|
||||
@@ -67,6 +69,7 @@ public class InjectorForLazyResolve {
|
||||
this.annotationResolver = new AnnotationResolver();
|
||||
this.qualifiedExpressionResolver = new QualifiedExpressionResolver();
|
||||
this.callResolver = new CallResolver();
|
||||
this.candidateResolver = new CandidateResolver();
|
||||
this.resolutionResultsHandler = new ResolutionResultsHandler();
|
||||
this.overloadingConflictResolver = new OverloadingConflictResolver();
|
||||
|
||||
@@ -87,11 +90,14 @@ public class InjectorForLazyResolve {
|
||||
this.annotationResolver.setCallResolver(callResolver);
|
||||
this.annotationResolver.setExpressionTypingServices(expressionTypingServices);
|
||||
|
||||
callResolver.setDescriptorResolver(descriptorResolver);
|
||||
callResolver.setCandidateResolver(candidateResolver);
|
||||
callResolver.setExpressionTypingServices(expressionTypingServices);
|
||||
callResolver.setResolutionResultsHandler(resolutionResultsHandler);
|
||||
callResolver.setTypeResolver(typeResolver);
|
||||
|
||||
candidateResolver.setExpressionTypingServices(expressionTypingServices);
|
||||
candidateResolver.setTypeResolver(typeResolver);
|
||||
|
||||
resolutionResultsHandler.setOverloadingConflictResolver(overloadingConflictResolver);
|
||||
|
||||
}
|
||||
|
||||
@@ -21,9 +21,10 @@ import org.jetbrains.jet.lang.types.expressions.ExpressionTypingServices;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import org.jetbrains.jet.lang.ModuleConfiguration;
|
||||
import org.jetbrains.jet.lang.resolve.calls.CallResolver;
|
||||
import org.jetbrains.jet.lang.resolve.DescriptorResolver;
|
||||
import org.jetbrains.jet.lang.resolve.AnnotationResolver;
|
||||
import org.jetbrains.jet.lang.resolve.calls.CandidateResolver;
|
||||
import org.jetbrains.jet.lang.resolve.TypeResolver;
|
||||
import org.jetbrains.jet.lang.resolve.AnnotationResolver;
|
||||
import org.jetbrains.jet.lang.resolve.DescriptorResolver;
|
||||
import org.jetbrains.jet.lang.resolve.QualifiedExpressionResolver;
|
||||
import org.jetbrains.jet.lang.resolve.calls.results.ResolutionResultsHandler;
|
||||
import org.jetbrains.jet.lang.resolve.calls.results.OverloadingConflictResolver;
|
||||
@@ -37,9 +38,10 @@ public class InjectorForMacros {
|
||||
private final Project project;
|
||||
private final ModuleConfiguration moduleConfiguration;
|
||||
private CallResolver callResolver;
|
||||
private DescriptorResolver descriptorResolver;
|
||||
private AnnotationResolver annotationResolver;
|
||||
private CandidateResolver candidateResolver;
|
||||
private TypeResolver typeResolver;
|
||||
private AnnotationResolver annotationResolver;
|
||||
private DescriptorResolver descriptorResolver;
|
||||
private QualifiedExpressionResolver qualifiedExpressionResolver;
|
||||
private ResolutionResultsHandler resolutionResultsHandler;
|
||||
private OverloadingConflictResolver overloadingConflictResolver;
|
||||
@@ -52,9 +54,10 @@ public class InjectorForMacros {
|
||||
this.project = project;
|
||||
this.moduleConfiguration = moduleConfiguration;
|
||||
this.callResolver = new CallResolver();
|
||||
this.descriptorResolver = new DescriptorResolver();
|
||||
this.annotationResolver = new AnnotationResolver();
|
||||
this.candidateResolver = new CandidateResolver();
|
||||
this.typeResolver = new TypeResolver();
|
||||
this.annotationResolver = new AnnotationResolver();
|
||||
this.descriptorResolver = new DescriptorResolver();
|
||||
this.qualifiedExpressionResolver = new QualifiedExpressionResolver();
|
||||
this.resolutionResultsHandler = new ResolutionResultsHandler();
|
||||
this.overloadingConflictResolver = new OverloadingConflictResolver();
|
||||
@@ -64,23 +67,26 @@ public class InjectorForMacros {
|
||||
this.expressionTypingServices.setProject(project);
|
||||
this.expressionTypingServices.setTypeResolver(typeResolver);
|
||||
|
||||
callResolver.setDescriptorResolver(descriptorResolver);
|
||||
callResolver.setCandidateResolver(candidateResolver);
|
||||
callResolver.setExpressionTypingServices(expressionTypingServices);
|
||||
callResolver.setResolutionResultsHandler(resolutionResultsHandler);
|
||||
callResolver.setTypeResolver(typeResolver);
|
||||
|
||||
descriptorResolver.setAnnotationResolver(annotationResolver);
|
||||
descriptorResolver.setExpressionTypingServices(expressionTypingServices);
|
||||
descriptorResolver.setTypeResolver(typeResolver);
|
||||
|
||||
annotationResolver.setCallResolver(callResolver);
|
||||
annotationResolver.setExpressionTypingServices(expressionTypingServices);
|
||||
candidateResolver.setExpressionTypingServices(expressionTypingServices);
|
||||
candidateResolver.setTypeResolver(typeResolver);
|
||||
|
||||
typeResolver.setAnnotationResolver(annotationResolver);
|
||||
typeResolver.setDescriptorResolver(descriptorResolver);
|
||||
typeResolver.setModuleConfiguration(moduleConfiguration);
|
||||
typeResolver.setQualifiedExpressionResolver(qualifiedExpressionResolver);
|
||||
|
||||
annotationResolver.setCallResolver(callResolver);
|
||||
annotationResolver.setExpressionTypingServices(expressionTypingServices);
|
||||
|
||||
descriptorResolver.setAnnotationResolver(annotationResolver);
|
||||
descriptorResolver.setExpressionTypingServices(expressionTypingServices);
|
||||
descriptorResolver.setTypeResolver(typeResolver);
|
||||
|
||||
resolutionResultsHandler.setOverloadingConflictResolver(overloadingConflictResolver);
|
||||
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@ import org.jetbrains.jet.lang.resolve.NamespaceFactoryImpl;
|
||||
import org.jetbrains.jet.lang.resolve.DeclarationResolver;
|
||||
import org.jetbrains.jet.lang.resolve.AnnotationResolver;
|
||||
import org.jetbrains.jet.lang.resolve.calls.CallResolver;
|
||||
import org.jetbrains.jet.lang.resolve.calls.CandidateResolver;
|
||||
import org.jetbrains.jet.lang.types.expressions.ExpressionTypingServices;
|
||||
import org.jetbrains.jet.lang.resolve.TypeResolver;
|
||||
import org.jetbrains.jet.lang.resolve.QualifiedExpressionResolver;
|
||||
@@ -66,6 +67,7 @@ public class InjectorForTopDownAnalyzerBasic {
|
||||
private DeclarationResolver declarationResolver;
|
||||
private AnnotationResolver annotationResolver;
|
||||
private CallResolver callResolver;
|
||||
private CandidateResolver candidateResolver;
|
||||
private ExpressionTypingServices expressionTypingServices;
|
||||
private TypeResolver typeResolver;
|
||||
private QualifiedExpressionResolver qualifiedExpressionResolver;
|
||||
@@ -101,6 +103,7 @@ public class InjectorForTopDownAnalyzerBasic {
|
||||
this.declarationResolver = new DeclarationResolver();
|
||||
this.annotationResolver = new AnnotationResolver();
|
||||
this.callResolver = new CallResolver();
|
||||
this.candidateResolver = new CandidateResolver();
|
||||
this.expressionTypingServices = new ExpressionTypingServices();
|
||||
this.typeResolver = new TypeResolver();
|
||||
this.qualifiedExpressionResolver = new QualifiedExpressionResolver();
|
||||
@@ -159,11 +162,14 @@ public class InjectorForTopDownAnalyzerBasic {
|
||||
annotationResolver.setCallResolver(callResolver);
|
||||
annotationResolver.setExpressionTypingServices(expressionTypingServices);
|
||||
|
||||
callResolver.setDescriptorResolver(descriptorResolver);
|
||||
callResolver.setCandidateResolver(candidateResolver);
|
||||
callResolver.setExpressionTypingServices(expressionTypingServices);
|
||||
callResolver.setResolutionResultsHandler(resolutionResultsHandler);
|
||||
callResolver.setTypeResolver(typeResolver);
|
||||
|
||||
candidateResolver.setExpressionTypingServices(expressionTypingServices);
|
||||
candidateResolver.setTypeResolver(typeResolver);
|
||||
|
||||
expressionTypingServices.setCallResolver(callResolver);
|
||||
expressionTypingServices.setDescriptorResolver(descriptorResolver);
|
||||
expressionTypingServices.setProject(project);
|
||||
|
||||
@@ -16,28 +16,18 @@
|
||||
|
||||
package org.jetbrains.jet.lang.resolve.calls;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.intellij.openapi.progress.ProgressIndicatorProvider;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.descriptors.*;
|
||||
import org.jetbrains.jet.lang.diagnostics.Errors;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
import org.jetbrains.jet.lang.resolve.*;
|
||||
import org.jetbrains.jet.lang.resolve.calls.autocasts.AutoCastReceiver;
|
||||
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.DataFlowValue;
|
||||
import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowValueFactory;
|
||||
import org.jetbrains.jet.lang.resolve.calls.inference.*;
|
||||
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.results.*;
|
||||
import org.jetbrains.jet.lang.resolve.calls.tasks.*;
|
||||
import org.jetbrains.jet.lang.resolve.calls.util.DelegatingCall;
|
||||
@@ -45,7 +35,6 @@ import org.jetbrains.jet.lang.resolve.calls.util.ExpressionAsFunctionDescriptor;
|
||||
import org.jetbrains.jet.lang.resolve.calls.util.JetFakeReference;
|
||||
import org.jetbrains.jet.lang.resolve.name.Name;
|
||||
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.ReceiverDescriptor;
|
||||
import org.jetbrains.jet.lang.types.*;
|
||||
import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
|
||||
@@ -61,7 +50,6 @@ import java.util.*;
|
||||
import static org.jetbrains.jet.lang.diagnostics.Errors.*;
|
||||
import static org.jetbrains.jet.lang.resolve.BindingContext.*;
|
||||
import static org.jetbrains.jet.lang.resolve.calls.results.ResolutionStatus.*;
|
||||
import static org.jetbrains.jet.lang.resolve.calls.inference.InferenceErrorData.ExtendedInferenceErrorData;
|
||||
import static org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor.NO_RECEIVER;
|
||||
import static org.jetbrains.jet.lang.types.TypeUtils.NO_EXPECTED_TYPE;
|
||||
|
||||
@@ -78,7 +66,7 @@ public class CallResolver {
|
||||
@NotNull
|
||||
private TypeResolver typeResolver;
|
||||
@NotNull
|
||||
private DescriptorResolver descriptorResolver;
|
||||
private CandidateResolver candidateResolver;
|
||||
|
||||
@Inject
|
||||
public void setResolutionResultsHandler(@NotNull ResolutionResultsHandler resolutionResultsHandler) {
|
||||
@@ -96,12 +84,10 @@ public class CallResolver {
|
||||
}
|
||||
|
||||
@Inject
|
||||
public void setDescriptorResolver(@NotNull DescriptorResolver descriptorResolver) {
|
||||
this.descriptorResolver = descriptorResolver;
|
||||
public void setCandidateResolver(@NotNull CandidateResolver candidateResolver) {
|
||||
this.candidateResolver = candidateResolver;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@NotNull
|
||||
public OverloadResolutionResults<VariableDescriptor> resolveSimpleProperty(@NotNull BasicResolutionContext context) {
|
||||
JetExpression calleeExpression = context.call.getCalleeExpression();
|
||||
@@ -122,7 +108,8 @@ public class CallResolver {
|
||||
List<ResolutionTask<VariableDescriptor, VariableDescriptor>> prioritizedTasks =
|
||||
TaskPrioritizer.<VariableDescriptor, VariableDescriptor>computePrioritizedTasks(context, referencedName, nameExpression,
|
||||
callableDescriptorCollectors);
|
||||
return doResolveCallOrGetCachedResults(RESOLUTION_RESULTS_FOR_PROPERTY, context, prioritizedTasks, CallTransformer.PROPERTY_CALL_TRANSFORMER, nameExpression);
|
||||
return doResolveCallOrGetCachedResults(RESOLUTION_RESULTS_FOR_PROPERTY, context, prioritizedTasks,
|
||||
CallTransformer.PROPERTY_CALL_TRANSFORMER, nameExpression);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -337,98 +324,17 @@ public class CallResolver {
|
||||
}
|
||||
continue;
|
||||
}
|
||||
completeTypeInferenceDependentOnExpectedTypeForCall(CallResolutionContext.create(context, tracing, resolvedCall), successful, failed);
|
||||
candidateResolver.completeTypeInferenceDependentOnExpectedTypeForCall(
|
||||
CallResolutionContext.create(context, tracing, resolvedCall), successful, failed);
|
||||
}
|
||||
OverloadResolutionResultsImpl<D> results = resolutionResultsHandler.computeResultAndReportErrors(context.trace, tracing, successful,
|
||||
failed);
|
||||
if (!results.isSingleResult()) {
|
||||
checkTypesWithNoCallee(context);
|
||||
candidateResolver.checkTypesWithNoCallee(context);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
private <D extends CallableDescriptor> void completeTypeInferenceDependentOnExpectedTypeForCall(
|
||||
CallResolutionContext<D, D> context,
|
||||
Set<ResolvedCallWithTrace<D>> successful,
|
||||
Set<ResolvedCallWithTrace<D>> failed
|
||||
) {
|
||||
ResolvedCallImpl<D> resolvedCall = context.candidateCall;
|
||||
assert resolvedCall.hasUnknownTypeParameters();
|
||||
D descriptor = resolvedCall.getCandidateDescriptor();
|
||||
ConstraintSystem constraintSystem = resolvedCall.getConstraintSystem();
|
||||
assert constraintSystem != null;
|
||||
|
||||
TypeSubstitutor substituteDontCare = ConstraintSystemWithPriorities
|
||||
.makeConstantSubstitutor(resolvedCall.getCandidateDescriptor().getTypeParameters(), ConstraintSystemImpl.DONT_CARE);
|
||||
|
||||
// constraints for function literals
|
||||
// Value parameters
|
||||
for (Map.Entry<ValueParameterDescriptor, ResolvedValueArgument> entry : resolvedCall.getValueArguments().entrySet()) {
|
||||
ResolvedValueArgument resolvedValueArgument = entry.getValue();
|
||||
ValueParameterDescriptor valueParameterDescriptor = entry.getKey();
|
||||
|
||||
for (ValueArgument valueArgument : resolvedValueArgument.getArguments()) {
|
||||
if (!JetPsiUtil.isFunctionLiteralWithoutDeclaredParameterTypes(valueArgument.getArgumentExpression())) continue;
|
||||
|
||||
ConstraintSystem systemWithCurrentSubstitution = constraintSystem.copy();
|
||||
addConstraintForValueArgument(valueArgument, valueParameterDescriptor, constraintSystem.getCurrentSubstitutor(),
|
||||
systemWithCurrentSubstitution, context, null);
|
||||
if (systemWithCurrentSubstitution.hasContradiction() || systemWithCurrentSubstitution.hasErrorInConstrainingTypes()) {
|
||||
addConstraintForValueArgument(valueArgument, valueParameterDescriptor, substituteDontCare, constraintSystem, context, null);
|
||||
}
|
||||
else {
|
||||
constraintSystem = systemWithCurrentSubstitution;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ConstraintSystem constraintSystemWithoutExpectedTypeConstraint = constraintSystem.copy();
|
||||
constraintSystem.addSupertypeConstraint(descriptor.getReturnType(), context.expectedType,
|
||||
ConstraintPosition.EXPECTED_TYPE_POSITION);
|
||||
|
||||
|
||||
if (!constraintSystem.isSuccessful()) {
|
||||
resolvedCall.setResultingSubstitutor(constraintSystemWithoutExpectedTypeConstraint.getResultingSubstitutor());
|
||||
List<JetType> argumentTypes = checkValueArgumentTypes(context, resolvedCall, resolvedCall.getTrace()).argumentTypes;
|
||||
JetType receiverType = resolvedCall.getReceiverArgument().exists() ? resolvedCall.getReceiverArgument().getType() : null;
|
||||
context.tracing.typeInferenceFailed(resolvedCall.getTrace(),
|
||||
InferenceErrorData
|
||||
.create(descriptor, constraintSystem, argumentTypes, receiverType,
|
||||
context.expectedType),
|
||||
constraintSystemWithoutExpectedTypeConstraint);
|
||||
resolvedCall.addStatus(ResolutionStatus.TYPE_INFERENCE_ERROR);
|
||||
failed.add(resolvedCall);
|
||||
return;
|
||||
}
|
||||
|
||||
resolvedCall.setResultingSubstitutor(constraintSystem.getResultingSubstitutor());
|
||||
// Here we type check the arguments with inferred types expected
|
||||
checkAllValueArguments(context);
|
||||
|
||||
checkBounds(resolvedCall, constraintSystem, resolvedCall.getTrace(), context.tracing);
|
||||
resolvedCall.setHasUnknownTypeParameters(false);
|
||||
if (resolvedCall.getStatus().isSuccess() || resolvedCall.getStatus() == ResolutionStatus.UNKNOWN_STATUS) {
|
||||
resolvedCall.addStatus(ResolutionStatus.SUCCESS);
|
||||
successful.add(resolvedCall);
|
||||
}
|
||||
else {
|
||||
failed.add(resolvedCall);
|
||||
}
|
||||
}
|
||||
|
||||
private <D extends CallableDescriptor> void checkBounds(
|
||||
@NotNull ResolvedCallImpl<D> call,
|
||||
@NotNull ConstraintSystem constraintSystem,
|
||||
@NotNull BindingTrace trace,
|
||||
@NotNull TracingStrategy tracing
|
||||
) {
|
||||
for (TypeParameterDescriptor typeParameter : call.getCandidateDescriptor().getTypeParameters()) {
|
||||
if (!ConstraintsUtil.checkUpperBoundIsSatisfied(constraintSystem, typeParameter)) {
|
||||
tracing.upperBoundViolated(trace, InferenceErrorData.create(call.getCandidateDescriptor(), constraintSystem));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private <F extends CallableDescriptor> void cacheResults(@NotNull WritableSlice<CallKey, OverloadResolutionResults<F>> resolutionResultsSlice,
|
||||
@NotNull BasicResolutionContext context, @NotNull OverloadResolutionResults<F> results,
|
||||
@NotNull DelegatingBindingTrace traceToResolveCall) {
|
||||
@@ -452,7 +358,7 @@ public class CallResolver {
|
||||
}
|
||||
|
||||
private <D extends CallableDescriptor> OverloadResolutionResults<D> checkArgumentTypesAndFail(BasicResolutionContext context) {
|
||||
checkTypesWithNoCallee(context);
|
||||
candidateResolver.checkTypesWithNoCallee(context);
|
||||
return OverloadResolutionResultsImpl.nameNotFound();
|
||||
}
|
||||
|
||||
@@ -506,7 +412,7 @@ public class CallResolver {
|
||||
}
|
||||
else {
|
||||
context.trace.report(UNRESOLVED_REFERENCE.on(reference));
|
||||
checkTypesWithNoCallee(context);
|
||||
candidateResolver.checkTypesWithNoCallee(context);
|
||||
}
|
||||
return resultsForFirstNonemptyCandidateSet != null ? resultsForFirstNonemptyCandidateSet : OverloadResolutionResultsImpl.<F>nameNotFound();
|
||||
}
|
||||
@@ -571,7 +477,7 @@ public class CallResolver {
|
||||
Collection<CallResolutionContext<D, F>> contexts = callTransformer.createCallContexts(resolutionCandidate, task, candidateTrace);
|
||||
for (CallResolutionContext<D, F> context : contexts) {
|
||||
|
||||
performResolutionForCandidateCall(context, task);
|
||||
candidateResolver.performResolutionForCandidateCall(context, task);
|
||||
|
||||
/* important for 'variable as function case': temporary bind reference to descriptor (will be rewritten)
|
||||
to have a binding to variable while 'invoke' call resolve */
|
||||
@@ -614,443 +520,13 @@ public class CallResolver {
|
||||
successfulCandidates,
|
||||
failedCandidates);
|
||||
if (!results.isSingleResult() && !results.isIncomplete()) {
|
||||
checkTypesWithNoCallee(task.toBasic());
|
||||
candidateResolver.checkTypesWithNoCallee(task.toBasic());
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
private <D extends CallableDescriptor, F extends D> void performResolutionForCandidateCall(@NotNull CallResolutionContext<D, F> context,
|
||||
@NotNull ResolutionTask<D, F> task) {
|
||||
|
||||
ProgressIndicatorProvider.checkCanceled();
|
||||
|
||||
ResolvedCallImpl<D> candidateCall = context.candidateCall;
|
||||
D candidate = candidateCall.getCandidateDescriptor();
|
||||
|
||||
if (ErrorUtils.isError(candidate)) {
|
||||
candidateCall.addStatus(SUCCESS);
|
||||
checkTypesWithNoCallee(context.toBasic());
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Visibilities.isVisible(candidate, context.scope.getContainingDeclaration())) {
|
||||
candidateCall.addStatus(OTHER_ERROR);
|
||||
context.tracing.invisibleMember(context.trace, candidate);
|
||||
return;
|
||||
}
|
||||
|
||||
Set<ValueArgument> unmappedArguments = Sets.newLinkedHashSet();
|
||||
ValueArgumentsToParametersMapper.Status
|
||||
argumentMappingStatus = ValueArgumentsToParametersMapper.mapValueArgumentsToParameters(context.call, context.tracing,
|
||||
candidateCall, unmappedArguments);
|
||||
if (!argumentMappingStatus.isSuccess()) {
|
||||
if (argumentMappingStatus == ValueArgumentsToParametersMapper.Status.STRONG_ERROR) {
|
||||
candidateCall.addStatus(STRONG_ERROR);
|
||||
}
|
||||
else {
|
||||
candidateCall.addStatus(OTHER_ERROR);
|
||||
}
|
||||
if ((argumentMappingStatus == ValueArgumentsToParametersMapper.Status.ERROR && candidate.getTypeParameters().isEmpty()) ||
|
||||
argumentMappingStatus == ValueArgumentsToParametersMapper.Status.STRONG_ERROR) {
|
||||
checkTypesWithNoCallee(context.toBasic());
|
||||
return;
|
||||
}
|
||||
checkUnmappedArgumentTypes(context.toBasic(), unmappedArguments);
|
||||
}
|
||||
|
||||
List<JetTypeProjection> jetTypeArguments = context.call.getTypeArguments();
|
||||
if (jetTypeArguments.isEmpty()) {
|
||||
if (!candidate.getTypeParameters().isEmpty()) {
|
||||
ResolutionStatus status = inferTypeArguments(context);
|
||||
candidateCall.addStatus(status);
|
||||
}
|
||||
else {
|
||||
candidateCall.addStatus(checkAllValueArguments(context).status);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Explicit type arguments passed
|
||||
|
||||
List<JetType> typeArguments = new ArrayList<JetType>();
|
||||
for (JetTypeProjection projection : jetTypeArguments) {
|
||||
if (projection.getProjectionKind() != JetProjectionKind.NONE) {
|
||||
context.trace.report(PROJECTION_ON_NON_CLASS_TYPE_ARGUMENT.on(projection));
|
||||
}
|
||||
JetTypeReference typeReference = projection.getTypeReference();
|
||||
if (typeReference != null) {
|
||||
typeArguments.add(typeResolver.resolveType(context.scope, typeReference, context.trace, true));
|
||||
}
|
||||
else {
|
||||
typeArguments.add(ErrorUtils.createErrorType("Star projection in a call"));
|
||||
}
|
||||
}
|
||||
int expectedTypeArgumentCount = candidate.getTypeParameters().size();
|
||||
if (expectedTypeArgumentCount == jetTypeArguments.size()) {
|
||||
|
||||
checkGenericBoundsInAFunctionCall(jetTypeArguments, typeArguments, candidate, context.trace);
|
||||
|
||||
Map<TypeConstructor, TypeProjection>
|
||||
substitutionContext = FunctionDescriptorUtil.createSubstitutionContext((FunctionDescriptor)candidate, typeArguments);
|
||||
candidateCall.setResultingSubstitutor(TypeSubstitutor.create(substitutionContext));
|
||||
|
||||
List<TypeParameterDescriptor> typeParameters = candidateCall.getCandidateDescriptor().getTypeParameters();
|
||||
for (int i = 0; i < typeParameters.size(); i++) {
|
||||
TypeParameterDescriptor typeParameterDescriptor = typeParameters.get(i);
|
||||
candidateCall.recordTypeArgument(typeParameterDescriptor, typeArguments.get(i));
|
||||
}
|
||||
candidateCall.addStatus(checkAllValueArguments(context).status);
|
||||
}
|
||||
else {
|
||||
candidateCall.addStatus(OTHER_ERROR);
|
||||
context.tracing.wrongNumberOfTypeArguments(context.trace, expectedTypeArgumentCount);
|
||||
}
|
||||
}
|
||||
|
||||
task.performAdvancedChecks(candidate, context.trace, context.tracing);
|
||||
|
||||
// 'super' cannot be passed as an argument, for receiver arguments expression typer does not track this
|
||||
// See TaskPrioritizer for more
|
||||
JetSuperExpression superExpression = TaskPrioritizer.getReceiverSuper(candidateCall.getReceiverArgument());
|
||||
if (superExpression != null) {
|
||||
context.trace.report(SUPER_IS_NOT_AN_EXPRESSION.on(superExpression, superExpression.getText()));
|
||||
candidateCall.addStatus(OTHER_ERROR);
|
||||
}
|
||||
|
||||
recordAutoCastIfNecessary(candidateCall.getReceiverArgument(), candidateCall.getTrace());
|
||||
recordAutoCastIfNecessary(candidateCall.getThisObject(), candidateCall.getTrace());
|
||||
}
|
||||
|
||||
private <D extends CallableDescriptor, F extends D> ResolutionStatus inferTypeArguments(CallResolutionContext<D, F> context) {
|
||||
ResolvedCallImpl<D> candidateCall = context.candidateCall;
|
||||
final D candidate = candidateCall.getCandidateDescriptor();
|
||||
|
||||
ResolutionDebugInfo.Data debugInfo = context.trace.get(ResolutionDebugInfo.RESOLUTION_DEBUG_INFO, context.call.getCallElement());
|
||||
|
||||
ConstraintSystemImpl constraintsSystem = new ConstraintSystemImpl();
|
||||
|
||||
// If the call is recursive, e.g.
|
||||
// fun foo<T>(t : T) : T = foo(t)
|
||||
// we can't use same descriptor objects for T's as actual type values and same T's as unknowns,
|
||||
// because constraints become trivial (T :< T), and inference fails
|
||||
//
|
||||
// Thus, we replace the parameters of our descriptor with fresh objects (perform alpha-conversion)
|
||||
CallableDescriptor candidateWithFreshVariables = FunctionDescriptorUtil.alphaConvertTypeParameters(candidate);
|
||||
|
||||
|
||||
for (TypeParameterDescriptor typeParameterDescriptor : candidateWithFreshVariables.getTypeParameters()) {
|
||||
constraintsSystem.registerTypeVariable(typeParameterDescriptor, Variance.INVARIANT); // TODO: variance of the occurrences
|
||||
}
|
||||
|
||||
TypeSubstitutor substituteDontCare = ConstraintSystemWithPriorities
|
||||
.makeConstantSubstitutor(candidateWithFreshVariables.getTypeParameters(), ConstraintSystemImpl.DONT_CARE);
|
||||
|
||||
// Value parameters
|
||||
for (Map.Entry<ValueParameterDescriptor, ResolvedValueArgument> entry : candidateCall.getValueArguments().entrySet()) {
|
||||
ResolvedValueArgument resolvedValueArgument = entry.getValue();
|
||||
ValueParameterDescriptor valueParameterDescriptor = candidateWithFreshVariables.getValueParameters().get(entry.getKey().getIndex());
|
||||
|
||||
|
||||
for (ValueArgument valueArgument : resolvedValueArgument.getArguments()) {
|
||||
if (JetPsiUtil.isFunctionLiteralWithoutDeclaredParameterTypes(valueArgument.getArgumentExpression())) continue;
|
||||
// TODO : more attempts, with different expected types
|
||||
|
||||
// Here we type check expecting an error type (DONT_CARE, substitution with substituteDontCare)
|
||||
// and throw the results away
|
||||
// We'll type check the arguments later, with the inferred types expected
|
||||
boolean[] isErrorType = new boolean[1];
|
||||
addConstraintForValueArgument(valueArgument, valueParameterDescriptor, substituteDontCare, constraintsSystem,
|
||||
context, isErrorType);
|
||||
if (isErrorType[0]) {
|
||||
candidateCall.argumentHasNoType();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Receiver
|
||||
// Error is already reported if something is missing
|
||||
ReceiverDescriptor receiverArgument = candidateCall.getReceiverArgument();
|
||||
ReceiverDescriptor receiverParameter = candidateWithFreshVariables.getReceiverParameter();
|
||||
if (receiverArgument.exists() && receiverParameter.exists()) {
|
||||
constraintsSystem.addSubtypeConstraint(receiverParameter.getType(), receiverArgument.getType(),
|
||||
ConstraintPosition.RECEIVER_POSITION);
|
||||
}
|
||||
|
||||
ConstraintSystem constraintSystemWithRightTypeParameters = constraintsSystem.replaceTypeVariables(new Function<TypeParameterDescriptor, TypeParameterDescriptor>() {
|
||||
@Override
|
||||
public TypeParameterDescriptor apply(@Nullable TypeParameterDescriptor typeParameterDescriptor) {
|
||||
assert typeParameterDescriptor != null;
|
||||
return candidate.getTypeParameters().get(typeParameterDescriptor.getIndex());
|
||||
}
|
||||
});
|
||||
candidateCall.setConstraintSystem(constraintSystemWithRightTypeParameters);
|
||||
|
||||
|
||||
// Solution
|
||||
boolean hasContradiction = constraintsSystem.hasContradiction();
|
||||
boolean boundsAreSatisfied = ConstraintsUtil.checkBoundsAreSatisfied(constraintsSystem);
|
||||
if (!hasContradiction && boundsAreSatisfied) {
|
||||
candidateCall.setHasUnknownTypeParameters(true);
|
||||
return SUCCESS;
|
||||
}
|
||||
ValueArgumentsCheckingResult checkingResult = checkAllValueArguments(context);
|
||||
ResolutionStatus argumentsStatus = checkingResult.status;
|
||||
List<JetType> argumentTypes = checkingResult.argumentTypes;
|
||||
JetType receiverType = candidateCall.getReceiverArgument().exists() ? candidateCall.getReceiverArgument().getType() : null;
|
||||
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 TYPE_INFERENCE_ERROR.combine(argumentsStatus);
|
||||
}
|
||||
|
||||
private boolean addConstraintForValueArgument(ValueArgument valueArgument,
|
||||
@NotNull ValueParameterDescriptor valueParameterDescriptor,
|
||||
@NotNull TypeSubstitutor substitutor,
|
||||
@NotNull ConstraintSystem constraintSystem,
|
||||
@NotNull ResolutionContext context,
|
||||
@Nullable boolean[] isErrorType) {
|
||||
|
||||
JetType effectiveExpectedType = getEffectiveExpectedType(valueParameterDescriptor, valueArgument);
|
||||
JetExpression argumentExpression = valueArgument.getArgumentExpression();
|
||||
JetType type;
|
||||
if (argumentExpression != null) {
|
||||
TemporaryBindingTrace traceForUnknown = TemporaryBindingTrace.create(
|
||||
context.trace, "transient trace to resolve argument", argumentExpression);
|
||||
type = expressionTypingServices.getType(context.scope, argumentExpression,
|
||||
substitutor.substitute(effectiveExpectedType, Variance.INVARIANT), context.dataFlowInfo, traceForUnknown);
|
||||
}
|
||||
else {
|
||||
type = null;
|
||||
}
|
||||
constraintSystem.addSubtypeConstraint(effectiveExpectedType, type, ConstraintPosition.getValueParameterPosition(
|
||||
valueParameterDescriptor.getIndex()));
|
||||
//todo no return
|
||||
if (isErrorType != null) {
|
||||
isErrorType[0] = type == null || ErrorUtils.isErrorType(type);
|
||||
}
|
||||
if (type == null || ErrorUtils.isErrorType(type)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
private static void recordAutoCastIfNecessary(ReceiverDescriptor receiver, BindingTrace trace) {
|
||||
if (receiver instanceof AutoCastReceiver) {
|
||||
AutoCastReceiver autoCastReceiver = (AutoCastReceiver) receiver;
|
||||
ReceiverDescriptor original = autoCastReceiver.getOriginal();
|
||||
if (original instanceof ExpressionReceiver) {
|
||||
ExpressionReceiver expressionReceiver = (ExpressionReceiver) original;
|
||||
if (autoCastReceiver.canCast()) {
|
||||
trace.record(AUTOCAST, expressionReceiver.getExpression(), autoCastReceiver.getType());
|
||||
trace.record(EXPRESSION_TYPE, expressionReceiver.getExpression(), autoCastReceiver.getType());
|
||||
}
|
||||
else {
|
||||
trace.report(AUTOCAST_IMPOSSIBLE.on(expressionReceiver.getExpression(), autoCastReceiver.getType(), expressionReceiver.getExpression().getText()));
|
||||
}
|
||||
}
|
||||
else {
|
||||
assert autoCastReceiver.canCast() : "A non-expression receiver must always be autocastabe: " + original;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void checkTypesWithNoCallee(BasicResolutionContext context) {
|
||||
for (ValueArgument valueArgument : context.call.getValueArguments()) {
|
||||
JetExpression argumentExpression = valueArgument.getArgumentExpression();
|
||||
if (argumentExpression != null) {
|
||||
expressionTypingServices.getType(context.scope, argumentExpression, NO_EXPECTED_TYPE, context.dataFlowInfo, context.trace);
|
||||
}
|
||||
}
|
||||
|
||||
for (JetExpression expression : context.call.getFunctionLiteralArguments()) {
|
||||
expressionTypingServices.getType(context.scope, expression, NO_EXPECTED_TYPE, context.dataFlowInfo, context.trace);
|
||||
}
|
||||
|
||||
for (JetTypeProjection typeProjection : context.call.getTypeArguments()) {
|
||||
JetTypeReference typeReference = typeProjection.getTypeReference();
|
||||
if (typeReference == null) {
|
||||
context.trace.report(Errors.PROJECTION_ON_NON_CLASS_TYPE_ARGUMENT.on(typeProjection));
|
||||
}
|
||||
else {
|
||||
typeResolver.resolveType(context.scope, typeReference, context.trace, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void checkUnmappedArgumentTypes(BasicResolutionContext context, Set<ValueArgument> unmappedArguments) {
|
||||
for (ValueArgument valueArgument : unmappedArguments) {
|
||||
JetExpression argumentExpression = valueArgument.getArgumentExpression();
|
||||
if (argumentExpression != null) {
|
||||
expressionTypingServices.getType(context.scope, argumentExpression, NO_EXPECTED_TYPE, context.dataFlowInfo, context.trace);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
private <D extends CallableDescriptor, F extends D> ValueArgumentsCheckingResult checkAllValueArguments(CallResolutionContext<D, F> context) {
|
||||
ValueArgumentsCheckingResult checkingResult = checkValueArgumentTypes(context, context.candidateCall, context.candidateCall.getTrace());
|
||||
ResolutionStatus resultStatus = checkingResult.status;
|
||||
ResolvedCall<D> candidateCall = context.candidateCall;
|
||||
|
||||
// Comment about a very special case.
|
||||
// Call 'b.foo(1)' where class 'Foo' has an extension member 'fun B.invoke(Int)' should be checked two times for safe call (in 'checkReceiver'), because
|
||||
// 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, 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);
|
||||
}
|
||||
|
||||
private <D extends CallableDescriptor, F extends D> ResolutionStatus checkReceiver(CallResolutionContext<D, F> context, ResolvedCall<D> candidateCall,
|
||||
ReceiverDescriptor receiverParameter, ReceiverDescriptor receiverArgument,
|
||||
boolean isExplicitReceiver, boolean implicitInvokeCheck) {
|
||||
|
||||
BindingContext bindingContext = context.candidateCall.getTrace().getBindingContext();
|
||||
|
||||
ResolutionStatus result = SUCCESS;
|
||||
if (receiverParameter.exists() && receiverArgument.exists()) {
|
||||
boolean safeAccess = isExplicitReceiver && !implicitInvokeCheck && candidateCall.isSafeCall();
|
||||
JetType receiverArgumentType = receiverArgument.getType();
|
||||
AutoCastServiceImpl autoCastService = new AutoCastServiceImpl(context.dataFlowInfo, bindingContext);
|
||||
if (!safeAccess && !receiverParameter.getType().isNullable() && !autoCastService.isNotNull(receiverArgument)) {
|
||||
|
||||
context.tracing.unsafeCall(context.candidateCall.getTrace(), receiverArgumentType, implicitInvokeCheck);
|
||||
result = UNSAFE_CALL_ERROR;
|
||||
}
|
||||
else {
|
||||
JetType effectiveReceiverArgumentType = safeAccess
|
||||
? TypeUtils.makeNotNullable(receiverArgumentType)
|
||||
: receiverArgumentType;
|
||||
if (!TypeUtils.dependsOnTypeParameters(receiverParameter.getType(),
|
||||
candidateCall.getCandidateDescriptor().getTypeParameters()) &&
|
||||
!typeChecker.isSubtypeOf(effectiveReceiverArgumentType, receiverParameter.getType())) {
|
||||
context.tracing.wrongReceiverType(context.candidateCall.getTrace(), 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);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static class ValueArgumentsCheckingResult {
|
||||
public final List<JetType> argumentTypes;
|
||||
public final ResolutionStatus status;
|
||||
|
||||
private ValueArgumentsCheckingResult(@NotNull ResolutionStatus status, @NotNull List<JetType> argumentTypes) {
|
||||
this.status = status;
|
||||
this.argumentTypes = argumentTypes;
|
||||
}
|
||||
}
|
||||
|
||||
private <D extends CallableDescriptor> ValueArgumentsCheckingResult checkValueArgumentTypes(ResolutionContext context, ResolvedCallImpl<D> candidateCall, BindingTrace trace) {
|
||||
ResolutionStatus resultStatus = SUCCESS;
|
||||
DataFlowInfo dataFlowInfo = context.dataFlowInfo;
|
||||
List<JetType> argumentTypes = Lists.newArrayList();
|
||||
for (Map.Entry<ValueParameterDescriptor, ResolvedValueArgument> entry : candidateCall.getValueArguments().entrySet()) {
|
||||
ValueParameterDescriptor parameterDescriptor = entry.getKey();
|
||||
ResolvedValueArgument resolvedArgument = entry.getValue();
|
||||
|
||||
|
||||
for (ValueArgument argument : resolvedArgument.getArguments()) {
|
||||
JetExpression expression = argument.getArgumentExpression();
|
||||
if (expression == null) continue;
|
||||
|
||||
JetType expectedType = getEffectiveExpectedType(parameterDescriptor, argument);
|
||||
if (TypeUtils.dependsOnTypeParameters(expectedType, candidateCall.getCandidateDescriptor().getTypeParameters())) {
|
||||
expectedType = NO_EXPECTED_TYPE;
|
||||
}
|
||||
JetTypeInfo typeInfo = expressionTypingServices.getTypeInfo(context.scope, expression, expectedType, dataFlowInfo, trace);
|
||||
JetType type = typeInfo.getType();
|
||||
argumentTypes.add(type);
|
||||
dataFlowInfo = dataFlowInfo.and(typeInfo.getDataFlowInfo());
|
||||
if (type == null || ErrorUtils.isErrorType(type)) {
|
||||
candidateCall.argumentHasNoType();
|
||||
}
|
||||
else if (expectedType != NO_EXPECTED_TYPE && !typeChecker.isSubtypeOf(type, expectedType)) {
|
||||
// VariableDescriptor variableDescriptor = AutoCastUtils.getVariableDescriptorFromSimpleName(temporaryTrace.getBindingContext(), argument);
|
||||
// if (variableDescriptor != null) {
|
||||
// JetType autoCastType = null;
|
||||
// for (JetType possibleType : dataFlowInfo.getPossibleTypesForVariable(variableDescriptor)) {
|
||||
// if (semanticServices.getTypeChecker().isSubtypeOf(type, parameterType)) {
|
||||
// autoCastType = possibleType;
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// if (autoCastType != null) {
|
||||
// if (AutoCastUtils.isStableVariable(variableDescriptor)) {
|
||||
// temporaryTrace.record(AUTOCAST, argument, autoCastType);
|
||||
// }
|
||||
// else {
|
||||
// temporaryTrace.report(AUTOCAST_IMPOSSIBLE.on(argument, autoCastType, variableDescriptor));
|
||||
// resultStatus = false;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// else {
|
||||
resultStatus = OTHER_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
return new ValueArgumentsCheckingResult(resultStatus, argumentTypes);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private JetType getEffectiveExpectedType(ValueParameterDescriptor parameterDescriptor, ValueArgument argument) {
|
||||
if (argument.getSpreadElement() != null) {
|
||||
if (parameterDescriptor.getVarargElementType() == null) {
|
||||
// Spread argument passed to a non-vararg parameter, an error is already reported by ValueArgumentsToParametersMapper
|
||||
return ConstraintSystemImpl.DONT_CARE;
|
||||
}
|
||||
else {
|
||||
return parameterDescriptor.getType();
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (argument.isNamed()) {
|
||||
return parameterDescriptor.getType();
|
||||
}
|
||||
else {
|
||||
JetType varargElementType = parameterDescriptor.getVarargElementType();
|
||||
if (varargElementType == null) {
|
||||
return parameterDescriptor.getType();
|
||||
}
|
||||
return varargElementType;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void checkGenericBoundsInAFunctionCall(List<JetTypeProjection> jetTypeArguments, List<JetType> typeArguments, CallableDescriptor functionDescriptor, BindingTrace trace) {
|
||||
Map<TypeConstructor, TypeProjection> context = Maps.newHashMap();
|
||||
|
||||
List<TypeParameterDescriptor> typeParameters = functionDescriptor.getOriginal().getTypeParameters();
|
||||
for (int i = 0, typeParametersSize = typeParameters.size(); i < typeParametersSize; i++) {
|
||||
TypeParameterDescriptor typeParameter = typeParameters.get(i);
|
||||
JetType typeArgument = typeArguments.get(i);
|
||||
context.put(typeParameter.getTypeConstructor(), new TypeProjection(typeArgument));
|
||||
}
|
||||
TypeSubstitutor substitutor = TypeSubstitutor.create(context);
|
||||
for (int i = 0, typeParametersSize = typeParameters.size(); i < typeParametersSize; i++) {
|
||||
TypeParameterDescriptor typeParameterDescriptor = typeParameters.get(i);
|
||||
JetType typeArgument = typeArguments.get(i);
|
||||
JetTypeReference typeReference = jetTypeArguments.get(i).getTypeReference();
|
||||
if (typeReference != null) {
|
||||
descriptorResolver.checkBounds(typeReference, typeArgument, typeParameterDescriptor, substitutor, trace);
|
||||
}
|
||||
}
|
||||
}
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// to be removed
|
||||
|
||||
@Deprecated // Creates wrong resolved calls, should be removed
|
||||
@NotNull
|
||||
|
||||
@@ -0,0 +1,600 @@
|
||||
/*
|
||||
* Copyright 2010-2012 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.jet.lang.resolve.calls;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.intellij.openapi.progress.ProgressIndicatorProvider;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.descriptors.*;
|
||||
import org.jetbrains.jet.lang.diagnostics.Errors;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
import org.jetbrains.jet.lang.resolve.*;
|
||||
import org.jetbrains.jet.lang.resolve.calls.autocasts.*;
|
||||
import org.jetbrains.jet.lang.resolve.calls.inference.*;
|
||||
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.results.ResolutionDebugInfo;
|
||||
import org.jetbrains.jet.lang.resolve.calls.results.ResolutionStatus;
|
||||
import org.jetbrains.jet.lang.resolve.calls.tasks.ResolutionTask;
|
||||
import org.jetbrains.jet.lang.resolve.calls.tasks.TaskPrioritizer;
|
||||
import org.jetbrains.jet.lang.resolve.calls.tasks.TracingStrategy;
|
||||
import org.jetbrains.jet.lang.resolve.scopes.receivers.ExpressionReceiver;
|
||||
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor;
|
||||
import org.jetbrains.jet.lang.types.*;
|
||||
import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
|
||||
import org.jetbrains.jet.lang.types.expressions.ExpressionTypingServices;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.jetbrains.jet.lang.diagnostics.Errors.*;
|
||||
import static org.jetbrains.jet.lang.resolve.BindingContext.AUTOCAST;
|
||||
import static org.jetbrains.jet.lang.resolve.BindingContext.EXPRESSION_TYPE;
|
||||
import static org.jetbrains.jet.lang.resolve.calls.results.ResolutionStatus.*;
|
||||
import static org.jetbrains.jet.lang.types.TypeUtils.NO_EXPECTED_TYPE;
|
||||
|
||||
public class CandidateResolver {
|
||||
@NotNull
|
||||
private final JetTypeChecker typeChecker = JetTypeChecker.INSTANCE;
|
||||
@NotNull
|
||||
private TypeResolver typeResolver;
|
||||
@NotNull
|
||||
private ExpressionTypingServices expressionTypingServices;
|
||||
|
||||
@Inject
|
||||
public void setExpressionTypingServices(@NotNull ExpressionTypingServices expressionTypingServices) {
|
||||
this.expressionTypingServices = expressionTypingServices;
|
||||
}
|
||||
|
||||
@Inject
|
||||
public void setTypeResolver(@NotNull TypeResolver typeResolver) {
|
||||
this.typeResolver = typeResolver;
|
||||
}
|
||||
|
||||
|
||||
public void checkTypesWithNoCallee(@NotNull ResolutionContext context) {
|
||||
for (ValueArgument valueArgument : context.call.getValueArguments()) {
|
||||
JetExpression argumentExpression = valueArgument.getArgumentExpression();
|
||||
if (argumentExpression != null) {
|
||||
expressionTypingServices.getType(context.scope, argumentExpression, NO_EXPECTED_TYPE, context.dataFlowInfo, context.trace);
|
||||
}
|
||||
}
|
||||
|
||||
for (JetExpression expression : context.call.getFunctionLiteralArguments()) {
|
||||
expressionTypingServices.getType(context.scope, expression, NO_EXPECTED_TYPE, context.dataFlowInfo, context.trace);
|
||||
}
|
||||
|
||||
for (JetTypeProjection typeProjection : context.call.getTypeArguments()) {
|
||||
JetTypeReference typeReference = typeProjection.getTypeReference();
|
||||
if (typeReference == null) {
|
||||
context.trace.report(Errors.PROJECTION_ON_NON_CLASS_TYPE_ARGUMENT.on(typeProjection));
|
||||
}
|
||||
else {
|
||||
typeResolver.resolveType(context.scope, typeReference, context.trace, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public <D extends CallableDescriptor, F extends D> void performResolutionForCandidateCall(
|
||||
@NotNull CallResolutionContext<D, F> context,
|
||||
@NotNull ResolutionTask<D, F> task) {
|
||||
|
||||
ProgressIndicatorProvider.checkCanceled();
|
||||
|
||||
ResolvedCallImpl<D> candidateCall = context.candidateCall;
|
||||
D candidate = candidateCall.getCandidateDescriptor();
|
||||
|
||||
if (ErrorUtils.isError(candidate)) {
|
||||
candidateCall.addStatus(SUCCESS);
|
||||
checkTypesWithNoCallee(context.toBasic());
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Visibilities.isVisible(candidate, context.scope.getContainingDeclaration())) {
|
||||
candidateCall.addStatus(OTHER_ERROR);
|
||||
context.tracing.invisibleMember(context.trace, candidate);
|
||||
return;
|
||||
}
|
||||
|
||||
Set<ValueArgument> unmappedArguments = Sets.newLinkedHashSet();
|
||||
ValueArgumentsToParametersMapper.Status
|
||||
argumentMappingStatus = ValueArgumentsToParametersMapper.mapValueArgumentsToParameters(context.call, context.tracing,
|
||||
candidateCall, unmappedArguments);
|
||||
if (!argumentMappingStatus.isSuccess()) {
|
||||
if (argumentMappingStatus == ValueArgumentsToParametersMapper.Status.STRONG_ERROR) {
|
||||
candidateCall.addStatus(STRONG_ERROR);
|
||||
}
|
||||
else {
|
||||
candidateCall.addStatus(OTHER_ERROR);
|
||||
}
|
||||
if ((argumentMappingStatus == ValueArgumentsToParametersMapper.Status.ERROR && candidate.getTypeParameters().isEmpty()) ||
|
||||
argumentMappingStatus == ValueArgumentsToParametersMapper.Status.STRONG_ERROR) {
|
||||
checkTypesWithNoCallee(context.toBasic());
|
||||
return;
|
||||
}
|
||||
checkUnmappedArgumentTypes(context.toBasic(), unmappedArguments);
|
||||
}
|
||||
|
||||
List<JetTypeProjection> jetTypeArguments = context.call.getTypeArguments();
|
||||
if (jetTypeArguments.isEmpty()) {
|
||||
if (!candidate.getTypeParameters().isEmpty()) {
|
||||
ResolutionStatus status = inferTypeArguments(context);
|
||||
candidateCall.addStatus(status);
|
||||
}
|
||||
else {
|
||||
candidateCall.addStatus(checkAllValueArguments(context).status);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Explicit type arguments passed
|
||||
|
||||
List<JetType> typeArguments = new ArrayList<JetType>();
|
||||
for (JetTypeProjection projection : jetTypeArguments) {
|
||||
if (projection.getProjectionKind() != JetProjectionKind.NONE) {
|
||||
context.trace.report(PROJECTION_ON_NON_CLASS_TYPE_ARGUMENT.on(projection));
|
||||
}
|
||||
JetTypeReference typeReference = projection.getTypeReference();
|
||||
if (typeReference != null) {
|
||||
typeArguments.add(typeResolver.resolveType(context.scope, typeReference, context.trace, true));
|
||||
}
|
||||
else {
|
||||
typeArguments.add(ErrorUtils.createErrorType("Star projection in a call"));
|
||||
}
|
||||
}
|
||||
int expectedTypeArgumentCount = candidate.getTypeParameters().size();
|
||||
if (expectedTypeArgumentCount == jetTypeArguments.size()) {
|
||||
|
||||
checkGenericBoundsInAFunctionCall(jetTypeArguments, typeArguments, candidate, context.trace);
|
||||
|
||||
Map<TypeConstructor, TypeProjection>
|
||||
substitutionContext = FunctionDescriptorUtil.createSubstitutionContext((FunctionDescriptor)candidate, typeArguments);
|
||||
candidateCall.setResultingSubstitutor(TypeSubstitutor.create(substitutionContext));
|
||||
|
||||
List<TypeParameterDescriptor> typeParameters = candidateCall.getCandidateDescriptor().getTypeParameters();
|
||||
for (int i = 0; i < typeParameters.size(); i++) {
|
||||
TypeParameterDescriptor typeParameterDescriptor = typeParameters.get(i);
|
||||
candidateCall.recordTypeArgument(typeParameterDescriptor, typeArguments.get(i));
|
||||
}
|
||||
candidateCall.addStatus(checkAllValueArguments(context).status);
|
||||
}
|
||||
else {
|
||||
candidateCall.addStatus(OTHER_ERROR);
|
||||
context.tracing.wrongNumberOfTypeArguments(context.trace, expectedTypeArgumentCount);
|
||||
}
|
||||
}
|
||||
|
||||
task.performAdvancedChecks(candidate, context.trace, context.tracing);
|
||||
|
||||
// 'super' cannot be passed as an argument, for receiver arguments expression typer does not track this
|
||||
// See TaskPrioritizer for more
|
||||
JetSuperExpression superExpression = TaskPrioritizer.getReceiverSuper(candidateCall.getReceiverArgument());
|
||||
if (superExpression != null) {
|
||||
context.trace.report(SUPER_IS_NOT_AN_EXPRESSION.on(superExpression, superExpression.getText()));
|
||||
candidateCall.addStatus(OTHER_ERROR);
|
||||
}
|
||||
|
||||
recordAutoCastIfNecessary(candidateCall.getReceiverArgument(), candidateCall.getTrace());
|
||||
recordAutoCastIfNecessary(candidateCall.getThisObject(), candidateCall.getTrace());
|
||||
}
|
||||
|
||||
public <D extends CallableDescriptor> void completeTypeInferenceDependentOnExpectedTypeForCall(
|
||||
CallResolutionContext<D, D> context,
|
||||
Set<ResolvedCallWithTrace<D>> successful,
|
||||
Set<ResolvedCallWithTrace<D>> failed
|
||||
) {
|
||||
ResolvedCallImpl<D> resolvedCall = context.candidateCall;
|
||||
assert resolvedCall.hasUnknownTypeParameters();
|
||||
D descriptor = resolvedCall.getCandidateDescriptor();
|
||||
ConstraintSystem constraintSystem = resolvedCall.getConstraintSystem();
|
||||
assert constraintSystem != null;
|
||||
|
||||
TypeSubstitutor substituteDontCare = ConstraintSystemWithPriorities
|
||||
.makeConstantSubstitutor(resolvedCall.getCandidateDescriptor().getTypeParameters(), ConstraintSystemImpl.DONT_CARE);
|
||||
|
||||
// constraints for function literals
|
||||
// Value parameters
|
||||
for (Map.Entry<ValueParameterDescriptor, ResolvedValueArgument> entry : resolvedCall.getValueArguments().entrySet()) {
|
||||
ResolvedValueArgument resolvedValueArgument = entry.getValue();
|
||||
ValueParameterDescriptor valueParameterDescriptor = entry.getKey();
|
||||
|
||||
for (ValueArgument valueArgument : resolvedValueArgument.getArguments()) {
|
||||
if (!JetPsiUtil.isFunctionLiteralWithoutDeclaredParameterTypes(valueArgument.getArgumentExpression())) continue;
|
||||
|
||||
ConstraintSystem systemWithCurrentSubstitution = constraintSystem.copy();
|
||||
addConstraintForValueArgument(valueArgument, valueParameterDescriptor, constraintSystem.getCurrentSubstitutor(),
|
||||
systemWithCurrentSubstitution, context, null);
|
||||
if (systemWithCurrentSubstitution.hasContradiction() || systemWithCurrentSubstitution.hasErrorInConstrainingTypes()) {
|
||||
addConstraintForValueArgument(valueArgument, valueParameterDescriptor, substituteDontCare, constraintSystem, context, null);
|
||||
}
|
||||
else {
|
||||
constraintSystem = systemWithCurrentSubstitution;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ConstraintSystem constraintSystemWithoutExpectedTypeConstraint = constraintSystem.copy();
|
||||
constraintSystem.addSupertypeConstraint(descriptor.getReturnType(), context.expectedType,
|
||||
ConstraintPosition.EXPECTED_TYPE_POSITION);
|
||||
|
||||
|
||||
if (!constraintSystem.isSuccessful()) {
|
||||
resolvedCall.setResultingSubstitutor(constraintSystemWithoutExpectedTypeConstraint.getResultingSubstitutor());
|
||||
List<JetType> argumentTypes = checkValueArgumentTypes(context, resolvedCall, resolvedCall.getTrace()).argumentTypes;
|
||||
JetType receiverType = resolvedCall.getReceiverArgument().exists() ? resolvedCall.getReceiverArgument().getType() : null;
|
||||
context.tracing.typeInferenceFailed(resolvedCall.getTrace(),
|
||||
InferenceErrorData
|
||||
.create(descriptor, constraintSystem, argumentTypes, receiverType,
|
||||
context.expectedType),
|
||||
constraintSystemWithoutExpectedTypeConstraint);
|
||||
resolvedCall.addStatus(ResolutionStatus.TYPE_INFERENCE_ERROR);
|
||||
failed.add(resolvedCall);
|
||||
return;
|
||||
}
|
||||
|
||||
resolvedCall.setResultingSubstitutor(constraintSystem.getResultingSubstitutor());
|
||||
// Here we type check the arguments with inferred types expected
|
||||
checkAllValueArguments(context);
|
||||
|
||||
checkBounds(resolvedCall, constraintSystem, resolvedCall.getTrace(), context.tracing);
|
||||
resolvedCall.setHasUnknownTypeParameters(false);
|
||||
if (resolvedCall.getStatus().isSuccess() || resolvedCall.getStatus() == ResolutionStatus.UNKNOWN_STATUS) {
|
||||
resolvedCall.addStatus(ResolutionStatus.SUCCESS);
|
||||
successful.add(resolvedCall);
|
||||
}
|
||||
else {
|
||||
failed.add(resolvedCall);
|
||||
}
|
||||
}
|
||||
|
||||
private <D extends CallableDescriptor, F extends D> ResolutionStatus inferTypeArguments(CallResolutionContext<D, F> context) {
|
||||
ResolvedCallImpl<D> candidateCall = context.candidateCall;
|
||||
final D candidate = candidateCall.getCandidateDescriptor();
|
||||
|
||||
context.trace.get(ResolutionDebugInfo.RESOLUTION_DEBUG_INFO, context.call.getCallElement());
|
||||
|
||||
ConstraintSystemImpl constraintsSystem = new ConstraintSystemImpl();
|
||||
|
||||
// If the call is recursive, e.g.
|
||||
// fun foo<T>(t : T) : T = foo(t)
|
||||
// we can't use same descriptor objects for T's as actual type values and same T's as unknowns,
|
||||
// because constraints become trivial (T :< T), and inference fails
|
||||
//
|
||||
// Thus, we replace the parameters of our descriptor with fresh objects (perform alpha-conversion)
|
||||
CallableDescriptor candidateWithFreshVariables = FunctionDescriptorUtil.alphaConvertTypeParameters(candidate);
|
||||
|
||||
|
||||
for (TypeParameterDescriptor typeParameterDescriptor : candidateWithFreshVariables.getTypeParameters()) {
|
||||
constraintsSystem.registerTypeVariable(typeParameterDescriptor, Variance.INVARIANT); // TODO: variance of the occurrences
|
||||
}
|
||||
|
||||
TypeSubstitutor substituteDontCare = ConstraintSystemWithPriorities
|
||||
.makeConstantSubstitutor(candidateWithFreshVariables.getTypeParameters(), ConstraintSystemImpl.DONT_CARE);
|
||||
|
||||
// Value parameters
|
||||
for (Map.Entry<ValueParameterDescriptor, ResolvedValueArgument> entry : candidateCall.getValueArguments().entrySet()) {
|
||||
ResolvedValueArgument resolvedValueArgument = entry.getValue();
|
||||
ValueParameterDescriptor valueParameterDescriptor = candidateWithFreshVariables.getValueParameters().get(entry.getKey().getIndex());
|
||||
|
||||
|
||||
for (ValueArgument valueArgument : resolvedValueArgument.getArguments()) {
|
||||
if (JetPsiUtil.isFunctionLiteralWithoutDeclaredParameterTypes(valueArgument.getArgumentExpression())) continue;
|
||||
// TODO : more attempts, with different expected types
|
||||
|
||||
// Here we type check expecting an error type (DONT_CARE, substitution with substituteDontCare)
|
||||
// and throw the results away
|
||||
// We'll type check the arguments later, with the inferred types expected
|
||||
boolean[] isErrorType = new boolean[1];
|
||||
addConstraintForValueArgument(valueArgument, valueParameterDescriptor, substituteDontCare, constraintsSystem,
|
||||
context, isErrorType);
|
||||
if (isErrorType[0]) {
|
||||
candidateCall.argumentHasNoType();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Receiver
|
||||
// Error is already reported if something is missing
|
||||
ReceiverDescriptor receiverArgument = candidateCall.getReceiverArgument();
|
||||
ReceiverDescriptor receiverParameter = candidateWithFreshVariables.getReceiverParameter();
|
||||
if (receiverArgument.exists() && receiverParameter.exists()) {
|
||||
constraintsSystem.addSubtypeConstraint(receiverParameter.getType(), receiverArgument.getType(),
|
||||
ConstraintPosition.RECEIVER_POSITION);
|
||||
}
|
||||
|
||||
ConstraintSystem
|
||||
constraintSystemWithRightTypeParameters = constraintsSystem.replaceTypeVariables(new Function<TypeParameterDescriptor, TypeParameterDescriptor>() {
|
||||
@Override
|
||||
public TypeParameterDescriptor apply(@Nullable TypeParameterDescriptor typeParameterDescriptor) {
|
||||
assert typeParameterDescriptor != null;
|
||||
return candidate.getTypeParameters().get(typeParameterDescriptor.getIndex());
|
||||
}
|
||||
});
|
||||
candidateCall.setConstraintSystem(constraintSystemWithRightTypeParameters);
|
||||
|
||||
|
||||
// Solution
|
||||
boolean hasContradiction = constraintsSystem.hasContradiction();
|
||||
boolean boundsAreSatisfied = ConstraintsUtil.checkBoundsAreSatisfied(constraintsSystem);
|
||||
if (!hasContradiction && boundsAreSatisfied) {
|
||||
candidateCall.setHasUnknownTypeParameters(true);
|
||||
return SUCCESS;
|
||||
}
|
||||
ValueArgumentsCheckingResult checkingResult = checkAllValueArguments(context);
|
||||
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 TYPE_INFERENCE_ERROR.combine(argumentsStatus);
|
||||
}
|
||||
|
||||
private void addConstraintForValueArgument(
|
||||
@NotNull ValueArgument valueArgument,
|
||||
@NotNull ValueParameterDescriptor valueParameterDescriptor,
|
||||
@NotNull TypeSubstitutor substitutor,
|
||||
@NotNull ConstraintSystem constraintSystem,
|
||||
@NotNull ResolutionContext context,
|
||||
@Nullable boolean[] isErrorType) {
|
||||
|
||||
JetType effectiveExpectedType = getEffectiveExpectedType(valueParameterDescriptor, valueArgument);
|
||||
JetExpression argumentExpression = valueArgument.getArgumentExpression();
|
||||
JetType type;
|
||||
if (argumentExpression != null) {
|
||||
TemporaryBindingTrace traceForUnknown = TemporaryBindingTrace.create(
|
||||
context.trace, "transient trace to resolve argument", argumentExpression);
|
||||
type = expressionTypingServices.getType(context.scope, argumentExpression,
|
||||
substitutor.substitute(effectiveExpectedType, Variance.INVARIANT), context.dataFlowInfo, traceForUnknown);
|
||||
}
|
||||
else {
|
||||
type = null;
|
||||
}
|
||||
constraintSystem.addSubtypeConstraint(effectiveExpectedType, type, ConstraintPosition.getValueParameterPosition(
|
||||
valueParameterDescriptor.getIndex()));
|
||||
//todo no return
|
||||
if (isErrorType != null) {
|
||||
isErrorType[0] = type == null || ErrorUtils.isErrorType(type);
|
||||
}
|
||||
}
|
||||
|
||||
private <D extends CallableDescriptor, F extends D> ValueArgumentsCheckingResult checkAllValueArguments(CallResolutionContext<D, F> context) {
|
||||
ValueArgumentsCheckingResult checkingResult = checkValueArgumentTypes(context, context.candidateCall, context.candidateCall.getTrace());
|
||||
ResolutionStatus resultStatus = checkingResult.status;
|
||||
ResolvedCall<D> candidateCall = context.candidateCall;
|
||||
|
||||
// Comment about a very special case.
|
||||
// Call 'b.foo(1)' where class 'Foo' has an extension member 'fun B.invoke(Int)' should be checked two times for safe call (in 'checkReceiver'), because
|
||||
// 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, 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);
|
||||
}
|
||||
|
||||
private <D extends CallableDescriptor> ValueArgumentsCheckingResult checkValueArgumentTypes(
|
||||
@NotNull ResolutionContext context,
|
||||
@NotNull ResolvedCallImpl<D> candidateCall,
|
||||
@NotNull BindingTrace trace) {
|
||||
ResolutionStatus resultStatus = SUCCESS;
|
||||
DataFlowInfo dataFlowInfo = context.dataFlowInfo;
|
||||
List<JetType> argumentTypes = Lists.newArrayList();
|
||||
for (Map.Entry<ValueParameterDescriptor, ResolvedValueArgument> entry : candidateCall.getValueArguments().entrySet()) {
|
||||
ValueParameterDescriptor parameterDescriptor = entry.getKey();
|
||||
ResolvedValueArgument resolvedArgument = entry.getValue();
|
||||
|
||||
|
||||
for (ValueArgument argument : resolvedArgument.getArguments()) {
|
||||
JetExpression expression = argument.getArgumentExpression();
|
||||
if (expression == null) continue;
|
||||
|
||||
JetType expectedType = getEffectiveExpectedType(parameterDescriptor, argument);
|
||||
if (TypeUtils.dependsOnTypeParameters(expectedType, candidateCall.getCandidateDescriptor().getTypeParameters())) {
|
||||
expectedType = NO_EXPECTED_TYPE;
|
||||
}
|
||||
JetTypeInfo typeInfo = expressionTypingServices.getTypeInfo(context.scope, expression, expectedType, dataFlowInfo, trace);
|
||||
JetType type = typeInfo.getType();
|
||||
argumentTypes.add(type);
|
||||
dataFlowInfo = dataFlowInfo.and(typeInfo.getDataFlowInfo());
|
||||
if (type == null || ErrorUtils.isErrorType(type)) {
|
||||
candidateCall.argumentHasNoType();
|
||||
}
|
||||
else if (expectedType != NO_EXPECTED_TYPE && !typeChecker.isSubtypeOf(type, expectedType)) {
|
||||
// VariableDescriptor variableDescriptor = AutoCastUtils.getVariableDescriptorFromSimpleName(temporaryTrace.getBindingContext(), argument);
|
||||
// if (variableDescriptor != null) {
|
||||
// JetType autoCastType = null;
|
||||
// for (JetType possibleType : dataFlowInfo.getPossibleTypesForVariable(variableDescriptor)) {
|
||||
// if (semanticServices.getTypeChecker().isSubtypeOf(type, parameterType)) {
|
||||
// autoCastType = possibleType;
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// if (autoCastType != null) {
|
||||
// if (AutoCastUtils.isStableVariable(variableDescriptor)) {
|
||||
// temporaryTrace.record(AUTOCAST, argument, autoCastType);
|
||||
// }
|
||||
// else {
|
||||
// temporaryTrace.report(AUTOCAST_IMPOSSIBLE.on(argument, autoCastType, variableDescriptor));
|
||||
// resultStatus = false;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// else {
|
||||
resultStatus = OTHER_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
return new ValueArgumentsCheckingResult(resultStatus, argumentTypes);
|
||||
}
|
||||
|
||||
private void checkUnmappedArgumentTypes(ResolutionContext context, Set<ValueArgument> unmappedArguments) {
|
||||
for (ValueArgument valueArgument : unmappedArguments) {
|
||||
JetExpression argumentExpression = valueArgument.getArgumentExpression();
|
||||
if (argumentExpression != null) {
|
||||
expressionTypingServices.getType(context.scope, argumentExpression, NO_EXPECTED_TYPE, context.dataFlowInfo, context.trace);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private <D extends CallableDescriptor, F extends D> ResolutionStatus checkReceiver(CallResolutionContext<D, F> context, ResolvedCall<D> candidateCall,
|
||||
ReceiverDescriptor receiverParameter, ReceiverDescriptor receiverArgument,
|
||||
boolean isExplicitReceiver, boolean implicitInvokeCheck) {
|
||||
|
||||
BindingContext bindingContext = context.candidateCall.getTrace().getBindingContext();
|
||||
|
||||
ResolutionStatus result = SUCCESS;
|
||||
if (receiverParameter.exists() && receiverArgument.exists()) {
|
||||
boolean safeAccess = isExplicitReceiver && !implicitInvokeCheck && candidateCall.isSafeCall();
|
||||
JetType receiverArgumentType = receiverArgument.getType();
|
||||
AutoCastServiceImpl autoCastService = new AutoCastServiceImpl(context.dataFlowInfo, bindingContext);
|
||||
if (!safeAccess && !receiverParameter.getType().isNullable() && !autoCastService.isNotNull(receiverArgument)) {
|
||||
|
||||
context.tracing.unsafeCall(context.candidateCall.getTrace(), receiverArgumentType, implicitInvokeCheck);
|
||||
result = UNSAFE_CALL_ERROR;
|
||||
}
|
||||
else {
|
||||
JetType effectiveReceiverArgumentType = safeAccess
|
||||
? TypeUtils.makeNotNullable(receiverArgumentType)
|
||||
: receiverArgumentType;
|
||||
if (!TypeUtils.dependsOnTypeParameters(receiverParameter.getType(),
|
||||
candidateCall.getCandidateDescriptor().getTypeParameters()) &&
|
||||
!typeChecker.isSubtypeOf(effectiveReceiverArgumentType, receiverParameter.getType())) {
|
||||
context.tracing.wrongReceiverType(context.candidateCall.getTrace(), 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);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static class ValueArgumentsCheckingResult {
|
||||
|
||||
public final List<JetType> argumentTypes;
|
||||
public final ResolutionStatus status;
|
||||
|
||||
private ValueArgumentsCheckingResult(@NotNull ResolutionStatus status, @NotNull List<JetType> argumentTypes) {
|
||||
this.status = status;
|
||||
this.argumentTypes = argumentTypes;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static void recordAutoCastIfNecessary(ReceiverDescriptor receiver, BindingTrace trace) {
|
||||
if (receiver instanceof AutoCastReceiver) {
|
||||
AutoCastReceiver autoCastReceiver = (AutoCastReceiver) receiver;
|
||||
ReceiverDescriptor original = autoCastReceiver.getOriginal();
|
||||
if (original instanceof ExpressionReceiver) {
|
||||
ExpressionReceiver expressionReceiver = (ExpressionReceiver) original;
|
||||
if (autoCastReceiver.canCast()) {
|
||||
trace.record(AUTOCAST, expressionReceiver.getExpression(), autoCastReceiver.getType());
|
||||
trace.record(EXPRESSION_TYPE, expressionReceiver.getExpression(), autoCastReceiver.getType());
|
||||
}
|
||||
else {
|
||||
trace.report(AUTOCAST_IMPOSSIBLE.on(expressionReceiver.getExpression(), autoCastReceiver.getType(), expressionReceiver.getExpression().getText()));
|
||||
}
|
||||
}
|
||||
else {
|
||||
assert autoCastReceiver.canCast() : "A non-expression receiver must always be autocastabe: " + original;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static JetType getEffectiveExpectedType(ValueParameterDescriptor parameterDescriptor, ValueArgument argument) {
|
||||
if (argument.getSpreadElement() != null) {
|
||||
if (parameterDescriptor.getVarargElementType() == null) {
|
||||
// Spread argument passed to a non-vararg parameter, an error is already reported by ValueArgumentsToParametersMapper
|
||||
return ConstraintSystemImpl.DONT_CARE;
|
||||
}
|
||||
else {
|
||||
return parameterDescriptor.getType();
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (argument.isNamed()) {
|
||||
return parameterDescriptor.getType();
|
||||
}
|
||||
else {
|
||||
JetType varargElementType = parameterDescriptor.getVarargElementType();
|
||||
if (varargElementType == null) {
|
||||
return parameterDescriptor.getType();
|
||||
}
|
||||
return varargElementType;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static <D extends CallableDescriptor> void checkBounds(
|
||||
@NotNull ResolvedCallImpl<D> call,
|
||||
@NotNull ConstraintSystem constraintSystem,
|
||||
@NotNull BindingTrace trace,
|
||||
@NotNull TracingStrategy tracing
|
||||
) {
|
||||
for (TypeParameterDescriptor typeParameter : call.getCandidateDescriptor().getTypeParameters()) {
|
||||
if (!ConstraintsUtil.checkUpperBoundIsSatisfied(constraintSystem, typeParameter)) {
|
||||
tracing.upperBoundViolated(trace, InferenceErrorData.create(call.getCandidateDescriptor(), constraintSystem));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void checkGenericBoundsInAFunctionCall(
|
||||
@NotNull List<JetTypeProjection> jetTypeArguments,
|
||||
@NotNull List<JetType> typeArguments,
|
||||
@NotNull CallableDescriptor functionDescriptor,
|
||||
@NotNull BindingTrace trace) {
|
||||
Map<TypeConstructor, TypeProjection> context = Maps.newHashMap();
|
||||
|
||||
List<TypeParameterDescriptor> typeParameters = functionDescriptor.getOriginal().getTypeParameters();
|
||||
for (int i = 0, typeParametersSize = typeParameters.size(); i < typeParametersSize; i++) {
|
||||
TypeParameterDescriptor typeParameter = typeParameters.get(i);
|
||||
JetType typeArgument = typeArguments.get(i);
|
||||
context.put(typeParameter.getTypeConstructor(), new TypeProjection(typeArgument));
|
||||
}
|
||||
TypeSubstitutor substitutor = TypeSubstitutor.create(context);
|
||||
for (int i = 0, typeParametersSize = typeParameters.size(); i < typeParametersSize; i++) {
|
||||
TypeParameterDescriptor typeParameterDescriptor = typeParameters.get(i);
|
||||
JetType typeArgument = typeArguments.get(i);
|
||||
JetTypeReference typeReference = jetTypeArguments.get(i).getTypeReference();
|
||||
if (typeReference != null) {
|
||||
DescriptorResolver.checkBounds(typeReference, typeArgument, typeParameterDescriptor, substitutor, trace);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -26,6 +26,7 @@ import org.jetbrains.jet.lang.ModuleConfiguration;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import org.jetbrains.jet.lang.resolve.AnnotationResolver;
|
||||
import org.jetbrains.jet.lang.resolve.QualifiedExpressionResolver;
|
||||
import org.jetbrains.jet.lang.resolve.calls.CandidateResolver;
|
||||
import org.jetbrains.jet.lang.resolve.calls.results.ResolutionResultsHandler;
|
||||
import org.jetbrains.jet.lang.resolve.calls.results.OverloadingConflictResolver;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -43,6 +44,7 @@ public class InjectorForTests {
|
||||
private final Project project;
|
||||
private AnnotationResolver annotationResolver;
|
||||
private QualifiedExpressionResolver qualifiedExpressionResolver;
|
||||
private CandidateResolver candidateResolver;
|
||||
private ResolutionResultsHandler resolutionResultsHandler;
|
||||
private OverloadingConflictResolver overloadingConflictResolver;
|
||||
|
||||
@@ -58,6 +60,7 @@ public class InjectorForTests {
|
||||
this.project = project;
|
||||
this.annotationResolver = new AnnotationResolver();
|
||||
this.qualifiedExpressionResolver = new QualifiedExpressionResolver();
|
||||
this.candidateResolver = new CandidateResolver();
|
||||
this.resolutionResultsHandler = new ResolutionResultsHandler();
|
||||
this.overloadingConflictResolver = new OverloadingConflictResolver();
|
||||
|
||||
@@ -75,7 +78,7 @@ public class InjectorForTests {
|
||||
this.typeResolver.setModuleConfiguration(moduleConfiguration);
|
||||
this.typeResolver.setQualifiedExpressionResolver(qualifiedExpressionResolver);
|
||||
|
||||
this.callResolver.setDescriptorResolver(descriptorResolver);
|
||||
this.callResolver.setCandidateResolver(candidateResolver);
|
||||
this.callResolver.setExpressionTypingServices(expressionTypingServices);
|
||||
this.callResolver.setResolutionResultsHandler(resolutionResultsHandler);
|
||||
this.callResolver.setTypeResolver(typeResolver);
|
||||
@@ -83,6 +86,9 @@ public class InjectorForTests {
|
||||
annotationResolver.setCallResolver(callResolver);
|
||||
annotationResolver.setExpressionTypingServices(expressionTypingServices);
|
||||
|
||||
candidateResolver.setExpressionTypingServices(expressionTypingServices);
|
||||
candidateResolver.setTypeResolver(typeResolver);
|
||||
|
||||
resolutionResultsHandler.setOverloadingConflictResolver(overloadingConflictResolver);
|
||||
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@ import org.jetbrains.jet.lang.resolve.NamespaceFactoryImpl;
|
||||
import org.jetbrains.jet.lang.resolve.DeclarationResolver;
|
||||
import org.jetbrains.jet.lang.resolve.AnnotationResolver;
|
||||
import org.jetbrains.jet.lang.resolve.calls.CallResolver;
|
||||
import org.jetbrains.jet.lang.resolve.calls.CandidateResolver;
|
||||
import org.jetbrains.jet.lang.types.expressions.ExpressionTypingServices;
|
||||
import org.jetbrains.jet.lang.resolve.TypeResolver;
|
||||
import org.jetbrains.jet.lang.resolve.QualifiedExpressionResolver;
|
||||
@@ -66,6 +67,7 @@ public class InjectorForTopDownAnalyzerForJs {
|
||||
private DeclarationResolver declarationResolver;
|
||||
private AnnotationResolver annotationResolver;
|
||||
private CallResolver callResolver;
|
||||
private CandidateResolver candidateResolver;
|
||||
private ExpressionTypingServices expressionTypingServices;
|
||||
private TypeResolver typeResolver;
|
||||
private QualifiedExpressionResolver qualifiedExpressionResolver;
|
||||
@@ -101,6 +103,7 @@ public class InjectorForTopDownAnalyzerForJs {
|
||||
this.declarationResolver = new DeclarationResolver();
|
||||
this.annotationResolver = new AnnotationResolver();
|
||||
this.callResolver = new CallResolver();
|
||||
this.candidateResolver = new CandidateResolver();
|
||||
this.expressionTypingServices = new ExpressionTypingServices();
|
||||
this.typeResolver = new TypeResolver();
|
||||
this.qualifiedExpressionResolver = new QualifiedExpressionResolver();
|
||||
@@ -159,11 +162,14 @@ public class InjectorForTopDownAnalyzerForJs {
|
||||
annotationResolver.setCallResolver(callResolver);
|
||||
annotationResolver.setExpressionTypingServices(expressionTypingServices);
|
||||
|
||||
callResolver.setDescriptorResolver(descriptorResolver);
|
||||
callResolver.setCandidateResolver(candidateResolver);
|
||||
callResolver.setExpressionTypingServices(expressionTypingServices);
|
||||
callResolver.setResolutionResultsHandler(resolutionResultsHandler);
|
||||
callResolver.setTypeResolver(typeResolver);
|
||||
|
||||
candidateResolver.setExpressionTypingServices(expressionTypingServices);
|
||||
candidateResolver.setTypeResolver(typeResolver);
|
||||
|
||||
expressionTypingServices.setCallResolver(callResolver);
|
||||
expressionTypingServices.setDescriptorResolver(descriptorResolver);
|
||||
expressionTypingServices.setProject(project);
|
||||
|
||||
Reference in New Issue
Block a user