added CandidateResolver

(that took some methods from CallResolver)
This commit is contained in:
Svetlana Isakova
2012-10-29 15:13:16 +04:00
parent fc705edb65
commit f90f72a6ec
9 changed files with 683 additions and 565 deletions
@@ -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);