diff --git a/compiler/frontend.java/src/org/jetbrains/jet/di/InjectorForTopDownAnalyzerForJvm.java b/compiler/frontend.java/src/org/jetbrains/jet/di/InjectorForTopDownAnalyzerForJvm.java index 911fce1cecc..e50dffc1a13 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/di/InjectorForTopDownAnalyzerForJvm.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/di/InjectorForTopDownAnalyzerForJvm.java @@ -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); diff --git a/compiler/frontend/src/org/jetbrains/jet/di/InjectorForBodyResolve.java b/compiler/frontend/src/org/jetbrains/jet/di/InjectorForBodyResolve.java index 7524f66d23f..4e5cea44728 100644 --- a/compiler/frontend/src/org/jetbrains/jet/di/InjectorForBodyResolve.java +++ b/compiler/frontend/src/org/jetbrains/jet/di/InjectorForBodyResolve.java @@ -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); diff --git a/compiler/frontend/src/org/jetbrains/jet/di/InjectorForLazyResolve.java b/compiler/frontend/src/org/jetbrains/jet/di/InjectorForLazyResolve.java index 242aa643e3d..d49ecf829e4 100644 --- a/compiler/frontend/src/org/jetbrains/jet/di/InjectorForLazyResolve.java +++ b/compiler/frontend/src/org/jetbrains/jet/di/InjectorForLazyResolve.java @@ -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); } diff --git a/compiler/frontend/src/org/jetbrains/jet/di/InjectorForMacros.java b/compiler/frontend/src/org/jetbrains/jet/di/InjectorForMacros.java index 635ef5c643d..8532ad9dcc9 100644 --- a/compiler/frontend/src/org/jetbrains/jet/di/InjectorForMacros.java +++ b/compiler/frontend/src/org/jetbrains/jet/di/InjectorForMacros.java @@ -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); } diff --git a/compiler/frontend/src/org/jetbrains/jet/di/InjectorForTopDownAnalyzerBasic.java b/compiler/frontend/src/org/jetbrains/jet/di/InjectorForTopDownAnalyzerBasic.java index 404c87a923f..f442bf874b7 100644 --- a/compiler/frontend/src/org/jetbrains/jet/di/InjectorForTopDownAnalyzerBasic.java +++ b/compiler/frontend/src/org/jetbrains/jet/di/InjectorForTopDownAnalyzerBasic.java @@ -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); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java index 2114a2744ab..482c8b159e0 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolver.java @@ -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 resolveSimpleProperty(@NotNull BasicResolutionContext context) { JetExpression calleeExpression = context.call.getCalleeExpression(); @@ -122,7 +108,8 @@ public class CallResolver { List> prioritizedTasks = TaskPrioritizer.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 results = resolutionResultsHandler.computeResultAndReportErrors(context.trace, tracing, successful, failed); if (!results.isSingleResult()) { - checkTypesWithNoCallee(context); + candidateResolver.checkTypesWithNoCallee(context); } return results; } - private void completeTypeInferenceDependentOnExpectedTypeForCall( - CallResolutionContext context, - Set> successful, - Set> failed - ) { - ResolvedCallImpl 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 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 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 void checkBounds( - @NotNull ResolvedCallImpl 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 void cacheResults(@NotNull WritableSlice> resolutionResultsSlice, @NotNull BasicResolutionContext context, @NotNull OverloadResolutionResults results, @NotNull DelegatingBindingTrace traceToResolveCall) { @@ -452,7 +358,7 @@ public class CallResolver { } private OverloadResolutionResults 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.nameNotFound(); } @@ -571,7 +477,7 @@ public class CallResolver { Collection> contexts = callTransformer.createCallContexts(resolutionCandidate, task, candidateTrace); for (CallResolutionContext 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 void performResolutionForCandidateCall(@NotNull CallResolutionContext context, - @NotNull ResolutionTask task) { - - ProgressIndicatorProvider.checkCanceled(); - - ResolvedCallImpl 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 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 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 typeArguments = new ArrayList(); - 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 - substitutionContext = FunctionDescriptorUtil.createSubstitutionContext((FunctionDescriptor)candidate, typeArguments); - candidateCall.setResultingSubstitutor(TypeSubstitutor.create(substitutionContext)); - - List 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 ResolutionStatus inferTypeArguments(CallResolutionContext context) { - ResolvedCallImpl 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 = 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 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() { - @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 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 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 ValueArgumentsCheckingResult checkAllValueArguments(CallResolutionContext context) { - ValueArgumentsCheckingResult checkingResult = checkValueArgumentTypes(context, context.candidateCall, context.candidateCall.getTrace()); - ResolutionStatus resultStatus = checkingResult.status; - ResolvedCall 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 ResolutionStatus checkReceiver(CallResolutionContext context, ResolvedCall 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 argumentTypes; - public final ResolutionStatus status; - - private ValueArgumentsCheckingResult(@NotNull ResolutionStatus status, @NotNull List argumentTypes) { - this.status = status; - this.argumentTypes = argumentTypes; - } - } - - private ValueArgumentsCheckingResult checkValueArgumentTypes(ResolutionContext context, ResolvedCallImpl candidateCall, BindingTrace trace) { - ResolutionStatus resultStatus = SUCCESS; - DataFlowInfo dataFlowInfo = context.dataFlowInfo; - List argumentTypes = Lists.newArrayList(); - for (Map.Entry 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 jetTypeArguments, List typeArguments, CallableDescriptor functionDescriptor, BindingTrace trace) { - Map context = Maps.newHashMap(); - - List 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 diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CandidateResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CandidateResolver.java new file mode 100644 index 00000000000..476adef9921 --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CandidateResolver.java @@ -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 void performResolutionForCandidateCall( + @NotNull CallResolutionContext context, + @NotNull ResolutionTask task) { + + ProgressIndicatorProvider.checkCanceled(); + + ResolvedCallImpl 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 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 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 typeArguments = new ArrayList(); + 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 + substitutionContext = FunctionDescriptorUtil.createSubstitutionContext((FunctionDescriptor)candidate, typeArguments); + candidateCall.setResultingSubstitutor(TypeSubstitutor.create(substitutionContext)); + + List 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 void completeTypeInferenceDependentOnExpectedTypeForCall( + CallResolutionContext context, + Set> successful, + Set> failed + ) { + ResolvedCallImpl 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 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 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 ResolutionStatus inferTypeArguments(CallResolutionContext context) { + ResolvedCallImpl 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 = 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 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() { + @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 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 ValueArgumentsCheckingResult checkAllValueArguments(CallResolutionContext context) { + ValueArgumentsCheckingResult checkingResult = checkValueArgumentTypes(context, context.candidateCall, context.candidateCall.getTrace()); + ResolutionStatus resultStatus = checkingResult.status; + ResolvedCall 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 ValueArgumentsCheckingResult checkValueArgumentTypes( + @NotNull ResolutionContext context, + @NotNull ResolvedCallImpl candidateCall, + @NotNull BindingTrace trace) { + ResolutionStatus resultStatus = SUCCESS; + DataFlowInfo dataFlowInfo = context.dataFlowInfo; + List argumentTypes = Lists.newArrayList(); + for (Map.Entry 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 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 ResolutionStatus checkReceiver(CallResolutionContext context, ResolvedCall 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 argumentTypes; + public final ResolutionStatus status; + + private ValueArgumentsCheckingResult(@NotNull ResolutionStatus status, @NotNull List 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 void checkBounds( + @NotNull ResolvedCallImpl 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 jetTypeArguments, + @NotNull List typeArguments, + @NotNull CallableDescriptor functionDescriptor, + @NotNull BindingTrace trace) { + Map context = Maps.newHashMap(); + + List 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); + } + } + } +} diff --git a/compiler/tests/org/jetbrains/jet/di/InjectorForTests.java b/compiler/tests/org/jetbrains/jet/di/InjectorForTests.java index 921615c1546..d0668eb0f60 100644 --- a/compiler/tests/org/jetbrains/jet/di/InjectorForTests.java +++ b/compiler/tests/org/jetbrains/jet/di/InjectorForTests.java @@ -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); } diff --git a/js/js.translator/src/org/jetbrains/jet/di/InjectorForTopDownAnalyzerForJs.java b/js/js.translator/src/org/jetbrains/jet/di/InjectorForTopDownAnalyzerForJs.java index d4439f033a3..0259ffd17e2 100644 --- a/js/js.translator/src/org/jetbrains/jet/di/InjectorForTopDownAnalyzerForJs.java +++ b/js/js.translator/src/org/jetbrains/jet/di/InjectorForTopDownAnalyzerForJs.java @@ -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);