[NI] Introduced ResolutionAtom's

Introduced new model for resolution result: tree of ResolvedAtoms.
Moved all postprocessing for arguments to front-end module.
Do not create freshDescriptor -- use freshTypeSubstitutor directly.
Removed Candidates for variables+invoke.
Add lazy way for argument analysis -- do not analyze all arguments
if we have subtyping error in first argument, but if we want report
all errors, then all arguments checks will be performed.

Future improvements:
  - optimize constraint system usage inside ResolutionCandidate
  - improve constraint system API
  - improve diagnostic handlers
This commit is contained in:
Stanislav Erokhin
2017-08-15 19:07:09 +03:00
parent 76012f6603
commit cb1270836c
44 changed files with 1367 additions and 1167 deletions
@@ -29,8 +29,8 @@ import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor;
import org.jetbrains.kotlin.name.FqName; import org.jetbrains.kotlin.name.FqName;
import org.jetbrains.kotlin.name.FqNameUnsafe; import org.jetbrains.kotlin.name.FqNameUnsafe;
import org.jetbrains.kotlin.psi.*; import org.jetbrains.kotlin.psi.*;
import org.jetbrains.kotlin.resolve.calls.model.ResolvedKotlinCall;
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemCompleter; import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemCompleter;
import org.jetbrains.kotlin.resolve.calls.model.CallResolutionResult;
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall; import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo; import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo;
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValue; import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValue;
@@ -122,7 +122,7 @@ public interface BindingContext {
new BasicWritableSlice<>(DO_NOTHING); new BasicWritableSlice<>(DO_NOTHING);
WritableSlice<Call, ResolvedCall<?>> RESOLVED_CALL = new BasicWritableSlice<>(DO_NOTHING); WritableSlice<Call, ResolvedCall<?>> RESOLVED_CALL = new BasicWritableSlice<>(DO_NOTHING);
WritableSlice<Call, ResolvedKotlinCall.OnlyResolvedKotlinCall> ONLY_RESOLVED_CALL = new BasicWritableSlice<>(DO_NOTHING); WritableSlice<Call, CallResolutionResult> ONLY_RESOLVED_CALL = new BasicWritableSlice<>(DO_NOTHING);
WritableSlice<KtExpression, Call> DELEGATE_EXPRESSION_TO_PROVIDE_DELEGATE_CALL = new BasicWritableSlice<>(DO_NOTHING); WritableSlice<KtExpression, Call> DELEGATE_EXPRESSION_TO_PROVIDE_DELEGATE_CALL = new BasicWritableSlice<>(DO_NOTHING);
WritableSlice<Call, TailRecursionKind> TAIL_RECURSION_CALL = Slices.createSimpleSlice(); WritableSlice<Call, TailRecursionKind> TAIL_RECURSION_CALL = Slices.createSimpleSlice();
WritableSlice<KtElement, ConstraintSystemCompleter> CONSTRAINT_SYSTEM_COMPLETER = new BasicWritableSlice<>(DO_NOTHING); WritableSlice<KtElement, ConstraintSystemCompleter> CONSTRAINT_SYSTEM_COMPLETER = new BasicWritableSlice<>(DO_NOTHING);
@@ -24,8 +24,7 @@ import org.jetbrains.kotlin.resolve.calls.KotlinResolutionConfigurationKt;
import org.jetbrains.kotlin.resolve.calls.context.ContextDependency; import org.jetbrains.kotlin.resolve.calls.context.ContextDependency;
import org.jetbrains.kotlin.resolve.calls.model.MutableResolvedCall; import org.jetbrains.kotlin.resolve.calls.model.MutableResolvedCall;
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall; import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
import org.jetbrains.kotlin.resolve.calls.tower.StubOnlyResolvedCall; import org.jetbrains.kotlin.resolve.calls.tower.KotlinToResolvedCallTransformerKt;
import org.jetbrains.kotlin.resolve.calls.tower.StubOnlyVariableAsFunctionCall;
import org.jetbrains.kotlin.types.KotlinType; import org.jetbrains.kotlin.types.KotlinType;
import java.util.Collection; import java.util.Collection;
@@ -61,7 +60,7 @@ public class OverloadResolutionResultsUtil {
} }
} }
else { else {
if (resultingCall instanceof StubOnlyResolvedCall || resultingCall instanceof StubOnlyVariableAsFunctionCall) { if (KotlinToResolvedCallTransformerKt.isNewNotCompleted(resultingCall)) {
return null; return null;
} }
} }
@@ -19,8 +19,6 @@ package org.jetbrains.kotlin.resolve.calls.tower
import org.jetbrains.kotlin.builtins.createFunctionType import org.jetbrains.kotlin.builtins.createFunctionType
import org.jetbrains.kotlin.config.LanguageVersionSettings import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.descriptors.CallableDescriptor import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.psi.KtExpression import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.psi.KtPsiUtil import org.jetbrains.kotlin.psi.KtPsiUtil
@@ -28,22 +26,22 @@ import org.jetbrains.kotlin.psi.KtReturnExpression
import org.jetbrains.kotlin.psi.psiUtil.lastBlockStatementOrThis import org.jetbrains.kotlin.psi.psiUtil.lastBlockStatementOrThis
import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.BindingTrace import org.jetbrains.kotlin.resolve.BindingTrace
import org.jetbrains.kotlin.resolve.TemporaryBindingTrace
import org.jetbrains.kotlin.resolve.calls.ArgumentTypeResolver import org.jetbrains.kotlin.resolve.calls.ArgumentTypeResolver
import org.jetbrains.kotlin.resolve.calls.components.KotlinResolutionCallbacks import org.jetbrains.kotlin.resolve.calls.components.KotlinResolutionCallbacks
import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext
import org.jetbrains.kotlin.resolve.calls.context.ContextDependency import org.jetbrains.kotlin.resolve.calls.context.ContextDependency
import org.jetbrains.kotlin.resolve.calls.model.* import org.jetbrains.kotlin.resolve.calls.model.LambdaKotlinCallArgument
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCallAtom
import org.jetbrains.kotlin.resolve.calls.model.SimpleKotlinCallArgument
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind
import org.jetbrains.kotlin.resolve.calls.tasks.TracingStrategyImpl
import org.jetbrains.kotlin.resolve.calls.util.CallMaker import org.jetbrains.kotlin.resolve.calls.util.CallMaker
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
import org.jetbrains.kotlin.types.* import org.jetbrains.kotlin.types.TypeApproximator
import org.jetbrains.kotlin.types.expressions.DoubleColonExpressionResolver import org.jetbrains.kotlin.types.TypeApproximatorConfiguration
import org.jetbrains.kotlin.types.TypeUtils
import org.jetbrains.kotlin.types.UnwrappedType
import org.jetbrains.kotlin.types.expressions.ExpressionTypingServices import org.jetbrains.kotlin.types.expressions.ExpressionTypingServices
import org.jetbrains.kotlin.types.expressions.KotlinTypeInfo import org.jetbrains.kotlin.types.expressions.KotlinTypeInfo
import org.jetbrains.kotlin.types.typeUtil.asTypeProjection
import org.jetbrains.kotlin.types.typeUtil.isUnit import org.jetbrains.kotlin.types.typeUtil.isUnit
import org.jetbrains.kotlin.utils.addIfNotNull import org.jetbrains.kotlin.utils.addIfNotNull
@@ -51,10 +49,9 @@ class KotlinResolutionCallbacksImpl(
val topLevelCallContext: BasicCallResolutionContext, val topLevelCallContext: BasicCallResolutionContext,
val expressionTypingServices: ExpressionTypingServices, val expressionTypingServices: ExpressionTypingServices,
val typeApproximator: TypeApproximator, val typeApproximator: TypeApproximator,
val kotlinToResolvedCallTransformer: KotlinToResolvedCallTransformer,
val argumentTypeResolver: ArgumentTypeResolver, val argumentTypeResolver: ArgumentTypeResolver,
val doubleColonExpressionResolver: DoubleColonExpressionResolver, val languageVersionSettings: LanguageVersionSettings,
val languageVersionSettings: LanguageVersionSettings val kotlinToResolvedCallTransformer: KotlinToResolvedCallTransformer
): KotlinResolutionCallbacks { ): KotlinResolutionCallbacks {
val trace: BindingTrace = topLevelCallContext.trace val trace: BindingTrace = topLevelCallContext.trace
@@ -143,72 +140,8 @@ class KotlinResolutionCallbacksImpl(
return KtPsiUtil.deparenthesize(lastExpression) return KtPsiUtil.deparenthesize(lastExpression)
} }
override fun bindStubResolvedCallForCandidate(candidate: KotlinResolutionCandidate) { override fun bindStubResolvedCallForCandidate(candidate: ResolvedCallAtom) {
kotlinToResolvedCallTransformer.createStubResolvedCallAndWriteItToTrace<CallableDescriptor>(candidate, trace) kotlinToResolvedCallTransformer.createStubResolvedCallAndWriteItToTrace<CallableDescriptor>(candidate, trace)
} }
override fun completeCallableReference(
callableReferenceArgument: PostponedCallableReferenceArgument,
resultTypeParameters: List<UnwrappedType>
) {
val callableCandidate = callableReferenceArgument.callableResolutionCandidate
val psiCallArgument = callableReferenceArgument.argument.psiCallArgument as CallableReferenceKotlinCallArgumentImpl
val callableReferenceExpression = psiCallArgument.ktCallableReferenceExpression
val resultSubstitutor = IndexedParametersSubstitution(callableCandidate.candidate.typeParameters, resultTypeParameters.map { it.asTypeProjection() }).buildSubstitutor()
// write down type for callable reference expression
val resultType = resultSubstitutor.safeSubstitute(callableCandidate.reflectionCandidateType, Variance.INVARIANT)
argumentTypeResolver.updateResultArgumentTypeIfNotDenotable(trace, expressionTypingServices.statementFilter,
resultType,
callableReferenceExpression)
val reference = callableReferenceExpression.callableReference
val explicitCallableReceiver = when (callableCandidate.explicitReceiverKind) {
ExplicitReceiverKind.DISPATCH_RECEIVER -> callableCandidate.dispatchReceiver
ExplicitReceiverKind.EXTENSION_RECEIVER -> callableCandidate.extensionReceiver
else -> null
}
val explicitReceiver = explicitCallableReceiver?.receiver
val psiCall = CallMaker.makeCall(reference, explicitReceiver?.receiverValue, null, reference, emptyList())
val tracing = TracingStrategyImpl.create(reference, psiCall)
val temporaryTrace = TemporaryBindingTrace.create(trace, "callable reference fake call")
val resolvedCall = ResolvedCallImpl(psiCall, callableCandidate.candidate, callableCandidate.dispatchReceiver?.receiver?.receiverValue,
callableCandidate.extensionReceiver?.receiver?.receiverValue, callableCandidate.explicitReceiverKind,
null, temporaryTrace, tracing, MutableDataFlowInfoForArguments.WithoutArgumentsCheck(DataFlowInfo.EMPTY))
resolvedCall.setResultingSubstitutor(resultSubstitutor)
tracing.bindCall(trace, psiCall)
tracing.bindReference(trace, resolvedCall)
tracing.bindResolvedCall(trace, resolvedCall)
resolvedCall.setStatusToSuccess()
resolvedCall.markCallAsCompleted()
when (callableCandidate.candidate) {
is FunctionDescriptor -> doubleColonExpressionResolver.bindFunctionReference(callableReferenceExpression, resultType, topLevelCallContext)
is PropertyDescriptor -> doubleColonExpressionResolver.bindPropertyReference(callableReferenceExpression, resultType, topLevelCallContext)
}
// TODO: probably we should also record key 'DATA_FLOW_INFO_BEFORE', see ExpressionTypingVisitorDispatcher.getTypeInfo
trace.recordType(callableReferenceExpression, resultType)
trace.record(BindingContext.PROCESSED, callableReferenceExpression)
doubleColonExpressionResolver.checkReferenceIsToAllowedMember(callableCandidate.candidate, topLevelCallContext.trace, callableReferenceExpression)
}
override fun completeCollectionLiteralCalls(collectionLiteralArgument: PostponedCollectionLiteralArgument) {
val psiCallArgument = collectionLiteralArgument.argument.psiCallArgument as CollectionLiteralKotlinCallArgumentImpl
val context = psiCallArgument.outerCallContext
val actualContext = context
.replaceBindingTrace(trace)
.replaceExpectedType(collectionLiteralArgument.expectedType)
.replaceContextDependency(ContextDependency.INDEPENDENT)
expressionTypingServices.getTypeInfo(psiCallArgument.collectionLiteralExpression, actualContext)
}
} }
@@ -29,6 +29,7 @@ import org.jetbrains.kotlin.resolve.calls.model.CallableReferenceKotlinCallArgum
import org.jetbrains.kotlin.resolve.calls.model.KotlinCall import org.jetbrains.kotlin.resolve.calls.model.KotlinCall
import org.jetbrains.kotlin.resolve.calls.model.SimpleKotlinCallArgument import org.jetbrains.kotlin.resolve.calls.model.SimpleKotlinCallArgument
import org.jetbrains.kotlin.resolve.isHiddenInResolution import org.jetbrains.kotlin.resolve.isHiddenInResolution
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
class KotlinResolutionStatelessCallbacksImpl( class KotlinResolutionStatelessCallbacksImpl(
private val languageVersionSettings: LanguageVersionSettings private val languageVersionSettings: LanguageVersionSettings
@@ -54,4 +55,7 @@ class KotlinResolutionStatelessCallbacksImpl(
override fun getScopeTowerForCallableReferenceArgument(argument: CallableReferenceKotlinCallArgument): ImplicitScopeTower = override fun getScopeTowerForCallableReferenceArgument(argument: CallableReferenceKotlinCallArgument): ImplicitScopeTower =
(argument as CallableReferenceKotlinCallArgumentImpl).scopeTowerForResolution (argument as CallableReferenceKotlinCallArgumentImpl).scopeTowerForResolution
override fun getVariableCandidateIfInvoke(functionCall: KotlinCall) =
functionCall.safeAs<PSIKotlinCallForInvoke>()?.variableCall
} }
@@ -16,10 +16,8 @@
package org.jetbrains.kotlin.resolve.calls.tower package org.jetbrains.kotlin.resolve.calls.tower
import org.jetbrains.kotlin.builtins.replaceReturnType
import org.jetbrains.kotlin.config.LanguageVersionSettings import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.impl.FunctionDescriptorImpl
import org.jetbrains.kotlin.diagnostics.Diagnostic import org.jetbrains.kotlin.diagnostics.Diagnostic
import org.jetbrains.kotlin.diagnostics.Errors import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
@@ -32,9 +30,15 @@ import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
import org.jetbrains.kotlin.resolve.calls.callUtil.isFakeElement import org.jetbrains.kotlin.resolve.calls.callUtil.isFakeElement
import org.jetbrains.kotlin.resolve.calls.checkers.CallChecker import org.jetbrains.kotlin.resolve.calls.checkers.CallChecker
import org.jetbrains.kotlin.resolve.calls.checkers.CallCheckerContext import org.jetbrains.kotlin.resolve.calls.checkers.CallCheckerContext
import org.jetbrains.kotlin.resolve.calls.components.AdditionalDiagnosticReporter
import org.jetbrains.kotlin.resolve.calls.components.isVararg import org.jetbrains.kotlin.resolve.calls.components.isVararg
import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext
import org.jetbrains.kotlin.resolve.calls.context.CallPosition import org.jetbrains.kotlin.resolve.calls.context.CallPosition
import org.jetbrains.kotlin.resolve.calls.inference.buildResultingSubstitutor
import org.jetbrains.kotlin.resolve.calls.inference.components.FreshVariableNewTypeSubstitutor
import org.jetbrains.kotlin.resolve.calls.inference.components.NewTypeSubstitutor
import org.jetbrains.kotlin.resolve.calls.inference.substitute
import org.jetbrains.kotlin.resolve.calls.inference.substituteAndApproximateCapturedTypes
import org.jetbrains.kotlin.resolve.calls.model.* import org.jetbrains.kotlin.resolve.calls.model.*
import org.jetbrains.kotlin.resolve.calls.resolvedCallUtil.makeNullableTypeIfSafeReceiver import org.jetbrains.kotlin.resolve.calls.resolvedCallUtil.makeNullableTypeIfSafeReceiver
import org.jetbrains.kotlin.resolve.calls.results.ResolutionStatus import org.jetbrains.kotlin.resolve.calls.results.ResolutionStatus
@@ -42,12 +46,15 @@ import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind
import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
import org.jetbrains.kotlin.types.ErrorUtils import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.checker.NewCapturedType
import org.jetbrains.kotlin.types.TypeUtils
import org.jetbrains.kotlin.types.UnwrappedType
import org.jetbrains.kotlin.types.expressions.DataFlowAnalyzer import org.jetbrains.kotlin.types.expressions.DataFlowAnalyzer
import org.jetbrains.kotlin.types.expressions.DoubleColonExpressionResolver
import org.jetbrains.kotlin.types.expressions.ExpressionTypingServices
import org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils import org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils
import org.jetbrains.kotlin.types.typeUtil.contains
import org.jetbrains.kotlin.utils.addToStdlib.cast
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
import java.util.* import java.util.*
@@ -56,91 +63,71 @@ class KotlinToResolvedCallTransformer(
private val languageFeatureSettings: LanguageVersionSettings, private val languageFeatureSettings: LanguageVersionSettings,
private val dataFlowAnalyzer: DataFlowAnalyzer, private val dataFlowAnalyzer: DataFlowAnalyzer,
private val argumentTypeResolver: ArgumentTypeResolver, private val argumentTypeResolver: ArgumentTypeResolver,
private val constantExpressionEvaluator: ConstantExpressionEvaluator private val constantExpressionEvaluator: ConstantExpressionEvaluator,
) { private val expressionTypingServices: ExpressionTypingServices,
private val doubleColonExpressionResolver: DoubleColonExpressionResolver,
private val additionalDiagnosticReporter: AdditionalDiagnosticReporter
) {
fun <D : CallableDescriptor> onlyTransform(
resolvedCallAtom: ResolvedCallAtom
): ResolvedCall<D> = transformToResolvedCall(resolvedCallAtom, completed = false)
fun <D : CallableDescriptor> transformAndReport( fun <D : CallableDescriptor> transformAndReport(
baseResolvedCall: ResolvedKotlinCall, baseResolvedCall: CallResolutionResult,
context: BasicCallResolutionContext, context: BasicCallResolutionContext
trace: BindingTrace? // if trace is not null then all information will be reported to this trace
): ResolvedCall<D> { ): ResolvedCall<D> {
if (baseResolvedCall is ResolvedKotlinCall.CompletedResolvedKotlinCall) { val candidate = baseResolvedCall.resultCallAtom!!
val allResolvedCalls = baseResolvedCall.allInnerCalls.mapTo(ArrayList<ResolvedCall<*>>()) { transformAndReportCompletedCall<CallableDescriptor>(it, context, trace) } when (baseResolvedCall.type) {
val result = transformAndReportCompletedCall<D>(baseResolvedCall.completedCall, context, trace) CallResolutionResult.Type.PARTIAL -> {
allResolvedCalls.add(result) context.trace.record(BindingContext.ONLY_RESOLVED_CALL, candidate.atom.psiKotlinCall.psiCall, baseResolvedCall)
if (trace != null) { return createStubResolvedCallAndWriteItToTrace(candidate, context.trace)
// todo: check checkers order
val callCheckerContext = CallCheckerContext(context.replaceBindingTrace(trace), languageFeatureSettings)
for (resolvedCall in allResolvedCalls) {
runCallCheckers(resolvedCall, callCheckerContext)
}
runLambdaArgumentsChecks(context, trace, baseResolvedCall.lambdaArguments)
allResolvedCalls.map {
if (it is VariableAsFunctionResolvedCall) it.functionCall else it
}.forEach {
runArgumentsChecks(context, trace, it as NewResolvedCallImpl<*>)
}
} }
CallResolutionResult.Type.ERROR, CallResolutionResult.Type.COMPLETED -> {
val resultSubstitutor = baseResolvedCall.constraintSystem.buildResultingSubstitutor()
val ktPrimitiveCompleter = ResolvedAtomCompleter(resultSubstitutor, context.trace, context, this,
expressionTypingServices, argumentTypeResolver, doubleColonExpressionResolver,
languageFeatureSettings)
return result for (subKtPrimitive in candidate.subResolvedAtoms) {
ktPrimitiveCompleter.completeAll(subKtPrimitive)
}
return ktPrimitiveCompleter.completeResolvedCall(candidate) as ResolvedCall<D>
}
} }
val onlyResolvedCall = (baseResolvedCall as ResolvedKotlinCall.OnlyResolvedKotlinCall)
trace?.record(BindingContext.ONLY_RESOLVED_CALL, onlyResolvedCall.candidate.kotlinCall.psiKotlinCall.psiCall, onlyResolvedCall)
return createStubResolvedCallAndWriteItToTrace(onlyResolvedCall.candidate, trace)
} }
fun <D : CallableDescriptor> createStubResolvedCallAndWriteItToTrace(candidate: KotlinResolutionCandidate, trace: BindingTrace?): ResolvedCall<D> { fun <D : CallableDescriptor> createStubResolvedCallAndWriteItToTrace(candidate: ResolvedCallAtom, trace: BindingTrace): ResolvedCall<D> {
val result = when (candidate) { val result = onlyTransform<D>(candidate)
is VariableAsFunctionKotlinResolutionCandidate -> { val psiKotlinCall = candidate.atom.psiKotlinCall
val variableStub = StubOnlyResolvedCall<VariableDescriptor>(candidate.resolvedVariable) val tracing = psiKotlinCall.safeAs<PSIKotlinCallForInvoke>()?.baseCall?.tracingStrategy ?: psiKotlinCall.tracingStrategy
val invokeStub = StubOnlyResolvedCall<FunctionDescriptor>(candidate.invokeCandidate)
StubOnlyVariableAsFunctionCall(variableStub, invokeStub) as ResolvedCall<D>
}
is SimpleKotlinResolutionCandidate -> {
StubOnlyResolvedCall<D>(candidate)
}
}
if (trace != null) {
val tracing = candidate.kotlinCall.psiKotlinCall.tracingStrategy
tracing.bindReference(trace, result) tracing.bindReference(trace, result)
tracing.bindResolvedCall(trace, result) tracing.bindResolvedCall(trace, result)
}
return result return result
} }
fun <D : CallableDescriptor> transformToResolvedCall(
private fun <D : CallableDescriptor> transformAndReportCompletedCall( completedCallAtom: ResolvedCallAtom,
completedCall: CompletedKotlinCall, completed: Boolean,
context: BasicCallResolutionContext, resultSubstitutor: NewTypeSubstitutor = FreshVariableNewTypeSubstitutor.Empty
trace: BindingTrace?
): ResolvedCall<D> { ): ResolvedCall<D> {
fun <C> C.runIfTraceNotNull(action: (BasicCallResolutionContext, BindingTrace, C) -> Unit): C { val psiKotlinCall = completedCallAtom.atom.psiKotlinCall
if (trace != null) action(context, trace, this) return if (psiKotlinCall is PSIKotlinCallForInvoke) {
return this @Suppress("UNCHECKED_CAST")
NewVariableAsFunctionResolvedCallImpl(
NewResolvedCallImpl(psiKotlinCall.variableCall.resolvedCall, completed, resultSubstitutor),
NewResolvedCallImpl(completedCallAtom, completed, resultSubstitutor)
) as ResolvedCall<D>
} }
else {
return when (completedCall) { NewResolvedCallImpl(completedCallAtom, completed, resultSubstitutor)
is CompletedKotlinCall.Simple -> {
NewResolvedCallImpl<D>(completedCall).runIfTraceNotNull(this::bindResolvedCall)
}
is CompletedKotlinCall.VariableAsFunction -> {
val resolvedCall = NewVariableAsFunctionResolvedCallImpl(
completedCall,
NewResolvedCallImpl(completedCall.variableCall),
NewResolvedCallImpl<FunctionDescriptor>(completedCall.invokeCall)
).runIfTraceNotNull(this::bindResolvedCall)
@Suppress("UNCHECKED_CAST")
(resolvedCall as ResolvedCall<D>)
}
} }
} }
private fun runCallCheckers(resolvedCall: ResolvedCall<*>, callCheckerContext: CallCheckerContext) { fun runCallCheckers(resolvedCall: ResolvedCall<*>, callCheckerContext: CallCheckerContext) {
val calleeExpression = if (resolvedCall is VariableAsFunctionResolvedCall) val calleeExpression = if (resolvedCall is VariableAsFunctionResolvedCall)
resolvedCall.variableCall.call.calleeExpression resolvedCall.variableCall.call.calleeExpression
else else
@@ -158,57 +145,8 @@ class KotlinToResolvedCallTransformer(
} }
} }
private fun runLambdaArgumentsChecks(
context: BasicCallResolutionContext,
trace: BindingTrace,
lambdaArguments: List<PostponedLambdaArgument>
) {
for (lambdaArgument in lambdaArguments) {
val returnType = lambdaArgument.finalReturnType
updateTraceForLambdaReturnType(lambdaArgument, trace, returnType)
for (lambdaResult in lambdaArgument.resultArguments) {
val resultValueArgument = lambdaResult as? PSIKotlinCallArgument ?: continue
val newContext =
context.replaceDataFlowInfo(resultValueArgument.dataFlowInfoAfterThisArgument)
.replaceExpectedType(returnType)
.replaceBindingTrace(trace)
val argumentExpression = resultValueArgument.valueArgument.getArgumentExpression() ?: continue
updateRecordedType(argumentExpression, newContext)
}
}
}
private fun updateTraceForLambdaReturnType(lambdaArgument: PostponedLambdaArgument, trace: BindingTrace, returnType: UnwrappedType) {
val psiCallArgument = lambdaArgument.argument.psiCallArgument
val ktArgumentExpression: KtExpression
val ktFunction: KtElement
when (psiCallArgument) {
is LambdaKotlinCallArgumentImpl -> {
ktArgumentExpression = psiCallArgument.ktLambdaExpression
ktFunction = ktArgumentExpression.functionLiteral
}
is FunctionExpressionImpl -> {
ktArgumentExpression = psiCallArgument.ktFunction
ktFunction = ktArgumentExpression
}
else -> throw AssertionError("Unexpected psiCallArgument for resolved lambda argument: $psiCallArgument")
}
val functionDescriptor = trace.bindingContext.get(BindingContext.FUNCTION, ktFunction) as? FunctionDescriptorImpl ?:
throw AssertionError("No function descriptor for resolved lambda argument")
functionDescriptor.setReturnType(returnType)
val existingLambdaType = trace.getType(ktArgumentExpression) ?: throw AssertionError("No type for resolved lambda argument")
trace.recordType(ktArgumentExpression, existingLambdaType.replaceReturnType(returnType))
}
// todo very beginning code // todo very beginning code
private fun runArgumentsChecks( fun runArgumentsChecks(
context: BasicCallResolutionContext, context: BasicCallResolutionContext,
trace: BindingTrace, trace: BindingTrace,
resolvedCall: NewResolvedCallImpl<*> resolvedCall: NewResolvedCallImpl<*>
@@ -320,19 +258,24 @@ class KotlinToResolvedCallTransformer(
return expressionType != null && TypeUtils.isNullableType(expressionType) return expressionType != null && TypeUtils.isNullableType(expressionType)
} }
private fun bindResolvedCall(context: BasicCallResolutionContext, trace: BindingTrace, simpleResolvedCall: NewResolvedCallImpl<*>) { internal fun bindAndReport(context: BasicCallResolutionContext, trace: BindingTrace, resolvedCall: ResolvedCall<*>) {
reportCallDiagnostic(context, trace, simpleResolvedCall.completedCall) resolvedCall.safeAs<NewResolvedCallImpl<*>>()?.let { bindAndReport(context, trace, it) }
val tracing = simpleResolvedCall.completedCall.kotlinCall.psiKotlinCall.tracingStrategy resolvedCall.safeAs<NewVariableAsFunctionResolvedCallImpl>()?.let { bindAndReport(context, trace, it) }
}
private fun bindAndReport(context: BasicCallResolutionContext, trace: BindingTrace, simpleResolvedCall: NewResolvedCallImpl<*>) {
reportCallDiagnostic(context, trace, simpleResolvedCall.resolvedCallAtom, simpleResolvedCall.resultingDescriptor)
val tracing = simpleResolvedCall.resolvedCallAtom.atom.psiKotlinCall.tracingStrategy
tracing.bindReference(trace, simpleResolvedCall) tracing.bindReference(trace, simpleResolvedCall)
tracing.bindResolvedCall(trace, simpleResolvedCall) tracing.bindResolvedCall(trace, simpleResolvedCall)
} }
private fun bindResolvedCall(context: BasicCallResolutionContext, trace: BindingTrace, variableAsFunction: NewVariableAsFunctionResolvedCallImpl) { private fun bindAndReport(context: BasicCallResolutionContext, trace: BindingTrace, variableAsFunction: NewVariableAsFunctionResolvedCallImpl) {
reportCallDiagnostic(context, trace, variableAsFunction.variableCall.completedCall) reportCallDiagnostic(context, trace, variableAsFunction.variableCall.resolvedCallAtom, variableAsFunction.variableCall.resultingDescriptor)
reportCallDiagnostic(context, trace, variableAsFunction.functionCall.completedCall) reportCallDiagnostic(context, trace, variableAsFunction.functionCall.resolvedCallAtom, variableAsFunction.functionCall.resultingDescriptor)
val outerTracingStrategy = variableAsFunction.completedCall.kotlinCall.psiKotlinCall.tracingStrategy val outerTracingStrategy = variableAsFunction.baseCall.tracingStrategy
outerTracingStrategy.bindReference(trace, variableAsFunction.variableCall) outerTracingStrategy.bindReference(trace, variableAsFunction.variableCall)
outerTracingStrategy.bindResolvedCall(trace, variableAsFunction) outerTracingStrategy.bindResolvedCall(trace, variableAsFunction)
variableAsFunction.functionCall.kotlinCall.psiKotlinCall.tracingStrategy.bindReference(trace, variableAsFunction.functionCall) variableAsFunction.functionCall.kotlinCall.psiKotlinCall.tracingStrategy.bindReference(trace, variableAsFunction.functionCall)
@@ -341,13 +284,17 @@ class KotlinToResolvedCallTransformer(
private fun reportCallDiagnostic( private fun reportCallDiagnostic(
context: BasicCallResolutionContext, context: BasicCallResolutionContext,
trace: BindingTrace, trace: BindingTrace,
completedCall: CompletedKotlinCall.Simple completedCallAtom: ResolvedCallAtom,
resultingDescriptor: CallableDescriptor
) { ) {
val trackingTrace = TrackingBindingTrace(trace) val trackingTrace = TrackingBindingTrace(trace)
val newContext = context.replaceBindingTrace(trackingTrace) val newContext = context.replaceBindingTrace(trackingTrace)
val diagnosticReporter = DiagnosticReporterByTrackingStrategy(constantExpressionEvaluator, newContext, completedCall.kotlinCall.psiKotlinCall) val diagnosticReporter = DiagnosticReporterByTrackingStrategy(constantExpressionEvaluator, newContext, completedCallAtom.atom.psiKotlinCall)
for (diagnostic in completedCall.diagnostics) { val diagnosticHolder = KotlinDiagnosticsHolder.SimpleHolder()
additionalDiagnosticReporter.reportAdditionalDiagnostics(completedCallAtom, resultingDescriptor, diagnosticHolder)
for (diagnostic in completedCallAtom.diagnostics + diagnosticHolder.getDiagnostics()) {
trackingTrace.reported = false trackingTrace.reported = false
diagnostic.report(diagnosticReporter) diagnostic.report(diagnosticReporter)
@@ -460,24 +407,46 @@ sealed class NewAbstractResolvedCall<D : CallableDescriptor>(): ResolvedCall<D>
} }
class NewResolvedCallImpl<D : CallableDescriptor>( class NewResolvedCallImpl<D : CallableDescriptor>(
val completedCall: CompletedKotlinCall.Simple val resolvedCallAtom: ResolvedCallAtom,
val completed: Boolean,
substitutor: NewTypeSubstitutor
): NewAbstractResolvedCall<D>() { ): NewAbstractResolvedCall<D>() {
override val kotlinCall: KotlinCall get() = completedCall.kotlinCall private val resultingDescriptor = run {
val candidateDescriptor = resolvedCallAtom.candidateDescriptor
val containsCapturedTypes = resolvedCallAtom.candidateDescriptor.returnType?.contains { it is NewCapturedType } ?: false
override fun getStatus(): ResolutionStatus = completedCall.resultingApplicability.toResolutionStatus() when {
candidateDescriptor is FunctionDescriptor ||
(candidateDescriptor is PropertyDescriptor && (candidateDescriptor.typeParameters.isNotEmpty() || containsCapturedTypes)) ->
// this code is very suspicious. Now it is very useful for BE, because they cannot do nothing with captured types,
// but it seems like temporary solution.
candidateDescriptor.substitute(resolvedCallAtom.substitutor).substituteAndApproximateCapturedTypes(substitutor)
else ->
candidateDescriptor
}
}
val typeArguments = resolvedCallAtom.substitutor.freshVariables.map {
val substituted = substitutor.safeSubstitute(it.defaultType)
TypeApproximator().approximateToSuperType(substituted, TypeApproximatorConfiguration.CapturedTypesApproximation) ?: substituted
}
override val kotlinCall: KotlinCall get() = resolvedCallAtom.atom
override fun getStatus(): ResolutionStatus = getResultApplicability(resolvedCallAtom.diagnostics).toResolutionStatus()
override val argumentMappingByOriginal: Map<ValueParameterDescriptor, ResolvedCallArgument> override val argumentMappingByOriginal: Map<ValueParameterDescriptor, ResolvedCallArgument>
get() = completedCall.argumentMappingByOriginal get() = resolvedCallAtom.argumentMappingByOriginal
override fun getCandidateDescriptor(): D = completedCall.candidateDescriptor as D override fun getCandidateDescriptor(): D = resolvedCallAtom.candidateDescriptor as D
override fun getResultingDescriptor(): D = completedCall.resultingDescriptor as D override fun getResultingDescriptor(): D = resultingDescriptor as D
override fun getExtensionReceiver(): ReceiverValue? = completedCall.extensionReceiver?.receiverValue override fun getExtensionReceiver(): ReceiverValue? = resolvedCallAtom.extensionReceiverArgument?.receiver?.receiverValue
override fun getDispatchReceiver(): ReceiverValue? = completedCall.dispatchReceiver?.receiverValue override fun getDispatchReceiver(): ReceiverValue? = resolvedCallAtom.dispatchReceiverArgument?.receiver?.receiverValue
override fun getExplicitReceiverKind(): ExplicitReceiverKind = completedCall.explicitReceiverKind override fun getExplicitReceiverKind(): ExplicitReceiverKind = resolvedCallAtom.explicitReceiverKind
override fun getTypeArguments(): Map<TypeParameterDescriptor, KotlinType> { override fun getTypeArguments(): Map<TypeParameterDescriptor, KotlinType> {
val typeParameters = candidateDescriptor.typeParameters.takeIf { it.isNotEmpty() } ?: return emptyMap() val typeParameters = candidateDescriptor.typeParameters.takeIf { it.isNotEmpty() } ?: return emptyMap()
return typeParameters.zip(completedCall.typeArguments).toMap() return typeParameters.zip(typeArguments).toMap()
} }
override fun getSmartCastDispatchReceiverType(): KotlinType? = null // todo override fun getSmartCastDispatchReceiverType(): KotlinType? = null // todo
@@ -490,30 +459,18 @@ fun ResolutionCandidateApplicability.toResolutionStatus(): ResolutionStatus = wh
} }
class NewVariableAsFunctionResolvedCallImpl( class NewVariableAsFunctionResolvedCallImpl(
val completedCall: CompletedKotlinCall.VariableAsFunction,
override val variableCall: NewResolvedCallImpl<VariableDescriptor>, override val variableCall: NewResolvedCallImpl<VariableDescriptor>,
override val functionCall: NewResolvedCallImpl<FunctionDescriptor> override val functionCall: NewResolvedCallImpl<FunctionDescriptor>
): VariableAsFunctionResolvedCall, ResolvedCall<FunctionDescriptor> by functionCall ): VariableAsFunctionResolvedCall, ResolvedCall<FunctionDescriptor> by functionCall {
val baseCall get() = functionCall.resolvedCallAtom.atom.psiKotlinCall.cast<PSIKotlinCallForInvoke>().baseCall
class StubOnlyResolvedCall<D : CallableDescriptor>(val candidate: SimpleKotlinResolutionCandidate): NewAbstractResolvedCall<D>() {
override fun getStatus() = candidate.resultingApplicability.toResolutionStatus()
override fun getCandidateDescriptor(): D = candidate.candidateDescriptor as D
override fun getResultingDescriptor(): D = candidate.descriptorWithFreshTypes as D
override fun getExtensionReceiver() = candidate.extensionReceiver?.receiver?.receiverValue
override fun getDispatchReceiver() = candidate.dispatchReceiverArgument?.receiver?.receiverValue
override fun getExplicitReceiverKind() = candidate.explicitReceiverKind
override fun getTypeArguments(): Map<TypeParameterDescriptor, KotlinType> = emptyMap()
override fun getSmartCastDispatchReceiverType(): KotlinType? = null
override val argumentMappingByOriginal: Map<ValueParameterDescriptor, ResolvedCallArgument>
get() = candidate.argumentMappingByOriginal
override val kotlinCall: KotlinCall get() = candidate.kotlinCall
} }
class StubOnlyVariableAsFunctionCall( fun ResolvedCall<*>.isNewNotCompleted(): Boolean {
override val variableCall: StubOnlyResolvedCall<VariableDescriptor>, if (this is NewVariableAsFunctionResolvedCallImpl) {
override val functionCall: StubOnlyResolvedCall<FunctionDescriptor> return !functionCall.completed
) : VariableAsFunctionResolvedCall, ResolvedCall<FunctionDescriptor> by functionCall }
if (this is NewResolvedCallImpl<*>) {
return !completed
}
return false
}
@@ -147,7 +147,7 @@ class SubKotlinCallArgumentImpl(
override val dataFlowInfoBeforeThisArgument: DataFlowInfo, override val dataFlowInfoBeforeThisArgument: DataFlowInfo,
override val dataFlowInfoAfterThisArgument: DataFlowInfo, override val dataFlowInfoAfterThisArgument: DataFlowInfo,
override val receiver: ReceiverValueWithSmartCastInfo, override val receiver: ReceiverValueWithSmartCastInfo,
override val resolvedCall: ResolvedKotlinCall.OnlyResolvedKotlinCall override val callResult: CallResolutionResult
): SimplePSIKotlinCallArgument(), SubKotlinCallArgument { ): SimplePSIKotlinCallArgument(), SubKotlinCallArgument {
override val isSpread: Boolean get() = valueArgument.getSpreadElement() != null override val isSpread: Boolean get() = valueArgument.getSpreadElement() != null
override val argumentName: Name? get() = valueArgument.getArgumentName()?.asName override val argumentName: Name? get() = valueArgument.getArgumentName()?.asName
@@ -216,7 +216,7 @@ internal fun createSimplePSICallArgument(
} }
// todo hack for if expression: sometimes we not write properly type information for branches // todo hack for if expression: sometimes we not write properly type information for branches
val baseType = typeInfoForArgument.type?.unwrap() ?: val baseType = typeInfoForArgument.type?.unwrap() ?:
onlyResolvedCall?.candidate?.lastCall?.descriptorWithFreshTypes?.returnType?.unwrap() ?: onlyResolvedCall?.resultCallAtom?.freshReturnType ?:
return null return null
// we should use DFI after this argument, because there can be some useful smartcast. Popular case: if branches. // we should use DFI after this argument, because there can be some useful smartcast. Popular case: if branches.
@@ -232,5 +232,4 @@ internal fun createSimplePSICallArgument(
else { else {
SubKotlinCallArgumentImpl(valueArgument, dataFlowInfoBeforeThisArgument, typeInfoForArgument.dataFlowInfo, receiverToCast, onlyResolvedCall) SubKotlinCallArgumentImpl(valueArgument, dataFlowInfoBeforeThisArgument, typeInfoForArgument.dataFlowInfo, receiverToCast, onlyResolvedCall)
} }
}
}
@@ -42,6 +42,7 @@ import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext
import org.jetbrains.kotlin.resolve.calls.context.ContextDependency import org.jetbrains.kotlin.resolve.calls.context.ContextDependency
import org.jetbrains.kotlin.resolve.calls.model.* import org.jetbrains.kotlin.resolve.calls.model.*
import org.jetbrains.kotlin.resolve.calls.results.* import org.jetbrains.kotlin.resolve.calls.results.*
import org.jetbrains.kotlin.resolve.calls.results.ManyCandidates
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory
import org.jetbrains.kotlin.resolve.calls.tasks.DynamicCallableDescriptors import org.jetbrains.kotlin.resolve.calls.tasks.DynamicCallableDescriptors
@@ -56,6 +57,7 @@ import org.jetbrains.kotlin.resolve.scopes.SyntheticScopes
import org.jetbrains.kotlin.resolve.scopes.receivers.* import org.jetbrains.kotlin.resolve.scopes.receivers.*
import org.jetbrains.kotlin.types.* import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.expressions.* import org.jetbrains.kotlin.types.expressions.*
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult
import java.util.* import java.util.*
@@ -93,7 +95,7 @@ class PSICallResolver(
var result = kotlinCallResolver.resolveCall(scopeTower, resolutionCallbacks, kotlinCall, expectedType, factoryProviderForInvoke) var result = kotlinCallResolver.resolveCall(scopeTower, resolutionCallbacks, kotlinCall, expectedType, factoryProviderForInvoke)
val shouldUseOperatorRem = languageVersionSettings.supportsFeature(LanguageFeature.OperatorRem) val shouldUseOperatorRem = languageVersionSettings.supportsFeature(LanguageFeature.OperatorRem)
if (isBinaryRemOperator && shouldUseOperatorRem && (result.isEmpty() || result.areAllCompletedAndInapplicable())) { if (isBinaryRemOperator && shouldUseOperatorRem && (result.isEmpty() || result.areAllInapplicable())) {
result = resolveToDeprecatedMod(name, context, resolutionKind, tracingStrategy, scopeTower, resolutionCallbacks, expectedType) result = resolveToDeprecatedMod(name, context, resolutionKind, tracingStrategy, scopeTower, resolutionCallbacks, expectedType)
} }
@@ -117,12 +119,12 @@ class PSICallResolver(
val resolutionCallbacks = createResolutionCallbacks(context) val resolutionCallbacks = createResolutionCallbacks(context)
val givenCandidates = resolutionCandidates.map { val givenCandidates = resolutionCandidates.map {
GivenCandidate(scopeTower, it.descriptor as FunctionDescriptor, GivenCandidate(it.descriptor as FunctionDescriptor,
it.dispatchReceiver?.let { context.transformToReceiverWithSmartCastInfo(it) }, it.dispatchReceiver?.let { context.transformToReceiverWithSmartCastInfo(it) },
it.knownTypeParametersResultingSubstitutor) it.knownTypeParametersResultingSubstitutor)
} }
val result = kotlinCallResolver.resolveGivenCandidates(resolutionCallbacks, kotlinCall, calculateExpectedType(context), givenCandidates) val result = kotlinCallResolver.resolveGivenCandidates(scopeTower, resolutionCallbacks, kotlinCall, calculateExpectedType(context), givenCandidates)
return convertToOverloadResolutionResults(context, result, tracingStrategy) return convertToOverloadResolutionResults(context, result, tracingStrategy)
} }
@@ -135,7 +137,7 @@ class PSICallResolver(
scopeTower: ImplicitScopeTower, scopeTower: ImplicitScopeTower,
resolutionCallbacks: KotlinResolutionCallbacksImpl, resolutionCallbacks: KotlinResolutionCallbacksImpl,
expectedType: UnwrappedType? expectedType: UnwrappedType?
): Collection<ResolvedKotlinCall> { ): CallResolutionResult {
val deprecatedName = OperatorConventions.REM_TO_MOD_OPERATION_NAMES[remOperatorName]!! val deprecatedName = OperatorConventions.REM_TO_MOD_OPERATION_NAMES[remOperatorName]!!
val callWithDeprecatedName = toKotlinCall(context, resolutionKind.kotlinCallKind, context.call, deprecatedName, tracingStrategy) val callWithDeprecatedName = toKotlinCall(context, resolutionKind.kotlinCallKind, context.call, deprecatedName, tracingStrategy)
val refinedProviderForInvokeFactory = FactoryProviderForInvoke(context, scopeTower, callWithDeprecatedName) val refinedProviderForInvokeFactory = FactoryProviderForInvoke(context, scopeTower, callWithDeprecatedName)
@@ -148,8 +150,8 @@ class PSICallResolver(
} }
private fun createResolutionCallbacks(context: BasicCallResolutionContext) = private fun createResolutionCallbacks(context: BasicCallResolutionContext) =
KotlinResolutionCallbacksImpl(context, expressionTypingServices, typeApproximator, kotlinToResolvedCallTransformer, KotlinResolutionCallbacksImpl(context, expressionTypingServices, typeApproximator,
argumentTypeResolver, doubleColonExpressionResolver, languageVersionSettings) argumentTypeResolver, languageVersionSettings, kotlinToResolvedCallTransformer)
private fun calculateExpectedType(context: BasicCallResolutionContext): UnwrappedType? { private fun calculateExpectedType(context: BasicCallResolutionContext): UnwrappedType? {
val expectedType = context.expectedType.unwrap() val expectedType = context.expectedType.unwrap()
@@ -167,60 +169,67 @@ class PSICallResolver(
private fun <D : CallableDescriptor> convertToOverloadResolutionResults( private fun <D : CallableDescriptor> convertToOverloadResolutionResults(
context: BasicCallResolutionContext, context: BasicCallResolutionContext,
result: Collection<ResolvedKotlinCall>, result: CallResolutionResult,
tracingStrategy: TracingStrategy tracingStrategy: TracingStrategy
): OverloadResolutionResults<D> { ): OverloadResolutionResults<D> {
val trace = context.trace val trace = context.trace
when (result.size) {
0 -> { result.diagnostics.firstIsInstanceOrNull<NoneCandidatesCallDiagnostic>()?.let {
tracingStrategy.unresolvedReference(trace) tracingStrategy.unresolvedReference(trace)
return OverloadResolutionResultsImpl.nameNotFound() return OverloadResolutionResultsImpl.nameNotFound()
}
result.diagnostics.firstIsInstanceOrNull<ManyCandidatesCallDiagnostic>()?.let {
val resolvedCalls = it.candidates.map { kotlinToResolvedCallTransformer.onlyTransform<D>(it.resolvedCall) }
if (it.candidates.areAllFailed()) {
tracingStrategy.noneApplicable(trace, resolvedCalls)
tracingStrategy.recordAmbiguity(trace, resolvedCalls)
} }
1 -> { else {
val singleCandidate = result.single() tracingStrategy.recordAmbiguity(trace, resolvedCalls)
if (resolvedCalls.first().status == ResolutionStatus.INCOMPLETE_TYPE_INFERENCE) {
val isInapplicableReceiver = singleCandidate.resultingApplicability == ResolutionCandidateApplicability.INAPPLICABLE_WRONG_RECEIVER tracingStrategy.cannotCompleteResolve(trace, resolvedCalls)
val resolvedCall = kotlinToResolvedCallTransformer.transformAndReport<D>(singleCandidate, context, trace.takeUnless { isInapplicableReceiver })
if (isInapplicableReceiver) {
tracingStrategy.unresolvedReferenceWrongReceiver(trace, listOf(resolvedCall))
}
return SingleOverloadResolutionResult(resolvedCall)
}
else -> {
val resolvedCalls = result.map { kotlinToResolvedCallTransformer.transformAndReport<D>(it, context, trace = null) }
if (result.areAllCompletedAndFailed()) {
tracingStrategy.noneApplicable(trace, resolvedCalls)
tracingStrategy.recordAmbiguity(trace, resolvedCalls)
} }
else { else {
tracingStrategy.recordAmbiguity(trace, resolvedCalls) tracingStrategy.ambiguity(trace, resolvedCalls)
if (resolvedCalls.first().status == ResolutionStatus.INCOMPLETE_TYPE_INFERENCE) {
tracingStrategy.cannotCompleteResolve(trace, resolvedCalls)
}
else {
tracingStrategy.ambiguity(trace, resolvedCalls)
}
} }
return ManyCandidates(resolvedCalls) }
return ManyCandidates(resolvedCalls)
}
val singleCandidate = result.resultCallAtom ?: error("Should be not null for result: $result")
val isInapplicableReceiver = getResultApplicability(singleCandidate.diagnostics) == ResolutionCandidateApplicability.INAPPLICABLE_WRONG_RECEIVER
val resolvedCall = if (isInapplicableReceiver) {
kotlinToResolvedCallTransformer.onlyTransform<D>(singleCandidate).also {
tracingStrategy.unresolvedReferenceWrongReceiver(trace, listOf(it))
} }
} }
else {
kotlinToResolvedCallTransformer.transformAndReport<D>(result, context)
}
return SingleOverloadResolutionResult(resolvedCall)
} }
private fun Collection<ResolvedKotlinCall>.areAllCompletedAndFailed() = private fun CallResolutionResult.isEmpty(): Boolean =
diagnostics.firstIsInstanceOrNull<NoneCandidatesCallDiagnostic>() != null
private fun Collection<KotlinResolutionCandidate>.areAllFailed() =
all { all {
it is ResolvedKotlinCall.CompletedResolvedKotlinCall && !it.resultingApplicability.isSuccess
!it.completedCall.resultingApplicability.isSuccess
} }
private fun Collection<ResolvedKotlinCall>.areAllCompletedAndInapplicable() = private fun CallResolutionResult.areAllInapplicable(): Boolean {
all { val candidates = diagnostics.firstIsInstanceOrNull<ManyCandidatesCallDiagnostic>()?.candidates?.map { it.resolvedCall }
val applicability = it.resultingApplicability ?: listOfNotNull(resultCallAtom)
applicability == ResolutionCandidateApplicability.INAPPLICABLE ||
applicability == ResolutionCandidateApplicability.INAPPLICABLE_WRONG_RECEIVER || return candidates.all {
applicability == ResolutionCandidateApplicability.HIDDEN val applicability = getResultApplicability(it.diagnostics)
} applicability == ResolutionCandidateApplicability.INAPPLICABLE ||
applicability == ResolutionCandidateApplicability.INAPPLICABLE_WRONG_RECEIVER ||
applicability == ResolutionCandidateApplicability.HIDDEN
}
}
// true if we found something // true if we found something
private fun reportAdditionalDiagnosticIfNoCandidates( private fun reportAdditionalDiagnosticIfNoCandidates(
@@ -285,18 +294,9 @@ class PSICallResolver(
override fun transformCandidate( override fun transformCandidate(
variable: KotlinResolutionCandidate, variable: KotlinResolutionCandidate,
invoke: KotlinResolutionCandidate invoke: KotlinResolutionCandidate
): VariableAsFunctionKotlinResolutionCandidate { ) = invoke
assert(variable is SimpleKotlinResolutionCandidate) {
"VariableAsFunction variable is not allowed here: $variable"
}
assert(invoke is SimpleKotlinResolutionCandidate) {
"VariableAsFunction candidate is not allowed here: $invoke"
}
return VariableAsFunctionKotlinResolutionCandidate(kotlinCall, variable as SimpleKotlinResolutionCandidate, invoke as SimpleKotlinResolutionCandidate) override fun factoryForVariable(stripExplicitReceiver: Boolean): CandidateFactory<KotlinResolutionCandidate> {
}
override fun factoryForVariable(stripExplicitReceiver: Boolean): CandidateFactory<SimpleKotlinResolutionCandidate> {
val explicitReceiver = if (stripExplicitReceiver) null else kotlinCall.explicitReceiver val explicitReceiver = if (stripExplicitReceiver) null else kotlinCall.explicitReceiver
val variableCall = PSIKotlinCallForVariable(kotlinCall, explicitReceiver, kotlinCall.name) val variableCall = PSIKotlinCallForVariable(kotlinCall, explicitReceiver, kotlinCall.name)
return SimpleCandidateFactory(callComponents, scopeTower, variableCall) return SimpleCandidateFactory(callComponents, scopeTower, variableCall)
@@ -304,58 +304,59 @@ class PSICallResolver(
override fun factoryForInvoke(variable: KotlinResolutionCandidate, useExplicitReceiver: Boolean): override fun factoryForInvoke(variable: KotlinResolutionCandidate, useExplicitReceiver: Boolean):
Pair<ReceiverValueWithSmartCastInfo, CandidateFactory<KotlinResolutionCandidate>>? { Pair<ReceiverValueWithSmartCastInfo, CandidateFactory<KotlinResolutionCandidate>>? {
assert(variable is SimpleKotlinResolutionCandidate) { if (isRecursiveVariableResolution(variable)) return null
"VariableAsFunction variable is not allowed here: $variable"
}
if (isRecursiveVariableResolution(variable as SimpleKotlinResolutionCandidate)) return null
assert(variable.isSuccessful) { assert(variable.isSuccessful) {
"Variable call should be successful: $variable " + "Variable call should be successful: $variable " +
"Descriptor: ${variable.descriptorWithFreshTypes}" "Descriptor: ${variable.resolvedCall.candidateDescriptor}"
} }
val variableCallArgument = createReceiverCallArgument(variable) val variableCallArgument = createReceiverCallArgument(variable)
val explicitReceiver = kotlinCall.explicitReceiver val explicitReceiver = kotlinCall.explicitReceiver
val callForInvoke = if (useExplicitReceiver && explicitReceiver is SimpleKotlinCallArgument) { val callForInvoke = if (useExplicitReceiver && explicitReceiver is SimpleKotlinCallArgument) {
PSIKotlinCallForInvoke(kotlinCall, explicitReceiver, variableCallArgument) PSIKotlinCallForInvoke(kotlinCall, variable, explicitReceiver, variableCallArgument)
} }
else { else {
PSIKotlinCallForInvoke(kotlinCall, variableCallArgument, null) PSIKotlinCallForInvoke(kotlinCall, variable, variableCallArgument, null)
} }
return variableCallArgument.receiver to SimpleCandidateFactory(callComponents, scopeTower, callForInvoke) return variableCallArgument.receiver to SimpleCandidateFactory(callComponents, scopeTower, callForInvoke)
} }
// todo: create special check that there is no invoke on variable // todo: create special check that there is no invoke on variable
private fun isRecursiveVariableResolution(variable: SimpleKotlinResolutionCandidate): Boolean { private fun isRecursiveVariableResolution(variable: KotlinResolutionCandidate): Boolean {
val variableType = variable.candidateDescriptor.returnType val variableType = variable.resolvedCall.candidateDescriptor.returnType
return variableType is DeferredType && variableType.isComputing return variableType is DeferredType && variableType.isComputing
} }
// todo: review // todo: review
private fun createReceiverCallArgument(variable: SimpleKotlinResolutionCandidate): SimpleKotlinCallArgument { private fun createReceiverCallArgument(variable: KotlinResolutionCandidate): SimpleKotlinCallArgument {
variable.forceResolution()
val variableReceiver = createReceiverValueWithSmartCastInfo(variable) val variableReceiver = createReceiverValueWithSmartCastInfo(variable)
if (variableReceiver.possibleTypes.isNotEmpty()) { if (variableReceiver.possibleTypes.isNotEmpty()) {
return ReceiverExpressionKotlinCallArgument(createReceiverValueWithSmartCastInfo(variable), isVariableReceiverForInvoke = true) return ReceiverExpressionKotlinCallArgument(createReceiverValueWithSmartCastInfo(variable), isVariableReceiverForInvoke = true)
} }
val psiKotlinCall = variable.kotlinCall.psiKotlinCall val psiKotlinCall = variable.resolvedCall.atom.psiKotlinCall
val variableResult = CallResolutionResult(CallResolutionResult.Type.PARTIAL, variable.resolvedCall, listOf(), variable.getSystem().asReadOnlyStorage())
return SubKotlinCallArgumentImpl(CallMaker.makeExternalValueArgument((variableReceiver.receiverValue as ExpressionReceiver).expression), return SubKotlinCallArgumentImpl(CallMaker.makeExternalValueArgument((variableReceiver.receiverValue as ExpressionReceiver).expression),
psiKotlinCall.resultDataFlowInfo, psiKotlinCall.resultDataFlowInfo, variableReceiver, psiKotlinCall.resultDataFlowInfo, psiKotlinCall.resultDataFlowInfo, variableReceiver,
ResolvedKotlinCall.OnlyResolvedKotlinCall(variable)) variableResult)
} }
// todo: decrease hacks count // todo: decrease hacks count
private fun createReceiverValueWithSmartCastInfo(variable: SimpleKotlinResolutionCandidate): ReceiverValueWithSmartCastInfo { private fun createReceiverValueWithSmartCastInfo(variable: KotlinResolutionCandidate): ReceiverValueWithSmartCastInfo {
val callForVariable = variable.kotlinCall as PSIKotlinCallForVariable val callForVariable = variable.resolvedCall.atom as PSIKotlinCallForVariable
val calleeExpression = callForVariable.baseCall.psiCall.calleeExpression as? KtReferenceExpression ?: val calleeExpression = callForVariable.baseCall.psiCall.calleeExpression as? KtReferenceExpression ?:
error("Unexpected call : ${callForVariable.baseCall.psiCall}") error("Unexpected call : ${callForVariable.baseCall.psiCall}")
val temporaryTrace = TemporaryBindingTrace.create(context.trace, "Context for resolve candidate") val temporaryTrace = TemporaryBindingTrace.create(context.trace, "Context for resolve candidate")
val type = variable.descriptorWithFreshTypes.returnType!!.unwrap()
val type = variable.resolvedCall.freshReturnType!!
val variableReceiver = ExpressionReceiver.create(calleeExpression, type, temporaryTrace.bindingContext) val variableReceiver = ExpressionReceiver.create(calleeExpression, type, temporaryTrace.bindingContext)
temporaryTrace.record(BindingContext.REFERENCE_TARGET, calleeExpression, variable.descriptorWithFreshTypes) temporaryTrace.record(BindingContext.REFERENCE_TARGET, calleeExpression, variable.resolvedCall.candidateDescriptor)
val dataFlowValue = DataFlowValueFactory.createDataFlowValue(variableReceiver, temporaryTrace.bindingContext, context.scope.ownerDescriptor) val dataFlowValue = DataFlowValueFactory.createDataFlowValue(variableReceiver, temporaryTrace.bindingContext, context.scope.ownerDescriptor)
return ReceiverValueWithSmartCastInfo(variableReceiver, context.dataFlowInfo.getCollectedTypes(dataFlowValue), dataFlowValue.isStable) return ReceiverValueWithSmartCastInfo(variableReceiver, context.dataFlowInfo.getCollectedTypes(dataFlowValue), dataFlowValue.isStable)
} }
@@ -79,6 +79,7 @@ class PSIKotlinCallForVariable(
class PSIKotlinCallForInvoke( class PSIKotlinCallForInvoke(
val baseCall: PSIKotlinCallImpl, val baseCall: PSIKotlinCallImpl,
val variableCall: KotlinResolutionCandidate,
override val explicitReceiver: SimpleKotlinCallArgument, override val explicitReceiver: SimpleKotlinCallArgument,
override val dispatchReceiverForInvokeExtension: SimpleKotlinCallArgument? override val dispatchReceiverForInvokeExtension: SimpleKotlinCallArgument?
) : PSIKotlinCall() { ) : PSIKotlinCall() {
@@ -0,0 +1,201 @@
/*
* Copyright 2010-2017 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.kotlin.resolve.calls.tower
import org.jetbrains.kotlin.builtins.replaceReturnType
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.descriptors.impl.FunctionDescriptorImpl
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.BindingTrace
import org.jetbrains.kotlin.resolve.TemporaryBindingTrace
import org.jetbrains.kotlin.resolve.calls.ArgumentTypeResolver
import org.jetbrains.kotlin.resolve.calls.checkers.CallCheckerContext
import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext
import org.jetbrains.kotlin.resolve.calls.context.ContextDependency
import org.jetbrains.kotlin.resolve.calls.inference.components.NewTypeSubstitutor
import org.jetbrains.kotlin.resolve.calls.model.*
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind
import org.jetbrains.kotlin.resolve.calls.tasks.TracingStrategyImpl
import org.jetbrains.kotlin.resolve.calls.util.CallMaker
import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.expressions.DoubleColonExpressionResolver
import org.jetbrains.kotlin.types.expressions.ExpressionTypingServices
import org.jetbrains.kotlin.types.typeUtil.asTypeProjection
class ResolvedAtomCompleter(
private val resultSubstitutor: NewTypeSubstitutor,
private val trace: BindingTrace,
private val topLevelCallContext: BasicCallResolutionContext,
private val kotlinToResolvedCallTransformer: KotlinToResolvedCallTransformer,
private val expressionTypingServices: ExpressionTypingServices,
private val argumentTypeResolver: ArgumentTypeResolver,
private val doubleColonExpressionResolver: DoubleColonExpressionResolver,
languageVersionSettings: LanguageVersionSettings
) {
private val callCheckerContext = CallCheckerContext(topLevelCallContext, languageVersionSettings)
fun completeAndReport(resolvedAtom: ResolvedAtom) {
when (resolvedAtom) {
is ResolvedCollectionLiteralAtom -> completeCollectionLiteralCalls(resolvedAtom)
is ResolvedCallableReferenceAtom -> completeCallableReference(resolvedAtom)
is ResolvedLambdaAtom -> completeLambda(resolvedAtom)
is ResolvedCallAtom -> completeResolvedCall(resolvedAtom)
}
}
fun completeAll(resolvedAtom: ResolvedAtom) {
for (subKtPrimitive in resolvedAtom.subResolvedAtoms) {
completeAll(subKtPrimitive)
}
completeAndReport(resolvedAtom)
}
fun completeResolvedCall(resolvedCallAtom: ResolvedCallAtom): ResolvedCall<*>? {
if (resolvedCallAtom.atom.psiKotlinCall is PSIKotlinCallForVariable) return null
val resolvedCall = kotlinToResolvedCallTransformer.transformToResolvedCall<CallableDescriptor>(resolvedCallAtom, true, resultSubstitutor)
kotlinToResolvedCallTransformer.bindAndReport(topLevelCallContext, trace, resolvedCall)
kotlinToResolvedCallTransformer.runCallCheckers(resolvedCall, callCheckerContext)
val lastCall = if (resolvedCall is VariableAsFunctionResolvedCall) resolvedCall.functionCall else resolvedCall
kotlinToResolvedCallTransformer.runArgumentsChecks(topLevelCallContext, trace, lastCall as NewResolvedCallImpl<*>)
return resolvedCall
}
private fun completeLambda(lambda: ResolvedLambdaAtom) {
val returnType = resultSubstitutor.safeSubstitute(lambda.returnType)
updateTraceForLambdaReturnType(lambda, trace, returnType)
for (lambdaResult in lambda.resultArguments) {
val resultValueArgument = lambdaResult as? PSIKotlinCallArgument ?: continue
val newContext =
topLevelCallContext.replaceDataFlowInfo(resultValueArgument.dataFlowInfoAfterThisArgument)
.replaceExpectedType(returnType)
.replaceBindingTrace(trace)
val argumentExpression = resultValueArgument.valueArgument.getArgumentExpression() ?: continue
kotlinToResolvedCallTransformer.updateRecordedType(argumentExpression, newContext)
}
}
private fun updateTraceForLambdaReturnType(lambda: ResolvedLambdaAtom, trace: BindingTrace, returnType: UnwrappedType) {
val psiCallArgument = lambda.atom.psiCallArgument
val ktArgumentExpression: KtExpression
val ktFunction: KtElement
when (psiCallArgument) {
is LambdaKotlinCallArgumentImpl -> {
ktArgumentExpression = psiCallArgument.ktLambdaExpression
ktFunction = ktArgumentExpression.functionLiteral
}
is FunctionExpressionImpl -> {
ktArgumentExpression = psiCallArgument.ktFunction
ktFunction = ktArgumentExpression
}
else -> throw AssertionError("Unexpected psiCallArgument for resolved lambda argument: $psiCallArgument")
}
val functionDescriptor = trace.bindingContext.get(BindingContext.FUNCTION, ktFunction) as? FunctionDescriptorImpl ?:
throw AssertionError("No function descriptor for resolved lambda argument")
functionDescriptor.setReturnType(returnType)
val existingLambdaType = trace.getType(ktArgumentExpression) ?: throw AssertionError("No type for resolved lambda argument")
trace.recordType(ktArgumentExpression, existingLambdaType.replaceReturnType(returnType))
}
private fun completeCallableReference(
resolvedAtom: ResolvedCallableReferenceAtom
) {
val callableCandidate = resolvedAtom.candidate
if (callableCandidate == null) {
// todo report meanfull diagnostic here
return
}
val resultTypeParameters = callableCandidate.freshSubstitutor!!.freshVariables.map { resultSubstitutor.safeSubstitute(it.defaultType) }
val psiCallArgument = resolvedAtom.atom.psiCallArgument as CallableReferenceKotlinCallArgumentImpl
val callableReferenceExpression = psiCallArgument.ktCallableReferenceExpression
val resultSubstitutor = IndexedParametersSubstitution(callableCandidate.candidate.typeParameters, resultTypeParameters.map { it.asTypeProjection() }).buildSubstitutor()
// write down type for callable reference expression
val resultType = resultSubstitutor.safeSubstitute(callableCandidate.reflectionCandidateType, Variance.INVARIANT)
argumentTypeResolver.updateResultArgumentTypeIfNotDenotable(trace, expressionTypingServices.statementFilter,
resultType,
callableReferenceExpression)
val reference = callableReferenceExpression.callableReference
val explicitCallableReceiver = when (callableCandidate.explicitReceiverKind) {
ExplicitReceiverKind.DISPATCH_RECEIVER -> callableCandidate.dispatchReceiver
ExplicitReceiverKind.EXTENSION_RECEIVER -> callableCandidate.extensionReceiver
else -> null
}
val explicitReceiver = explicitCallableReceiver?.receiver
val psiCall = CallMaker.makeCall(reference, explicitReceiver?.receiverValue, null, reference, emptyList())
val tracing = TracingStrategyImpl.create(reference, psiCall)
val temporaryTrace = TemporaryBindingTrace.create(trace, "callable reference fake call")
val resolvedCall = ResolvedCallImpl(psiCall, callableCandidate.candidate, callableCandidate.dispatchReceiver?.receiver?.receiverValue,
callableCandidate.extensionReceiver?.receiver?.receiverValue, callableCandidate.explicitReceiverKind,
null, temporaryTrace, tracing, MutableDataFlowInfoForArguments.WithoutArgumentsCheck(DataFlowInfo.EMPTY))
resolvedCall.setResultingSubstitutor(resultSubstitutor)
tracing.bindCall(trace, psiCall)
tracing.bindReference(trace, resolvedCall)
tracing.bindResolvedCall(trace, resolvedCall)
resolvedCall.setStatusToSuccess()
resolvedCall.markCallAsCompleted()
when (callableCandidate.candidate) {
is FunctionDescriptor -> doubleColonExpressionResolver.bindFunctionReference(callableReferenceExpression, resultType, topLevelCallContext)
is PropertyDescriptor -> doubleColonExpressionResolver.bindPropertyReference(callableReferenceExpression, resultType, topLevelCallContext)
}
// TODO: probably we should also record key 'DATA_FLOW_INFO_BEFORE', see ExpressionTypingVisitorDispatcher.getTypeInfo
trace.recordType(callableReferenceExpression, resultType)
trace.record(BindingContext.PROCESSED, callableReferenceExpression)
doubleColonExpressionResolver.checkReferenceIsToAllowedMember(callableCandidate.candidate, topLevelCallContext.trace, callableReferenceExpression)
}
private fun completeCollectionLiteralCalls(collectionLiteralArgument: ResolvedCollectionLiteralAtom) {
val psiCallArgument = collectionLiteralArgument.atom.psiCallArgument as CollectionLiteralKotlinCallArgumentImpl
val context = psiCallArgument.outerCallContext
val expectedType = collectionLiteralArgument.expectedType?.let { resultSubstitutor.safeSubstitute(it) } ?: TypeUtils.NO_EXPECTED_TYPE
val actualContext = context
.replaceBindingTrace(trace)
.replaceExpectedType(expectedType)
.replaceContextDependency(ContextDependency.INDEPENDENT)
expressionTypingServices.getTypeInfo(psiCallArgument.collectionLiteralExpression, actualContext)
}
}
@@ -21,7 +21,6 @@ import org.jetbrains.kotlin.resolve.calls.components.KotlinResolutionCallbacks
import org.jetbrains.kotlin.resolve.calls.components.NewOverloadingConflictResolver import org.jetbrains.kotlin.resolve.calls.components.NewOverloadingConflictResolver
import org.jetbrains.kotlin.resolve.calls.context.CheckArgumentTypesMode import org.jetbrains.kotlin.resolve.calls.context.CheckArgumentTypesMode
import org.jetbrains.kotlin.resolve.calls.model.* import org.jetbrains.kotlin.resolve.calls.model.*
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind
import org.jetbrains.kotlin.resolve.calls.tower.* import org.jetbrains.kotlin.resolve.calls.tower.*
import org.jetbrains.kotlin.types.UnwrappedType import org.jetbrains.kotlin.types.UnwrappedType
import java.lang.UnsupportedOperationException import java.lang.UnsupportedOperationException
@@ -40,7 +39,7 @@ class KotlinCallResolver(
kotlinCall: KotlinCall, kotlinCall: KotlinCall,
expectedType: UnwrappedType?, expectedType: UnwrappedType?,
factoryProviderForInvoke: CandidateFactoryProviderForInvoke<KotlinResolutionCandidate> factoryProviderForInvoke: CandidateFactoryProviderForInvoke<KotlinResolutionCandidate>
): Collection<ResolvedKotlinCall> { ): CallResolutionResult {
kotlinCall.checkCallInvariants() kotlinCall.checkCallInvariants()
val candidateFactory = SimpleCandidateFactory(callComponents, scopeTower, kotlinCall) val candidateFactory = SimpleCandidateFactory(callComponents, scopeTower, kotlinCall)
@@ -56,43 +55,33 @@ class KotlinCallResolver(
val candidates = towerResolver.runResolve(scopeTower, processor, useOrder = kotlinCall.callKind != KotlinCallKind.UNSUPPORTED) val candidates = towerResolver.runResolve(scopeTower, processor, useOrder = kotlinCall.callKind != KotlinCallKind.UNSUPPORTED)
return choseMostSpecific(resolutionCallbacks, expectedType, candidates) return choseMostSpecific(candidateFactory, resolutionCallbacks, expectedType, candidates)
} }
fun resolveGivenCandidates( fun resolveGivenCandidates(
scopeTower: ImplicitScopeTower,
resolutionCallbacks: KotlinResolutionCallbacks, resolutionCallbacks: KotlinResolutionCallbacks,
kotlinCall: KotlinCall, kotlinCall: KotlinCall,
expectedType: UnwrappedType?, expectedType: UnwrappedType?,
givenCandidates: Collection<GivenCandidate> givenCandidates: Collection<GivenCandidate>
): Collection<ResolvedKotlinCall> { ): CallResolutionResult {
kotlinCall.checkCallInvariants() kotlinCall.checkCallInvariants()
val candidateFactory = SimpleCandidateFactory(callComponents, scopeTower, kotlinCall)
val isSafeCall = (kotlinCall.explicitReceiver as? SimpleKotlinCallArgument)?.isSafeCall ?: false val resolutionCandidates = givenCandidates.map { candidateFactory.createCandidate(it).forceResolution() }
val resolutionCandidates = givenCandidates.map {
SimpleKotlinResolutionCandidate(callComponents,
it.scopeTower,
kotlinCall,
if (it.dispatchReceiver == null) ExplicitReceiverKind.NO_EXPLICIT_RECEIVER else ExplicitReceiverKind.DISPATCH_RECEIVER,
it.dispatchReceiver?.let { ReceiverExpressionKotlinCallArgument(it, isSafeCall) },
null,
it.descriptor,
it.knownTypeParametersResultingSubstitutor,
listOf()
)
}
val candidates = towerResolver.runWithEmptyTowerData(KnownResultProcessor(resolutionCandidates), val candidates = towerResolver.runWithEmptyTowerData(KnownResultProcessor(resolutionCandidates),
TowerResolver.SuccessfulResultCollector(), TowerResolver.SuccessfulResultCollector(),
useOrder = true) useOrder = true)
return choseMostSpecific(resolutionCallbacks, expectedType, candidates) return choseMostSpecific(candidateFactory, resolutionCallbacks, expectedType, candidates)
} }
private fun choseMostSpecific( private fun choseMostSpecific(
candidateFactory: SimpleCandidateFactory,
resolutionCallbacks: KotlinResolutionCallbacks, resolutionCallbacks: KotlinResolutionCallbacks,
expectedType: UnwrappedType?, expectedType: UnwrappedType?,
candidates: Collection<KotlinResolutionCandidate> candidates: Collection<KotlinResolutionCandidate>
): Collection<ResolvedKotlinCall> { ): CallResolutionResult {
val isDebuggerContext = (candidates.firstOrNull() ?: return emptyList()).lastCall.scopeTower.isDebuggerContext val isDebuggerContext = candidateFactory.scopeTower.isDebuggerContext
val maximallySpecificCandidates = overloadingConflictResolver.chooseMaximallySpecificCandidates( val maximallySpecificCandidates = overloadingConflictResolver.chooseMaximallySpecificCandidates(
candidates, candidates,
@@ -100,16 +89,7 @@ class KotlinCallResolver(
discriminateGenerics = true, // todo discriminateGenerics = true, // todo
isDebuggerContext = isDebuggerContext) isDebuggerContext = isDebuggerContext)
val singleResult = maximallySpecificCandidates.singleOrNull()?.let { return kotlinCallCompleter.runCompletion(candidateFactory, maximallySpecificCandidates, expectedType, resolutionCallbacks)
kotlinCallCompleter.completeCallIfNecessary(it, expectedType, resolutionCallbacks)
}
if (singleResult != null) {
return listOf(singleResult)
}
return maximallySpecificCandidates.map {
kotlinCallCompleter.transformWhenAmbiguity(it, resolutionCallbacks)
}
} }
} }
@@ -21,17 +21,19 @@ import org.jetbrains.kotlin.descriptors.ReceiverParameterDescriptor
import org.jetbrains.kotlin.resolve.calls.model.* import org.jetbrains.kotlin.resolve.calls.model.*
import org.jetbrains.kotlin.types.UnwrappedType import org.jetbrains.kotlin.types.UnwrappedType
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
import org.jetbrains.kotlin.utils.SmartList
import org.jetbrains.kotlin.utils.addIfNotNull
// very initial state of component // very initial state of component
// todo: handle all diagnostic inside DiagnosticReporterByTrackingStrategy // todo: handle all diagnostic inside DiagnosticReporterByTrackingStrategy
// move it to frontend module
class AdditionalDiagnosticReporter { class AdditionalDiagnosticReporter {
fun createAdditionalDiagnostics( fun reportAdditionalDiagnostics(
candidate: SimpleKotlinResolutionCandidate, candidate: ResolvedCallAtom,
resultingDescriptor: CallableDescriptor resultingDescriptor: CallableDescriptor,
): List<KotlinCallDiagnostic> = reportSmartCasts(candidate, resultingDescriptor) kotlinDiagnosticsHolder: KotlinDiagnosticsHolder
) {
reportSmartCasts(candidate, resultingDescriptor, kotlinDiagnosticsHolder)
}
private fun createSmartCastDiagnostic(argument: KotlinCallArgument, expectedResultType: UnwrappedType): SmartCastDiagnostic? { private fun createSmartCastDiagnostic(argument: KotlinCallArgument, expectedResultType: UnwrappedType): SmartCastDiagnostic? {
if (argument !is ExpressionKotlinCallArgument) return null if (argument !is ExpressionKotlinCallArgument) return null
@@ -42,7 +44,7 @@ class AdditionalDiagnosticReporter {
} }
private fun reportSmartCastOnReceiver( private fun reportSmartCastOnReceiver(
candidate: SimpleKotlinResolutionCandidate, candidate: ResolvedCallAtom,
receiver: SimpleKotlinCallArgument?, receiver: SimpleKotlinCallArgument?,
parameter: ReceiverParameterDescriptor? parameter: ReceiverParameterDescriptor?
): SmartCastDiagnostic? { ): SmartCastDiagnostic? {
@@ -53,33 +55,36 @@ class AdditionalDiagnosticReporter {
// todo may be we have smart cast to Int? // todo may be we have smart cast to Int?
return smartCastDiagnostic.takeIf { return smartCastDiagnostic.takeIf {
candidate.getCandidateDiagnostics().filterIsInstance<UnsafeCallError>().none { candidate.diagnostics.filterIsInstance<UnsafeCallError>().none {
it.receiver == receiver it.receiver == receiver
} }
&& &&
candidate.getCandidateDiagnostics().filterIsInstance<UnstableSmartCast>().none { candidate.diagnostics.filterIsInstance<UnstableSmartCast>().none {
it.argument == receiver it.argument == receiver
} }
} }
} }
private fun reportSmartCasts(candidate: SimpleKotlinResolutionCandidate, resultingDescriptor: CallableDescriptor) = private fun reportSmartCasts(
SmartList<KotlinCallDiagnostic>().apply { candidate: ResolvedCallAtom,
addIfNotNull(reportSmartCastOnReceiver(candidate, candidate.extensionReceiver, resultingDescriptor.extensionReceiverParameter)) resultingDescriptor: CallableDescriptor,
addIfNotNull(reportSmartCastOnReceiver(candidate, candidate.dispatchReceiverArgument, resultingDescriptor.dispatchReceiverParameter)) kotlinDiagnosticsHolder: KotlinDiagnosticsHolder
) {
kotlinDiagnosticsHolder.addDiagnosticIfNotNull(reportSmartCastOnReceiver(candidate, candidate.extensionReceiverArgument, resultingDescriptor.extensionReceiverParameter))
kotlinDiagnosticsHolder.addDiagnosticIfNotNull(reportSmartCastOnReceiver(candidate, candidate.dispatchReceiverArgument, resultingDescriptor.dispatchReceiverParameter))
for (parameter in resultingDescriptor.valueParameters) { for (parameter in resultingDescriptor.valueParameters) {
for (argument in candidate.argumentMappingByOriginal[parameter.original]?.arguments ?: continue) { for (argument in candidate.argumentMappingByOriginal[parameter.original]?.arguments ?: continue) {
val smartCastDiagnostic = createSmartCastDiagnostic(argument, argument.getExpectedType(parameter)) ?: continue val smartCastDiagnostic = createSmartCastDiagnostic(argument, argument.getExpectedType(parameter)) ?: continue
val thereIsUnstableSmartCastError = candidate.getCandidateDiagnostics().filterIsInstance<UnstableSmartCast>().any { val thereIsUnstableSmartCastError = candidate.diagnostics.filterIsInstance<UnstableSmartCast>().any {
it.argument == argument it.argument == argument
} }
if (!thereIsUnstableSmartCastError) { if (!thereIsUnstableSmartCastError) {
add(smartCastDiagnostic) kotlinDiagnosticsHolder.addDiagnostic(smartCastDiagnostic)
}
}
} }
} }
}
}
} }
@@ -16,11 +16,13 @@
package org.jetbrains.kotlin.resolve.calls.components package org.jetbrains.kotlin.resolve.calls.components
import org.jetbrains.kotlin.descriptors.ParameterDescriptor
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
import org.jetbrains.kotlin.resolve.calls.model.KotlinCallArgument import org.jetbrains.kotlin.resolve.calls.model.KotlinCallArgument
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValueWithSmartCastInfo import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValueWithSmartCastInfo
import org.jetbrains.kotlin.types.UnwrappedType import org.jetbrains.kotlin.types.UnwrappedType
import org.jetbrains.kotlin.types.checker.intersectWrappedTypes import org.jetbrains.kotlin.types.checker.intersectWrappedTypes
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
internal fun unexpectedArgument(argument: KotlinCallArgument): Nothing = internal fun unexpectedArgument(argument: KotlinCallArgument): Nothing =
@@ -40,12 +42,12 @@ internal val ReceiverValueWithSmartCastInfo.stableType: UnwrappedType
return intersectWrappedTypes(possibleTypes + receiverValue.type) return intersectWrappedTypes(possibleTypes + receiverValue.type)
} }
internal fun KotlinCallArgument.getExpectedType(parameter: ValueParameterDescriptor) = internal fun KotlinCallArgument.getExpectedType(parameter: ParameterDescriptor) =
if (this.isSpread) { if (this.isSpread) {
parameter.type.unwrap() parameter.type.unwrap()
} }
else { else {
parameter.varargElementType?.unwrap() ?: parameter.type.unwrap() parameter.safeAs<ValueParameterDescriptor>()?.varargElementType?.unwrap() ?: parameter.type.unwrap()
} }
val ValueParameterDescriptor.isVararg: Boolean get() = varargElementType != null val ValueParameterDescriptor.isVararg: Boolean get() = varargElementType != null
@@ -21,7 +21,7 @@ import org.jetbrains.kotlin.builtins.getReturnTypeFromFunctionType
import org.jetbrains.kotlin.builtins.isFunctionType import org.jetbrains.kotlin.builtins.isFunctionType
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.resolve.calls.components.CreateDescriptorWithFreshTypeVariables.createToFreshVariableSubstitutorAndAddInitialConstraints import org.jetbrains.kotlin.resolve.calls.components.CreateFreshVariablesSubstitutor.createToFreshVariableSubstitutorAndAddInitialConstraints
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemOperation import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemOperation
import org.jetbrains.kotlin.resolve.calls.inference.components.FreshVariableNewTypeSubstitutor import org.jetbrains.kotlin.resolve.calls.inference.components.FreshVariableNewTypeSubstitutor
import org.jetbrains.kotlin.resolve.calls.inference.model.ArgumentConstraintPosition import org.jetbrains.kotlin.resolve.calls.inference.model.ArgumentConstraintPosition
@@ -72,6 +72,9 @@ class CallableReferenceCandidate(
) : Candidate { ) : Candidate {
override val resultingApplicability = getResultApplicability(diagnostics) override val resultingApplicability = getResultApplicability(diagnostics)
override val isSuccessful get() = resultingApplicability.isSuccess override val isSuccessful get() = resultingApplicability.isSuccess
var freshSubstitutor: FreshVariableNewTypeSubstitutor? = null
internal set
} }
/** /**
@@ -21,7 +21,6 @@ import org.jetbrains.kotlin.resolve.calls.context.CheckArgumentTypesMode
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilder import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilder
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemOperation import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemOperation
import org.jetbrains.kotlin.resolve.calls.inference.components.ConstraintInjector import org.jetbrains.kotlin.resolve.calls.inference.components.ConstraintInjector
import org.jetbrains.kotlin.resolve.calls.inference.components.ResultTypeResolver
import org.jetbrains.kotlin.resolve.calls.inference.components.SimpleConstraintSystemImpl import org.jetbrains.kotlin.resolve.calls.inference.components.SimpleConstraintSystemImpl
import org.jetbrains.kotlin.resolve.calls.model.* import org.jetbrains.kotlin.resolve.calls.model.*
import org.jetbrains.kotlin.resolve.calls.results.FlatSignature import org.jetbrains.kotlin.resolve.calls.results.FlatSignature
@@ -30,20 +29,20 @@ import org.jetbrains.kotlin.resolve.calls.results.TypeSpecificityComparator
import org.jetbrains.kotlin.resolve.calls.tower.ImplicitScopeTower import org.jetbrains.kotlin.resolve.calls.tower.ImplicitScopeTower
import org.jetbrains.kotlin.resolve.calls.tower.TowerResolver import org.jetbrains.kotlin.resolve.calls.tower.TowerResolver
import org.jetbrains.kotlin.types.UnwrappedType import org.jetbrains.kotlin.types.UnwrappedType
import org.jetbrains.kotlin.utils.addToStdlib.safeAs import org.jetbrains.kotlin.utils.SmartList
import org.jetbrains.kotlin.utils.addIfNotNull
class CallableReferenceOverloadConflictResolver( class CallableReferenceOverloadConflictResolver(
builtIns: KotlinBuiltIns, builtIns: KotlinBuiltIns,
specificityComparator: TypeSpecificityComparator, specificityComparator: TypeSpecificityComparator,
statelessCallbacks: KotlinResolutionStatelessCallbacks, statelessCallbacks: KotlinResolutionStatelessCallbacks,
constraintInjector: ConstraintInjector, constraintInjector: ConstraintInjector
typeResolver: ResultTypeResolver
) : OverloadingConflictResolver<CallableReferenceCandidate>( ) : OverloadingConflictResolver<CallableReferenceCandidate>(
builtIns, builtIns,
specificityComparator, specificityComparator,
{ it.candidate }, { it.candidate },
{ SimpleConstraintSystemImpl(constraintInjector, typeResolver) }, { SimpleConstraintSystemImpl(constraintInjector, builtIns) },
Companion::createFlatSignature, Companion::createFlatSignature,
{ null }, { null },
{ statelessCallbacks.isDescriptorFromSource(it) } { statelessCallbacks.isDescriptorFromSource(it) }
@@ -63,39 +62,50 @@ class CallableReferenceResolver(
fun processCallableReferenceArgument( fun processCallableReferenceArgument(
csBuilder: ConstraintSystemBuilder, csBuilder: ConstraintSystemBuilder,
postponedArgument: PostponedCallableReferenceArgument resolvedAtom: ResolvedCallableReferenceAtom
): KotlinCallDiagnostic? { ) {
postponedArgument.analyzed = true val argument = resolvedAtom.atom
val expectedType = resolvedAtom.expectedType?.let { csBuilder.buildCurrentSubstitutor().safeSubstitute(it) }
val argument = postponedArgument.argument
val expectedType = csBuilder.buildCurrentSubstitutor().safeSubstitute(postponedArgument.expectedType)
val subLHSCall = argument.lhsResult.safeAs<LHSResult.Expression>()?.lshCallArgument.safeAs<SubKotlinCallArgument>()
if (subLHSCall != null) {
csBuilder.addInnerCall(subLHSCall.resolvedCall)
}
val scopeTower = callComponents.statelessCallbacks.getScopeTowerForCallableReferenceArgument(argument) val scopeTower = callComponents.statelessCallbacks.getScopeTowerForCallableReferenceArgument(argument)
val candidates = runRHSResolution(scopeTower, argument, expectedType) { checkCallableReference -> val candidates = runRHSResolution(scopeTower, argument, expectedType) { checkCallableReference ->
csBuilder.runTransaction { checkCallableReference(this); false } csBuilder.runTransaction { checkCallableReference(this); false }
} }
val chosenCandidate = when (candidates.size) { val diagnostics = SmartList<KotlinCallDiagnostic>()
0 -> return NoneCallableReferenceCandidates(argument)
1 -> candidates.single() val chosenCandidate = candidates.singleOrNull()
else -> return CallableReferenceCandidatesAmbiguity(argument, candidates) if (chosenCandidate != null) {
val (toFreshSubstitutor, diagnostic) = with(chosenCandidate) {
csBuilder.checkCallableReference(argument, dispatchReceiver, extensionReceiver, candidate,
reflectionCandidateType, expectedType, scopeTower.lexicalScope.ownerDescriptor)
}
diagnostics.addIfNotNull(diagnostic)
chosenCandidate.freshSubstitutor = toFreshSubstitutor
} }
val (toFreshSubstitutor, diagnostic) = with(chosenCandidate) { else {
csBuilder.checkCallableReference(argument, dispatchReceiver, extensionReceiver, candidate, if (candidates.isEmpty()) {
reflectionCandidateType, expectedType, scopeTower.lexicalScope.ownerDescriptor) diagnostics.add(NoneCallableReferenceCandidates(argument))
}
else {
diagnostics.add(CallableReferenceCandidatesAmbiguity(argument, candidates))
}
} }
postponedArgument.analyzedAndThereIsResult = true // todo -- create this inside CallableReferencesCandidateFactory
postponedArgument.myTypeVariables = toFreshSubstitutor.freshVariables val subKtArguments = listOfNotNull(buildResolvedKtArgument(argument.lhsResult))
postponedArgument.callableResolutionCandidate = chosenCandidate
return diagnostic resolvedAtom.setAnalyzedResults(chosenCandidate, subKtArguments, diagnostics)
} }
private fun buildResolvedKtArgument(lhsResult: LHSResult): ResolvedAtom? {
if (lhsResult !is LHSResult.Expression) return null
val lshCallArgument = lhsResult.lshCallArgument
return when(lshCallArgument) {
is SubKotlinCallArgument -> lshCallArgument.callResult
is ExpressionKotlinCallArgument -> ResolvedExpressionAtom(lshCallArgument)
else -> unexpectedArgument(lshCallArgument)
}
}
private fun runRHSResolution( private fun runRHSResolution(
scopeTower: ImplicitScopeTower, scopeTower: ImplicitScopeTower,
@@ -31,6 +31,7 @@ interface KotlinResolutionStatelessCallbacks {
fun isHiddenInResolution(descriptor: DeclarationDescriptor, kotlinCall: KotlinCall): Boolean fun isHiddenInResolution(descriptor: DeclarationDescriptor, kotlinCall: KotlinCall): Boolean
fun isSuperExpression(receiver: SimpleKotlinCallArgument?): Boolean fun isSuperExpression(receiver: SimpleKotlinCallArgument?): Boolean
fun getScopeTowerForCallableReferenceArgument(argument: CallableReferenceKotlinCallArgument): ImplicitScopeTower fun getScopeTowerForCallableReferenceArgument(argument: CallableReferenceKotlinCallArgument): ImplicitScopeTower
fun getVariableCandidateIfInvoke(functionCall: KotlinCall): KotlinResolutionCandidate?
} }
// This components hold state (trace). Work with this carefully. // This components hold state (trace). Work with this carefully.
@@ -43,11 +44,5 @@ interface KotlinResolutionCallbacks {
expectedReturnType: UnwrappedType? // null means, that return type is not proper i.e. it depends on some type variables expectedReturnType: UnwrappedType? // null means, that return type is not proper i.e. it depends on some type variables
): List<SimpleKotlinCallArgument> ): List<SimpleKotlinCallArgument>
// todo this is hack for some client which try to read ResolvedCall from trace before all calls completed fun bindStubResolvedCallForCandidate(candidate: ResolvedCallAtom)
fun bindStubResolvedCallForCandidate(candidate: KotlinResolutionCandidate)
fun completeCallableReference(callableReferenceArgument: PostponedCallableReferenceArgument,
resultTypeParameters: List<UnwrappedType>)
fun completeCollectionLiteralCalls(collectionLiteralArgument: PostponedCollectionLiteralArgument)
} }
@@ -16,152 +16,82 @@
package org.jetbrains.kotlin.resolve.calls.components package org.jetbrains.kotlin.resolve.calls.components
import org.jetbrains.kotlin.descriptors.CallableDescriptor import org.jetbrains.kotlin.resolve.calls.inference.NewConstraintSystem
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.resolve.calls.inference.components.KotlinConstraintSystemCompleter import org.jetbrains.kotlin.resolve.calls.inference.components.KotlinConstraintSystemCompleter
import org.jetbrains.kotlin.resolve.calls.inference.components.KotlinConstraintSystemCompleter.ConstraintSystemCompletionMode import org.jetbrains.kotlin.resolve.calls.inference.components.KotlinConstraintSystemCompleter.ConstraintSystemCompletionMode
import org.jetbrains.kotlin.resolve.calls.inference.components.NewTypeSubstitutor import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintStorage
import org.jetbrains.kotlin.resolve.calls.inference.model.ExpectedTypeConstraintPosition import org.jetbrains.kotlin.resolve.calls.inference.model.ExpectedTypeConstraintPosition
import org.jetbrains.kotlin.resolve.calls.inference.returnTypeOrNothing
import org.jetbrains.kotlin.resolve.calls.inference.substituteAndApproximateCapturedTypes
import org.jetbrains.kotlin.resolve.calls.model.* import org.jetbrains.kotlin.resolve.calls.model.*
import org.jetbrains.kotlin.types.TypeApproximator import org.jetbrains.kotlin.resolve.calls.tower.forceResolution
import org.jetbrains.kotlin.types.TypeApproximatorConfiguration
import org.jetbrains.kotlin.types.TypeUtils import org.jetbrains.kotlin.types.TypeUtils
import org.jetbrains.kotlin.types.UnwrappedType import org.jetbrains.kotlin.types.UnwrappedType
import org.jetbrains.kotlin.types.checker.NewCapturedType
import org.jetbrains.kotlin.types.typeUtil.contains
class KotlinCallCompleter( class KotlinCallCompleter(
private val additionalDiagnosticReporter: AdditionalDiagnosticReporter,
private val postponedArgumentsAnalyzer: PostponedArgumentsAnalyzer, private val postponedArgumentsAnalyzer: PostponedArgumentsAnalyzer,
private val kotlinConstraintSystemCompleter: KotlinConstraintSystemCompleter private val kotlinConstraintSystemCompleter: KotlinConstraintSystemCompleter
) { ) {
interface Context { fun runCompletion(
val innerCalls: List<ResolvedKotlinCall.OnlyResolvedKotlinCall> factory: SimpleCandidateFactory,
fun buildResultingSubstitutor(): NewTypeSubstitutor candidates: Collection<KotlinResolutionCandidate>,
val postponedArguments: List<PostponedKotlinCallArgument>
val lambdaArguments: List<PostponedLambdaArgument>
}
fun transformWhenAmbiguity(candidate: KotlinResolutionCandidate, resolutionCallbacks: KotlinResolutionCallbacks): ResolvedKotlinCall =
toCompletedBaseResolvedCall(candidate.lastCall.constraintSystem.asCallCompleterContext(), candidate, resolutionCallbacks)
// todo investigate variable+function calls
fun completeCallIfNecessary(
candidate: KotlinResolutionCandidate,
expectedType: UnwrappedType?, expectedType: UnwrappedType?,
resolutionCallbacks: KotlinResolutionCallbacks resolutionCallbacks: KotlinResolutionCallbacks
): ResolvedKotlinCall { ): CallResolutionResult {
resolutionCallbacks.bindStubResolvedCallForCandidate(candidate) val diagnosticHolder = KotlinDiagnosticsHolder.SimpleHolder()
val topLevelCall = if (candidates.isEmpty()) {
when (candidate) { diagnosticHolder.addDiagnostic(NoneCandidatesCallDiagnostic(factory.kotlinCall))
is VariableAsFunctionKotlinResolutionCandidate -> candidate.invokeCandidate }
else -> candidate as SimpleKotlinResolutionCandidate if (candidates.size > 1) {
} diagnosticHolder.addDiagnostic(ManyCandidatesCallDiagnostic(factory.kotlinCall, candidates))
}
val candidate = candidates.singleOrNull()
var completionType = topLevelCall.prepareForCompletion(expectedType) // this is needed at least for non-local return checker, because when we analyze lambda we should already bind descriptor for outer call
val lastCall = candidate.lastCall candidate?.resolvedCall?.let { resolutionCallbacks.bindStubResolvedCallForCandidate(it) }
lastCall.runCompletion(completionType, resolutionCallbacks)
if (lastCall.constraintSystem.asConstraintSystemCompleterContext().canBeProper(lastCall.descriptorWithFreshTypes.returnTypeOrNothing)) { if (candidate == null || candidate.csBuilder.hasContradiction) {
completionType = ConstraintSystemCompletionMode.FULL val candidateForCompletion = candidate ?: factory.createErrorCandidate().forceResolution()
lastCall.runCompletion(completionType, resolutionCallbacks) candidateForCompletion.prepareForCompletion(expectedType)
runCompletion(candidateForCompletion.resolvedCall, ConstraintSystemCompletionMode.FULL, diagnosticHolder, candidateForCompletion.getSystem(), resolutionCallbacks)
return CallResolutionResult(CallResolutionResult.Type.ERROR, candidate?.resolvedCall, diagnosticHolder.getDiagnostics(), ConstraintStorage.Empty)
} }
return when (completionType) { val completionType = candidate.prepareForCompletion(expectedType)
ConstraintSystemCompletionMode.FULL -> toCompletedBaseResolvedCall(lastCall.constraintSystem.asCallCompleterContext(), candidate, resolutionCallbacks) val constraintSystem = candidate.getSystem()
ConstraintSystemCompletionMode.PARTIAL -> ResolvedKotlinCall.OnlyResolvedKotlinCall(candidate) runCompletion(candidate.resolvedCall, completionType, diagnosticHolder, constraintSystem, resolutionCallbacks)
return if (completionType == ConstraintSystemCompletionMode.FULL) {
CallResolutionResult(CallResolutionResult.Type.COMPLETED, candidate.resolvedCall, diagnosticHolder.getDiagnostics(), constraintSystem.asReadOnlyStorage())
} }
else {
CallResolutionResult(CallResolutionResult.Type.PARTIAL, candidate.resolvedCall, diagnosticHolder.getDiagnostics(), constraintSystem.asReadOnlyStorage())
}
} }
private fun SimpleKotlinResolutionCandidate.runCompletion(completionMode: ConstraintSystemCompletionMode, resolutionCallbacks: KotlinResolutionCallbacks) { private fun runCompletion(
kotlinConstraintSystemCompleter.runCompletion( resolvedCallAtom: ResolvedCallAtom,
constraintSystem.asConstraintSystemCompleterContext(), completionMode, descriptorWithFreshTypes.returnTypeOrNothing completionMode: ConstraintSystemCompletionMode,
) { diagnosticsHolder: KotlinDiagnosticsHolder,
constraintSystem: NewConstraintSystem,
resolutionCallbacks: KotlinResolutionCallbacks
) {
val returnType = resolvedCallAtom.freshReturnType ?: constraintSystem.builtIns.unitType
kotlinConstraintSystemCompleter.runCompletion(constraintSystem.asConstraintSystemCompleterContext(), completionMode, resolvedCallAtom, returnType) {
postponedArgumentsAnalyzer.analyze(constraintSystem.asPostponedArgumentsAnalyzerContext(), resolutionCallbacks, it) postponedArgumentsAnalyzer.analyze(constraintSystem.asPostponedArgumentsAnalyzerContext(), resolutionCallbacks, it)
} }
constraintSystem.diagnostics.forEach(diagnosticsHolder::addDiagnostic)
} }
private fun toCompletedBaseResolvedCall(
c: Context,
candidate: KotlinResolutionCandidate,
resolutionCallbacks: KotlinResolutionCallbacks
): ResolvedKotlinCall.CompletedResolvedKotlinCall {
val currentSubstitutor = c.buildResultingSubstitutor()
val completedCall = candidate.toCompletedCall(currentSubstitutor, isTopLevel = true)
val competedCalls = c.innerCalls.map {
it.candidate.toCompletedCall(currentSubstitutor, isTopLevel = false)
}
for (postponedArgument in c.postponedArguments) {
when (postponedArgument) {
is PostponedLambdaArgument -> {
postponedArgument.finalReturnType = currentSubstitutor.safeSubstitute(postponedArgument.returnType)
}
is PostponedCallableReferenceArgument -> {
val resultTypeParameters = postponedArgument.myTypeVariables.map { currentSubstitutor.safeSubstitute(it.defaultType) }
resolutionCallbacks.completeCallableReference(postponedArgument, resultTypeParameters)
}
is PostponedCollectionLiteralArgument -> {
resolutionCallbacks.completeCollectionLiteralCalls(postponedArgument)
}
}
}
return ResolvedKotlinCall.CompletedResolvedKotlinCall(completedCall, competedCalls, c.lambdaArguments)
}
private fun KotlinResolutionCandidate.toCompletedCall(substitutor: NewTypeSubstitutor, isTopLevel: Boolean): CompletedKotlinCall {
if (this is VariableAsFunctionKotlinResolutionCandidate) {
val variable = resolvedVariable.toCompletedCall(substitutor, isTopLevel = false)
val invoke = invokeCandidate.toCompletedCall(substitutor, isTopLevel)
return CompletedKotlinCall.VariableAsFunction(kotlinCall, variable, invoke)
}
return (this as SimpleKotlinResolutionCandidate).toCompletedCall(substitutor, isTopLevel)
}
private fun SimpleKotlinResolutionCandidate.toCompletedCall(substitutor: NewTypeSubstitutor, isTopLevel: Boolean): CompletedKotlinCall.Simple {
val containsCapturedTypes = descriptorWithFreshTypes.returnType?.contains { it is NewCapturedType } ?: false
val resultingDescriptor = when {
descriptorWithFreshTypes is FunctionDescriptor ||
(descriptorWithFreshTypes is PropertyDescriptor && (descriptorWithFreshTypes.typeParameters.isNotEmpty() || containsCapturedTypes)) ->
// this code is very suspicious. Now it is very useful for BE, because they cannot do nothing with captured types,
// but it seems like temporary solution.
descriptorWithFreshTypes.substituteAndApproximateCapturedTypes(substitutor)
else ->
descriptorWithFreshTypes
}
val typeArguments = descriptorWithFreshTypes.typeParameters.map {
val substituted = substitutor.safeSubstitute(typeVariablesForFreshTypeParameters[it.index].defaultType)
TypeApproximator().approximateToSuperType(substituted, TypeApproximatorConfiguration.CapturedTypesApproximation) ?: substituted
}
val diagnostics = computeDiagnostics(this, resultingDescriptor, isTopLevel)
return CompletedKotlinCall.Simple(kotlinCall, candidateDescriptor, resultingDescriptor, diagnostics, explicitReceiverKind,
dispatchReceiverArgument?.receiver, extensionReceiver?.receiver, typeArguments, argumentMappingByOriginal)
}
private fun computeDiagnostics(
candidate: SimpleKotlinResolutionCandidate,
resultingDescriptor: CallableDescriptor,
isTopLevel: Boolean
): List<KotlinCallDiagnostic> {
var diagnostics = candidate.getCandidateDiagnostics()
if (isTopLevel) {
diagnostics += candidate.constraintSystem.diagnostics
}
diagnostics += additionalDiagnosticReporter.createAdditionalDiagnostics(candidate, resultingDescriptor)
return diagnostics
}
// true if we should complete this call // true if we should complete this call
private fun SimpleKotlinResolutionCandidate.prepareForCompletion(expectedType: UnwrappedType?): ConstraintSystemCompletionMode { private fun KotlinResolutionCandidate.prepareForCompletion(expectedType: UnwrappedType?): ConstraintSystemCompletionMode {
val returnType = descriptorWithFreshTypes.returnType?.unwrap() ?: return ConstraintSystemCompletionMode.PARTIAL val unsubstitutedReturnType = resolvedCall.candidateDescriptor.returnType?.unwrap() ?: return ConstraintSystemCompletionMode.PARTIAL
val returnType = resolvedCall.substitutor.safeSubstitute(unsubstitutedReturnType)
if (expectedType != null && !TypeUtils.noExpectedType(expectedType)) { if (expectedType != null && !TypeUtils.noExpectedType(expectedType)) {
csBuilder.addSubtypeConstraint(returnType, expectedType, ExpectedTypeConstraintPosition(kotlinCall)) csBuilder.addSubtypeConstraint(returnType, expectedType, ExpectedTypeConstraintPosition(resolvedCall.atom))
} }
return if (expectedType != null || csBuilder.isProperType(returnType)) { return if (expectedType != null || csBuilder.isProperType(returnType)) {
@@ -18,7 +18,6 @@ package org.jetbrains.kotlin.resolve.calls.components
import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.resolve.calls.inference.components.ConstraintInjector import org.jetbrains.kotlin.resolve.calls.inference.components.ConstraintInjector
import org.jetbrains.kotlin.resolve.calls.inference.components.ResultTypeResolver
import org.jetbrains.kotlin.resolve.calls.inference.components.SimpleConstraintSystemImpl import org.jetbrains.kotlin.resolve.calls.inference.components.SimpleConstraintSystemImpl
import org.jetbrains.kotlin.resolve.calls.model.* import org.jetbrains.kotlin.resolve.calls.model.*
import org.jetbrains.kotlin.resolve.calls.results.FlatSignature import org.jetbrains.kotlin.resolve.calls.results.FlatSignature
@@ -32,32 +31,30 @@ class NewOverloadingConflictResolver(
builtIns: KotlinBuiltIns, builtIns: KotlinBuiltIns,
specificityComparator: TypeSpecificityComparator, specificityComparator: TypeSpecificityComparator,
statelessCallbacks: KotlinResolutionStatelessCallbacks, statelessCallbacks: KotlinResolutionStatelessCallbacks,
constraintInjector: ConstraintInjector, constraintInjector: ConstraintInjector
typeResolver: ResultTypeResolver
) : OverloadingConflictResolver<KotlinResolutionCandidate>( ) : OverloadingConflictResolver<KotlinResolutionCandidate>(
builtIns, builtIns,
specificityComparator, specificityComparator,
{ {
// todo investigate // todo investigate
(it as? VariableAsFunctionKotlinResolutionCandidate)?.invokeCandidate?.candidateDescriptor ?: it.resolvedCall.candidateDescriptor
(it as SimpleKotlinResolutionCandidate).candidateDescriptor
}, },
{ SimpleConstraintSystemImpl(constraintInjector, typeResolver) }, { SimpleConstraintSystemImpl(constraintInjector, builtIns) },
Companion::createFlatSignature, Companion::createFlatSignature,
{ (it as? VariableAsFunctionKotlinResolutionCandidate)?.resolvedVariable }, { it.variableCandidateIfInvoke },
{ statelessCallbacks.isDescriptorFromSource(it) } { statelessCallbacks.isDescriptorFromSource(it) }
) { ) {
companion object { companion object {
private fun createFlatSignature(candidate: KotlinResolutionCandidate): FlatSignature<KotlinResolutionCandidate> { private fun createFlatSignature(candidate: KotlinResolutionCandidate): FlatSignature<KotlinResolutionCandidate> {
val simpleCandidate = (candidate as? VariableAsFunctionKotlinResolutionCandidate)?.invokeCandidate ?: (candidate as SimpleKotlinResolutionCandidate)
val originalDescriptor = simpleCandidate.descriptorWithFreshTypes.original val resolvedCall = candidate.resolvedCall
val originalDescriptor = resolvedCall.candidateDescriptor.original
val originalValueParameters = originalDescriptor.valueParameters val originalValueParameters = originalDescriptor.valueParameters
var numDefaults = 0 var numDefaults = 0
val valueArgumentToParameterType = HashMap<KotlinCallArgument, KotlinType>() val valueArgumentToParameterType = HashMap<KotlinCallArgument, KotlinType>()
for ((valueParameter, resolvedValueArgument) in simpleCandidate.argumentMappingByOriginal) { for ((valueParameter, resolvedValueArgument) in resolvedCall.argumentMappingByOriginal) {
if (resolvedValueArgument is ResolvedCallArgument.DefaultArgument) { if (resolvedValueArgument is ResolvedCallArgument.DefaultArgument) {
numDefaults++ numDefaults++
} }
@@ -73,8 +70,8 @@ class NewOverloadingConflictResolver(
return FlatSignature.create(candidate, return FlatSignature.create(candidate,
originalDescriptor, originalDescriptor,
numDefaults, numDefaults,
simpleCandidate.kotlinCall.argumentsInParenthesis.map { valueArgumentToParameterType[it] } + resolvedCall.atom.argumentsInParenthesis.map { valueArgumentToParameterType[it] } +
listOfNotNull(simpleCandidate.kotlinCall.externalArgument?.let { valueArgumentToParameterType[it] }) listOfNotNull(resolvedCall.atom.externalArgument?.let { valueArgumentToParameterType[it] })
) )
} }
@@ -17,6 +17,7 @@
package org.jetbrains.kotlin.resolve.calls.components package org.jetbrains.kotlin.resolve.calls.components
import org.jetbrains.kotlin.builtins.* import org.jetbrains.kotlin.builtins.*
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilder import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilder
import org.jetbrains.kotlin.resolve.calls.inference.model.ArgumentConstraintPosition import org.jetbrains.kotlin.resolve.calls.inference.model.ArgumentConstraintPosition
import org.jetbrains.kotlin.resolve.calls.inference.model.TypeVariableForLambdaReturnType import org.jetbrains.kotlin.resolve.calls.inference.model.TypeVariableForLambdaReturnType
@@ -25,94 +26,93 @@ import org.jetbrains.kotlin.types.UnwrappedType
import org.jetbrains.kotlin.types.typeUtil.builtIns import org.jetbrains.kotlin.types.typeUtil.builtIns
import org.jetbrains.kotlin.utils.addToStdlib.safeAs import org.jetbrains.kotlin.utils.addToStdlib.safeAs
fun createPostponedArgumentAndPerformInitialChecks( fun resolveKtPrimitive(
csBuilder: ConstraintSystemBuilder, csBuilder: ConstraintSystemBuilder,
argument: PostponableKotlinCallArgument, argument: KotlinCallArgument,
expectedType: UnwrappedType expectedType: UnwrappedType?,
): KotlinCallDiagnostic? { diagnosticsHolder: KotlinDiagnosticsHolder,
val (postponedArgument, diagnostic) = when (argument) { isReceiver: Boolean
is LambdaKotlinCallArgument -> preprocessLambdaArgument(csBuilder, argument, expectedType) ): ResolvedAtom = when (argument) {
is CallableReferenceKotlinCallArgument -> preprocessCallableReference(csBuilder, argument, expectedType) is SimpleKotlinCallArgument -> checkSimpleArgument(csBuilder, argument, expectedType, diagnosticsHolder, isReceiver)
is CollectionLiteralKotlinCallArgument -> preprocessCollectionLiteralArgument(csBuilder, argument, expectedType) is LambdaKotlinCallArgument -> preprocessLambdaArgument(csBuilder, argument, expectedType)
else -> unexpectedArgument(argument) is CallableReferenceKotlinCallArgument -> preprocessCallableReference(csBuilder, argument, expectedType, diagnosticsHolder)
} is CollectionLiteralKotlinCallArgument -> preprocessCollectionLiteralArgument(argument, expectedType)
csBuilder.addPostponedArgument(postponedArgument) else -> unexpectedArgument(argument)
return diagnostic
} }
// if expected type isn't function type, then may be it is Function<R>, Any or just `T` // if expected type isn't function type, then may be it is Function<R>, Any or just `T`
private fun preprocessLambdaArgument( private fun preprocessLambdaArgument(
csBuilder: ConstraintSystemBuilder, csBuilder: ConstraintSystemBuilder,
argument: LambdaKotlinCallArgument, argument: LambdaKotlinCallArgument,
expectedType: UnwrappedType expectedType: UnwrappedType?
): Pair<PostponedLambdaArgument, KotlinCallDiagnostic?> { ): ResolvedAtom {
val builtIns = expectedType.builtIns val builtIns = csBuilder.builtIns
val isSuspend = expectedType.isSuspendFunctionType val isSuspend = expectedType?.isSuspendFunctionType ?: false
val receiverType: UnwrappedType? // null means that there is no receiver val receiverType: UnwrappedType? // null means that there is no receiver
val parameters: List<UnwrappedType> val parameters: List<UnwrappedType>
val returnType: UnwrappedType val returnType: UnwrappedType
val typeVariable = TypeVariableForLambdaReturnType(argument, builtIns, "_L")
if (expectedType.isBuiltinFunctionalType) { if (expectedType?.isBuiltinFunctionalType == true) {
receiverType = if (argument is FunctionExpression) argument.receiverType else expectedType.getReceiverTypeFromFunctionType()?.unwrap() receiverType = if (argument is FunctionExpression) argument.receiverType else expectedType.getReceiverTypeFromFunctionType()?.unwrap()
val expectedParameters = expectedType.getValueParameterTypesFromFunctionType() val expectedParameters = expectedType.getValueParameterTypesFromFunctionType()
if (argument.parametersTypes != null) { parameters = if (argument.parametersTypes != null) {
parameters = argument.parametersTypes!!.mapIndexed { argument.parametersTypes!!.mapIndexed {
index, type -> index, type ->
type ?: expectedParameters.getOrNull(index)?.type?.unwrap() ?: builtIns.nullableAnyType type ?: expectedParameters.getOrNull(index)?.type?.unwrap() ?: builtIns.nullableAnyType
} }
} }
else { else {
// lambda without explicit parameters: { } // lambda without explicit parameters: { }
parameters = expectedParameters.map { it.type.unwrap() } expectedParameters.map { it.type.unwrap() }
} }
returnType = argument.safeAs<FunctionExpression>()?.returnType ?: expectedType.getReturnTypeFromFunctionType().unwrap() returnType = argument.safeAs<FunctionExpression>()?.returnType ?: expectedType.getReturnTypeFromFunctionType().unwrap()
} }
else { else {
val isFunctionSupertype = KotlinBuiltIns.isNotNullOrNullableFunctionSupertype(expectedType) val isFunctionSupertype = expectedType != null && KotlinBuiltIns.isNotNullOrNullableFunctionSupertype(expectedType)
receiverType = argument.safeAs<FunctionExpression>()?.receiverType receiverType = argument.safeAs<FunctionExpression>()?.receiverType
parameters = argument.parametersTypes?.map { it ?: builtIns.nothingType } ?: emptyList() parameters = argument.parametersTypes?.map { it ?: builtIns.nothingType } ?: emptyList()
returnType = argument.safeAs<FunctionExpression>()?.returnType ?: returnType = argument.safeAs<FunctionExpression>()?.returnType ?:
expectedType.arguments.singleOrNull()?.type?.unwrap()?.takeIf { isFunctionSupertype } ?: expectedType?.arguments?.singleOrNull()?.type?.unwrap()?.takeIf { isFunctionSupertype } ?:
createFreshTypeVariableForLambdaReturnType(csBuilder, argument, builtIns) typeVariable.defaultType
// what about case where expected type is type variable? In old TY such cases was not supported. => do nothing for now. todo design // what about case where expected type is type variable? In old TY such cases was not supported. => do nothing for now. todo design
} }
val resolvedArgument = PostponedLambdaArgument(argument, isSuspend, receiverType, parameters, returnType) val newTypeVariableUsed = returnType == typeVariable.defaultType
if (newTypeVariableUsed) csBuilder.registerVariable(typeVariable)
csBuilder.addSubtypeConstraint(resolvedArgument.type, expectedType, ArgumentConstraintPosition(argument)) if (expectedType != null) {
val lambdaType = createFunctionType(returnType.builtIns, Annotations.EMPTY, receiverType, parameters, null, returnType, isSuspend)
csBuilder.addSubtypeConstraint(lambdaType, expectedType, ArgumentConstraintPosition(argument))
}
return resolvedArgument to null return ResolvedLambdaAtom(argument, isSuspend, receiverType, parameters, returnType, typeVariable.takeIf { newTypeVariableUsed })
}
private fun createFreshTypeVariableForLambdaReturnType(
csBuilder: ConstraintSystemBuilder,
argument: LambdaKotlinCallArgument,
builtIns: KotlinBuiltIns
): UnwrappedType {
val typeVariable = TypeVariableForLambdaReturnType(argument, builtIns, "_L")
csBuilder.registerVariable(typeVariable)
return typeVariable.defaultType
} }
private fun preprocessCallableReference( private fun preprocessCallableReference(
csBuilder: ConstraintSystemBuilder, csBuilder: ConstraintSystemBuilder,
argument: CallableReferenceKotlinCallArgument, argument: CallableReferenceKotlinCallArgument,
expectedType: UnwrappedType expectedType: UnwrappedType?,
): Pair<PostponedCallableReferenceArgument, KotlinCallDiagnostic?> { diagnosticsHolder: KotlinDiagnosticsHolder
): ResolvedAtom {
val result = ResolvedCallableReferenceAtom(argument, expectedType)
if (expectedType == null) return result
val notCallableTypeConstructor = csBuilder.getProperSuperTypeConstructors(expectedType).firstOrNull { !ReflectionTypes.isPossibleExpectedCallableType(it) } val notCallableTypeConstructor = csBuilder.getProperSuperTypeConstructors(expectedType).firstOrNull { !ReflectionTypes.isPossibleExpectedCallableType(it) }
val diagnostic = notCallableTypeConstructor?.let { NotCallableExpectedType(argument, expectedType, notCallableTypeConstructor) } if (notCallableTypeConstructor != null) {
return PostponedCallableReferenceArgument(argument, expectedType) to diagnostic diagnosticsHolder.addDiagnostic(NotCallableExpectedType(argument, expectedType, notCallableTypeConstructor))
}
return result
} }
private fun preprocessCollectionLiteralArgument( private fun preprocessCollectionLiteralArgument(
csBuilder: ConstraintSystemBuilder,
collectionLiteralArgument: CollectionLiteralKotlinCallArgument, collectionLiteralArgument: CollectionLiteralKotlinCallArgument,
expectedType: UnwrappedType expectedType: UnwrappedType?
): Pair<PostponedCollectionLiteralArgument, KotlinCallDiagnostic?> { ): ResolvedAtom {
// todo add some checks about expected type // todo add some checks about expected type
return PostponedCollectionLiteralArgument(collectionLiteralArgument, expectedType) to null return ResolvedCollectionLiteralAtom(collectionLiteralArgument, expectedType)
} }
@@ -17,12 +17,11 @@
package org.jetbrains.kotlin.resolve.calls.components package org.jetbrains.kotlin.resolve.calls.components
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilder import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilder
import org.jetbrains.kotlin.resolve.calls.inference.addSubsystemForArgument
import org.jetbrains.kotlin.resolve.calls.inference.components.NewTypeSubstitutor import org.jetbrains.kotlin.resolve.calls.inference.components.NewTypeSubstitutor
import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintStorage
import org.jetbrains.kotlin.resolve.calls.inference.model.LambdaArgumentConstraintPosition import org.jetbrains.kotlin.resolve.calls.inference.model.LambdaArgumentConstraintPosition
import org.jetbrains.kotlin.resolve.calls.model.PostponedCallableReferenceArgument import org.jetbrains.kotlin.resolve.calls.model.*
import org.jetbrains.kotlin.resolve.calls.model.PostponedCollectionLiteralArgument
import org.jetbrains.kotlin.resolve.calls.model.PostponedKotlinCallArgument
import org.jetbrains.kotlin.resolve.calls.model.PostponedLambdaArgument
import org.jetbrains.kotlin.types.UnwrappedType import org.jetbrains.kotlin.types.UnwrappedType
import org.jetbrains.kotlin.types.typeUtil.builtIns import org.jetbrains.kotlin.types.typeUtil.builtIns
@@ -36,34 +35,42 @@ class PostponedArgumentsAnalyzer(
fun canBeProper(type: UnwrappedType): Boolean fun canBeProper(type: UnwrappedType): Boolean
// mutable operations // mutable operations
fun addOtherSystem(otherSystem: ConstraintStorage)
fun getBuilder(): ConstraintSystemBuilder fun getBuilder(): ConstraintSystemBuilder
} }
fun analyze(c: Context, resolutionCallbacks: KotlinResolutionCallbacks, argument: PostponedKotlinCallArgument) { fun analyze(c: Context, resolutionCallbacks: KotlinResolutionCallbacks, argument: ResolvedAtom) {
when (argument) { when (argument) {
is PostponedLambdaArgument -> analyzeLambda(c, resolutionCallbacks, argument) is ResolvedLambdaAtom -> analyzeLambda(c, resolutionCallbacks, argument)
is PostponedCallableReferenceArgument -> callableReferenceResolver.processCallableReferenceArgument(c.getBuilder(), argument) is ResolvedCallableReferenceAtom -> callableReferenceResolver.processCallableReferenceArgument(c.getBuilder(), argument)
is PostponedCollectionLiteralArgument -> TODO("Not supported") is ResolvedCollectionLiteralAtom -> TODO("Not supported")
else -> error("Unexpected resolved primitive: ${argument.javaClass.canonicalName}")
} }
} }
private fun analyzeLambda(c: Context, resolutionCallbacks: KotlinResolutionCallbacks, lambda: PostponedLambdaArgument) { private fun analyzeLambda(c: Context, resolutionCallbacks: KotlinResolutionCallbacks, lambda: ResolvedLambdaAtom) {
val currentSubstitutor = c.buildCurrentSubstitutor() val currentSubstitutor = c.buildCurrentSubstitutor()
fun substitute(type: UnwrappedType) = currentSubstitutor.safeSubstitute(type) fun substitute(type: UnwrappedType) = currentSubstitutor.safeSubstitute(type)
val receiver = lambda.receiver?.let(::substitute) val receiver = lambda.receiver?.let(::substitute)
val parameters = lambda.parameters.map(::substitute) val parameters = lambda.parameters.map(::substitute)
val expectedType = lambda.returnType.takeIf { c.canBeProper(it) }?.let(::substitute) val expectedType = lambda.returnType.takeIf { c.canBeProper(it) }?.let(::substitute)
lambda.analyzed = true
lambda.resultArguments = resolutionCallbacks.analyzeAndGetLambdaResultArguments(lambda.argument, lambda.isSuspend, receiver, parameters, expectedType)
for (resultLambdaArgument in lambda.resultArguments) { val resultArguments = resolutionCallbacks.analyzeAndGetLambdaResultArguments(lambda.atom, lambda.isSuspend, receiver, parameters, expectedType)
checkSimpleArgument(c.getBuilder(), resultLambdaArgument, lambda.returnType.let(::substitute))
resultArguments.forEach { c.addSubsystemForArgument(it) }
val diagnosticHolder = KotlinDiagnosticsHolder.SimpleHolder()
val subResolvedKtPrimitives = resultArguments.map {
checkSimpleArgument(c.getBuilder(), it, lambda.returnType.let(::substitute), diagnosticHolder, isReceiver = false)
} }
if (lambda.resultArguments.isEmpty()) { if (resultArguments.isEmpty()) {
val unitType = lambda.returnType.builtIns.unitType val unitType = lambda.returnType.builtIns.unitType
c.getBuilder().addSubtypeConstraint(lambda.returnType.let(::substitute), unitType, LambdaArgumentConstraintPosition(lambda)) c.getBuilder().addSubtypeConstraint(lambda.returnType.let(::substitute), unitType, LambdaArgumentConstraintPosition(lambda))
} }
lambda.setAnalyzedResults(resultArguments, subResolvedKtPrimitives, diagnosticHolder.getDiagnostics())
} }
} }
@@ -31,114 +31,127 @@ import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind.*
import org.jetbrains.kotlin.resolve.calls.tower.InfixCallNoInfixModifier import org.jetbrains.kotlin.resolve.calls.tower.InfixCallNoInfixModifier
import org.jetbrains.kotlin.resolve.calls.tower.InvokeConventionCallNoOperatorModifier import org.jetbrains.kotlin.resolve.calls.tower.InvokeConventionCallNoOperatorModifier
import org.jetbrains.kotlin.resolve.calls.tower.VisibilityError import org.jetbrains.kotlin.resolve.calls.tower.VisibilityError
import org.jetbrains.kotlin.resolve.calls.tower.isSuccess import org.jetbrains.kotlin.types.ErrorUtils
import org.jetbrains.kotlin.utils.SmartList import org.jetbrains.kotlin.utils.addToStdlib.safeAs
import org.jetbrains.kotlin.utils.addIfNotNull
internal object CheckInstantiationOfAbstractClass : ResolutionPart { internal object CheckInstantiationOfAbstractClass : ResolutionPart() {
override fun SimpleKotlinResolutionCandidate.process(): List<KotlinCallDiagnostic> { override fun KotlinResolutionCandidate.process(workIndex: Int) {
if (candidateDescriptor is ConstructorDescriptor && !callComponents.statelessCallbacks.isSuperOrDelegatingConstructorCall(kotlinCall)) { val candidateDescriptor = resolvedCall.candidateDescriptor
if (candidateDescriptor is ConstructorDescriptor &&
!callComponents.statelessCallbacks.isSuperOrDelegatingConstructorCall(resolvedCall.atom)) {
if (candidateDescriptor.constructedClass.modality == Modality.ABSTRACT) { if (candidateDescriptor.constructedClass.modality == Modality.ABSTRACT) {
return listOf(InstantiationOfAbstractClass) addDiagnostic(InstantiationOfAbstractClass)
} }
} }
return emptyList()
} }
} }
internal object CheckVisibility : ResolutionPart { internal object CheckVisibility : ResolutionPart() {
override fun SimpleKotlinResolutionCandidate.process(): List<KotlinCallDiagnostic> { override fun KotlinResolutionCandidate.process(workIndex: Int) {
val containingDescriptor = scopeTower.lexicalScope.ownerDescriptor
val dispatchReceiverArgument = resolvedCall.dispatchReceiverArgument
val receiverValue = dispatchReceiverArgument?.receiver?.receiverValue ?: Visibilities.ALWAYS_SUITABLE_RECEIVER val receiverValue = dispatchReceiverArgument?.receiver?.receiverValue ?: Visibilities.ALWAYS_SUITABLE_RECEIVER
val invisibleMember = Visibilities.findInvisibleMember(receiverValue, candidateDescriptor, containingDescriptor) ?: return emptyList() val invisibleMember = Visibilities.findInvisibleMember(receiverValue, resolvedCall.candidateDescriptor, containingDescriptor) ?: return
if (dispatchReceiverArgument is ExpressionKotlinCallArgument) { if (dispatchReceiverArgument is ExpressionKotlinCallArgument) {
val smartCastReceiver = getReceiverValueWithSmartCast(receiverValue, dispatchReceiverArgument.receiver.stableType) val smartCastReceiver = getReceiverValueWithSmartCast(receiverValue, dispatchReceiverArgument.receiver.stableType)
if (Visibilities.findInvisibleMember(smartCastReceiver, candidateDescriptor, containingDescriptor) == null) { if (Visibilities.findInvisibleMember(smartCastReceiver, candidateDescriptor, containingDescriptor) == null) {
return listOf(SmartCastDiagnostic(dispatchReceiverArgument, dispatchReceiverArgument.receiver.stableType)) addDiagnostic(SmartCastDiagnostic(dispatchReceiverArgument, dispatchReceiverArgument.receiver.stableType))
return
} }
} }
return listOf(VisibilityError(invisibleMember)) addDiagnostic(VisibilityError(invisibleMember))
}
private val SimpleKotlinResolutionCandidate.containingDescriptor: DeclarationDescriptor get() = scopeTower.lexicalScope.ownerDescriptor
}
internal object MapTypeArguments : ResolutionPart {
override fun SimpleKotlinResolutionCandidate.process(): List<KotlinCallDiagnostic> {
typeArgumentMappingByOriginal = callComponents.typeArgumentsToParametersMapper.mapTypeArguments(kotlinCall, candidateDescriptor.original)
return typeArgumentMappingByOriginal.diagnostics
} }
} }
internal object NoTypeArguments : ResolutionPart { internal object MapTypeArguments : ResolutionPart() {
override fun SimpleKotlinResolutionCandidate.process(): List<KotlinCallDiagnostic> { override fun KotlinResolutionCandidate.process(workIndex: Int) {
resolvedCall.typeArgumentMappingByOriginal =
callComponents.typeArgumentsToParametersMapper.mapTypeArguments(kotlinCall, candidateDescriptor.original).also {
it.diagnostics.forEach(this@process::addDiagnostic)
}
}
}
internal object NoTypeArguments : ResolutionPart() {
override fun KotlinResolutionCandidate.process(workIndex: Int) {
assert(kotlinCall.typeArguments.isEmpty()) { assert(kotlinCall.typeArguments.isEmpty()) {
"Variable call cannot has explicit type arguments: ${kotlinCall.typeArguments}. Call: $kotlinCall" "Variable call cannot has explicit type arguments: ${kotlinCall.typeArguments}. Call: $kotlinCall"
} }
typeArgumentMappingByOriginal = NoExplicitArguments resolvedCall.typeArgumentMappingByOriginal = NoExplicitArguments
return typeArgumentMappingByOriginal.diagnostics
} }
} }
internal object MapArguments : ResolutionPart { internal object MapArguments : ResolutionPart() {
override fun SimpleKotlinResolutionCandidate.process(): List<KotlinCallDiagnostic> { override fun KotlinResolutionCandidate.process(workIndex: Int) {
val mapping = callComponents.argumentsToParametersMapper.mapArguments(kotlinCall, candidateDescriptor) val mapping = callComponents.argumentsToParametersMapper.mapArguments(kotlinCall, candidateDescriptor)
argumentMappingByOriginal = mapping.parameterToCallArgumentMap mapping.diagnostics.forEach(this::addDiagnostic)
return mapping.diagnostics
resolvedCall.argumentMappingByOriginal = mapping.parameterToCallArgumentMap
} }
} }
internal object NoArguments : ResolutionPart { internal object ArgumentsToCandidateParameterDescriptor : ResolutionPart() {
override fun SimpleKotlinResolutionCandidate.process(): List<KotlinCallDiagnostic> { override fun KotlinResolutionCandidate.process(workIndex: Int) {
val map = hashMapOf<KotlinCallArgument, ValueParameterDescriptor>()
for ((originalValueParameter, resolvedCallArgument) in resolvedCall.argumentMappingByOriginal) {
val valueParameter = candidateDescriptor.valueParameters.getOrNull(originalValueParameter.index) ?: continue
for (argument in resolvedCallArgument.arguments) {
map[argument] = valueParameter
}
}
resolvedCall.argumentToCandidateParameter = map
}
}
internal object NoArguments : ResolutionPart() {
override fun KotlinResolutionCandidate.process(workIndex: Int) {
assert(kotlinCall.argumentsInParenthesis.isEmpty()) { assert(kotlinCall.argumentsInParenthesis.isEmpty()) {
"Variable call cannot has arguments: ${kotlinCall.argumentsInParenthesis}. Call: $kotlinCall" "Variable call cannot has arguments: ${kotlinCall.argumentsInParenthesis}. Call: $kotlinCall"
} }
assert(kotlinCall.externalArgument == null) { assert(kotlinCall.externalArgument == null) {
"Variable call cannot has external argument: ${kotlinCall.externalArgument}. Call: $kotlinCall" "Variable call cannot has external argument: ${kotlinCall.externalArgument}. Call: $kotlinCall"
} }
argumentMappingByOriginal = emptyMap() resolvedCall.argumentMappingByOriginal = emptyMap()
return emptyList() resolvedCall.argumentToCandidateParameter = emptyMap()
} }
} }
internal object CreateDescriptorWithFreshTypeVariables : ResolutionPart {
override fun SimpleKotlinResolutionCandidate.process(): List<KotlinCallDiagnostic> { internal object CreateFreshVariablesSubstitutor : ResolutionPart() {
override fun KotlinResolutionCandidate.process(workIndex: Int) {
if (candidateDescriptor.typeParameters.isEmpty()) { if (candidateDescriptor.typeParameters.isEmpty()) {
descriptorWithFreshTypes = candidateDescriptor resolvedCall.substitutor = FreshVariableNewTypeSubstitutor.Empty
return emptyList() return
} }
val toFreshVariables = createToFreshVariableSubstitutorAndAddInitialConstraints(candidateDescriptor, csBuilder) val toFreshVariables = createToFreshVariableSubstitutorAndAddInitialConstraints(candidateDescriptor, csBuilder)
typeVariablesForFreshTypeParameters = toFreshVariables.freshVariables resolvedCall.substitutor = toFreshVariables
// bad function -- error on declaration side // bad function -- error on declaration side
if (csBuilder.hasContradiction) { if (csBuilder.hasContradiction) return
descriptorWithFreshTypes = candidateDescriptor
return emptyList()
}
// optimization // optimization
if (typeArgumentMappingByOriginal == NoExplicitArguments && knownTypeParametersResultingSubstitutor == null) { if (resolvedCall.typeArgumentMappingByOriginal == NoExplicitArguments && knownTypeParametersResultingSubstitutor == null) {
descriptorWithFreshTypes = candidateDescriptor.substitute(toFreshVariables) return
csBuilder.simplify().let { assert(it.isEmpty) { "Substitutor should be empty: $it, call: $kotlinCall" } }
return emptyList()
} }
val typeParameters = candidateDescriptor.typeParameters val typeParameters = candidateDescriptor.typeParameters
for (index in typeParameters.indices) { for (index in typeParameters.indices) {
val typeParameter = typeParameters[index] val typeParameter = typeParameters[index]
val freshVariable = toFreshVariables.freshVariables[index]
val knownTypeArgument = knownTypeParametersResultingSubstitutor?.substitute(typeParameter.defaultType) val knownTypeArgument = knownTypeParametersResultingSubstitutor?.substitute(typeParameter.defaultType)
if (knownTypeArgument != null) { if (knownTypeArgument != null) {
val freshVariable = toFreshVariables.freshVariables[index]
csBuilder.addEqualityConstraint(freshVariable.defaultType, knownTypeArgument.unwrap(), KnownTypeParameterConstraintPosition(knownTypeArgument)) csBuilder.addEqualityConstraint(freshVariable.defaultType, knownTypeArgument.unwrap(), KnownTypeParameterConstraintPosition(knownTypeArgument))
continue continue
} }
val typeArgument = typeArgumentMappingByOriginal.getTypeArgument(typeParameter) val typeArgument = resolvedCall.typeArgumentMappingByOriginal.getTypeArgument(typeParameter)
if (typeArgument is SimpleTypeArgument) { if (typeArgument is SimpleTypeArgument) {
val freshVariable = toFreshVariables.freshVariables[index]
csBuilder.addEqualityConstraint(freshVariable.defaultType, typeArgument.type, ExplicitTypeParameterConstraintPosition(typeArgument)) csBuilder.addEqualityConstraint(freshVariable.defaultType, typeArgument.type, ExplicitTypeParameterConstraintPosition(typeArgument))
} }
else { else {
@@ -147,19 +160,6 @@ internal object CreateDescriptorWithFreshTypeVariables : ResolutionPart {
} }
} }
} }
/**
* Note: here we can fix also placeholders arguments.
* Example:
* fun <X : Array<Y>, Y> foo()
*
* foo<Array<String>, *>()
*/
val toFixedTypeParameters = csBuilder.simplify()
// todo optimize -- composite substitutions before run safeSubstitute
descriptorWithFreshTypes = candidateDescriptor.substitute(toFreshVariables).substitute(toFixedTypeParameters)
return emptyList()
} }
fun createToFreshVariableSubstitutorAndAddInitialConstraints( fun createToFreshVariableSubstitutorAndAddInitialConstraints(
@@ -189,98 +189,124 @@ internal object CreateDescriptorWithFreshTypeVariables : ResolutionPart {
} }
} }
internal object CheckExplicitReceiverKindConsistency : ResolutionPart { internal object CheckExplicitReceiverKindConsistency : ResolutionPart() {
private fun SimpleKotlinResolutionCandidate.hasError(): Nothing = private fun KotlinResolutionCandidate.hasError(): Nothing =
error("Inconsistent call: $kotlinCall. \n" + error("Inconsistent call: $kotlinCall. \n" +
"Candidate: $candidateDescriptor, explicitReceiverKind: $explicitReceiverKind.\n" + "Candidate: $candidateDescriptor, explicitReceiverKind: ${resolvedCall.explicitReceiverKind}.\n" +
"Explicit receiver: ${kotlinCall.explicitReceiver}, dispatchReceiverForInvokeExtension: ${kotlinCall.dispatchReceiverForInvokeExtension}") "Explicit receiver: ${kotlinCall.explicitReceiver}, dispatchReceiverForInvokeExtension: ${kotlinCall.dispatchReceiverForInvokeExtension}")
override fun SimpleKotlinResolutionCandidate.process(): List<KotlinCallDiagnostic> { override fun KotlinResolutionCandidate.process(workIndex: Int) {
when (explicitReceiverKind) { when (resolvedCall.explicitReceiverKind) {
NO_EXPLICIT_RECEIVER -> if (kotlinCall.explicitReceiver is SimpleKotlinCallArgument || kotlinCall.dispatchReceiverForInvokeExtension != null) hasError() NO_EXPLICIT_RECEIVER -> if (kotlinCall.explicitReceiver is SimpleKotlinCallArgument || kotlinCall.dispatchReceiverForInvokeExtension != null) hasError()
DISPATCH_RECEIVER, EXTENSION_RECEIVER -> if (kotlinCall.explicitReceiver == null || kotlinCall.dispatchReceiverForInvokeExtension != null) hasError() DISPATCH_RECEIVER, EXTENSION_RECEIVER -> if (kotlinCall.explicitReceiver == null || kotlinCall.dispatchReceiverForInvokeExtension != null) hasError()
BOTH_RECEIVERS -> if (kotlinCall.explicitReceiver == null || kotlinCall.dispatchReceiverForInvokeExtension == null) hasError() BOTH_RECEIVERS -> if (kotlinCall.explicitReceiver == null || kotlinCall.dispatchReceiverForInvokeExtension == null) hasError()
} }
return emptyList()
} }
} }
internal object CheckReceivers : ResolutionPart { private fun KotlinResolutionCandidate.resolveKotlinArgument(
private fun SimpleKotlinResolutionCandidate.checkReceiver( argument: KotlinCallArgument,
candidateParameter: ParameterDescriptor?,
isReceiver: Boolean
) {
val expectedType = candidateParameter?.let {
resolvedCall.substitutor.safeSubstitute(argument.getExpectedType(candidateParameter))
}
addResolvedKtPrimitive(resolveKtPrimitive(csBuilder, argument, expectedType, this, isReceiver))
}
internal object CheckReceivers : ResolutionPart() {
private fun KotlinResolutionCandidate.checkReceiver(
receiverArgument: SimpleKotlinCallArgument?, receiverArgument: SimpleKotlinCallArgument?,
receiverParameter: ReceiverParameterDescriptor? receiverParameter: ReceiverParameterDescriptor?
): KotlinCallDiagnostic? { ) {
if ((receiverArgument == null) != (receiverParameter == null)) { if ((receiverArgument == null) != (receiverParameter == null)) {
error("Inconsistency receiver state for call $kotlinCall and candidate descriptor: $candidateDescriptor") error("Inconsistency receiver state for call $kotlinCall and candidate descriptor: $candidateDescriptor")
} }
if (receiverArgument == null || receiverParameter == null) return null if (receiverArgument == null || receiverParameter == null) return
val expectedType = receiverParameter.type.unwrap() resolveKotlinArgument(receiverArgument, receiverParameter, isReceiver = true)
return checkSimpleArgument(csBuilder, receiverArgument, expectedType, isReceiver = true)
} }
override fun SimpleKotlinResolutionCandidate.process() = override fun KotlinResolutionCandidate.process(workIndex: Int) {
listOfNotNull(checkReceiver(dispatchReceiverArgument, descriptorWithFreshTypes.dispatchReceiverParameter), if (workIndex == 0) {
checkReceiver(extensionReceiver, descriptorWithFreshTypes.extensionReceiverParameter)) checkReceiver(resolvedCall.dispatchReceiverArgument, candidateDescriptor.dispatchReceiverParameter)
} } else {
checkReceiver(resolvedCall.extensionReceiverArgument, candidateDescriptor.extensionReceiverParameter)
internal object CheckArguments : ResolutionPart {
override fun SimpleKotlinResolutionCandidate.process(): List<KotlinCallDiagnostic> {
val diagnostics = SmartList<KotlinCallDiagnostic>()
for (parameterDescriptor in descriptorWithFreshTypes.valueParameters) {
// error was reported in ArgumentsToParametersMapper
val resolvedCallArgument = argumentMappingByOriginal[parameterDescriptor.original] ?: continue
for (argument in resolvedCallArgument.arguments) {
val expectedType = argument.getExpectedType(parameterDescriptor)
val diagnostic = when (argument) {
is SimpleKotlinCallArgument ->
checkSimpleArgument(csBuilder, argument, expectedType)
is PostponableKotlinCallArgument ->
createPostponedArgumentAndPerformInitialChecks(csBuilder, argument, expectedType)
else -> unexpectedArgument(argument)
}
diagnostics.addIfNotNull(diagnostic)
if (diagnostic != null && !diagnostic.candidateApplicability.isSuccess) break
}
} }
return diagnostics }
override fun KotlinResolutionCandidate.workCount() = 2
}
internal object CheckArguments : ResolutionPart() {
override fun KotlinResolutionCandidate.process(workIndex: Int) {
val argument = kotlinCall.argumentsInParenthesis[workIndex]
resolveKotlinArgument(argument, resolvedCall.argumentToCandidateParameter[argument], isReceiver = false)
}
override fun KotlinResolutionCandidate.workCount() = kotlinCall.argumentsInParenthesis.size
}
internal object CheckExternalArgument : ResolutionPart() {
override fun KotlinResolutionCandidate.process(workIndex: Int) {
val argument = kotlinCall.externalArgument ?: return
resolveKotlinArgument(argument, resolvedCall.argumentToCandidateParameter[argument], isReceiver = false)
} }
} }
internal object CheckInfixResolutionPart : ResolutionPart { internal object CheckInfixResolutionPart : ResolutionPart() {
override fun SimpleKotlinResolutionCandidate.process(): List<KotlinCallDiagnostic> { override fun KotlinResolutionCandidate.process(workIndex: Int) {
val candidateDescriptor = resolvedCall.candidateDescriptor
if (callComponents.statelessCallbacks.isInfixCall(kotlinCall) && if (callComponents.statelessCallbacks.isInfixCall(kotlinCall) &&
(candidateDescriptor !is FunctionDescriptor || !candidateDescriptor.isInfix)) { (candidateDescriptor !is FunctionDescriptor || !candidateDescriptor.isInfix)) {
return listOf(InfixCallNoInfixModifier) addDiagnostic(InfixCallNoInfixModifier)
} }
return emptyList()
} }
} }
internal object CheckOperatorResolutionPart : ResolutionPart { internal object CheckOperatorResolutionPart : ResolutionPart() {
override fun SimpleKotlinResolutionCandidate.process(): List<KotlinCallDiagnostic> { override fun KotlinResolutionCandidate.process(workIndex: Int) {
val candidateDescriptor = resolvedCall.candidateDescriptor
if (callComponents.statelessCallbacks.isOperatorCall(kotlinCall) && if (callComponents.statelessCallbacks.isOperatorCall(kotlinCall) &&
(candidateDescriptor !is FunctionDescriptor || !candidateDescriptor.isOperator)) { (candidateDescriptor !is FunctionDescriptor || !candidateDescriptor.isOperator)) {
return listOf(InvokeConventionCallNoOperatorModifier) addDiagnostic(InvokeConventionCallNoOperatorModifier)
} }
return emptyList()
} }
} }
internal object CheckAbstractSuperCallPart : ResolutionPart { internal object CheckAbstractSuperCallPart : ResolutionPart() {
override fun SimpleKotlinResolutionCandidate.process(): List<KotlinCallDiagnostic> { override fun KotlinResolutionCandidate.process(workIndex: Int) {
if (callComponents.statelessCallbacks.isSuperExpression(dispatchReceiverArgument)) { val candidateDescriptor = resolvedCall.candidateDescriptor
if (callComponents.statelessCallbacks.isSuperExpression(resolvedCall.dispatchReceiverArgument)) {
if (candidateDescriptor is MemberDescriptor && candidateDescriptor.modality == Modality.ABSTRACT) { if (candidateDescriptor is MemberDescriptor && candidateDescriptor.modality == Modality.ABSTRACT) {
return listOf(AbstractSuperCall) addDiagnostic(AbstractSuperCall)
} }
} }
return emptyList()
} }
}
internal object ErrorDescriptorResolutionPart : ResolutionPart() {
override fun KotlinResolutionCandidate.process(workIndex: Int) {
assert(ErrorUtils.isError(candidateDescriptor)) {
"Should be error descriptor: $candidateDescriptor"
}
resolvedCall.typeArgumentMappingByOriginal = TypeArgumentsToParametersMapper.TypeArgumentsMapping.NoExplicitArguments
resolvedCall.argumentMappingByOriginal = emptyMap()
resolvedCall.substitutor = FreshVariableNewTypeSubstitutor.Empty
resolvedCall.argumentToCandidateParameter = emptyMap()
kotlinCall.explicitReceiver?.safeAs<SimpleKotlinCallArgument>()?.let {
resolveKotlinArgument(it, null, isReceiver = true)
}
for (argument in kotlinCall.argumentsInParenthesis) {
resolveKotlinArgument(argument, null, isReceiver = true)
}
kotlinCall.externalArgument?.let {
resolveKotlinArgument(it, null, isReceiver = true)
}
}
} }
@@ -35,22 +35,25 @@ import org.jetbrains.kotlin.types.upperIfFlexible
fun checkSimpleArgument( fun checkSimpleArgument(
csBuilder: ConstraintSystemBuilder, csBuilder: ConstraintSystemBuilder,
argument: SimpleKotlinCallArgument, argument: SimpleKotlinCallArgument,
expectedType: UnwrappedType, expectedType: UnwrappedType?,
isReceiver: Boolean = false diagnosticsHolder: KotlinDiagnosticsHolder,
): KotlinCallDiagnostic? { isReceiver: Boolean
return when (argument) { ): ResolvedAtom = when (argument) {
is ExpressionKotlinCallArgument -> checkExpressionArgument(csBuilder, argument, expectedType, isReceiver) is ExpressionKotlinCallArgument -> checkExpressionArgument(csBuilder, argument, expectedType, diagnosticsHolder, isReceiver)
is SubKotlinCallArgument -> checkSubCallArgument(csBuilder, argument, expectedType, isReceiver) is SubKotlinCallArgument -> checkSubCallArgument(csBuilder, argument, expectedType, diagnosticsHolder, isReceiver)
else -> unexpectedArgument(argument) else -> unexpectedArgument(argument)
}
} }
private fun checkExpressionArgument( private fun checkExpressionArgument(
csBuilder: ConstraintSystemBuilder, csBuilder: ConstraintSystemBuilder,
expressionArgument: ExpressionKotlinCallArgument, expressionArgument: ExpressionKotlinCallArgument,
expectedType: UnwrappedType, expectedType: UnwrappedType?,
diagnosticsHolder: KotlinDiagnosticsHolder,
isReceiver: Boolean isReceiver: Boolean
): KotlinCallDiagnostic? { ): ResolvedAtom {
val resolvedKtExpression = ResolvedExpressionAtom(expressionArgument)
if (expectedType == null) return resolvedKtExpression
// todo run this approximation only once for call // todo run this approximation only once for call
val argumentType = captureFromTypeParameterUpperBoundIfNeeded(expressionArgument.receiver.stableType, expectedType) val argumentType = captureFromTypeParameterUpperBoundIfNeeded(expressionArgument.receiver.stableType, expectedType)
@@ -70,30 +73,31 @@ private fun checkExpressionArgument(
val position = if (isReceiver) ReceiverConstraintPosition(expressionArgument) else ArgumentConstraintPosition(expressionArgument) val position = if (isReceiver) ReceiverConstraintPosition(expressionArgument) else ArgumentConstraintPosition(expressionArgument)
if (expressionArgument.isSafeCall) { if (expressionArgument.isSafeCall) {
if (!csBuilder.addSubtypeConstraintIfCompatible(argumentType, expectedNullableType, position)) { if (!csBuilder.addSubtypeConstraintIfCompatible(argumentType, expectedNullableType, position)) {
return unstableSmartCastOrSubtypeError(expressionArgument.receiver.unstableType, expectedNullableType, position)?.let { return it } diagnosticsHolder.addDiagnosticIfNotNull(
unstableSmartCastOrSubtypeError(expressionArgument.receiver.unstableType, expectedNullableType, position))
} }
return null return resolvedKtExpression
} }
if (!csBuilder.addSubtypeConstraintIfCompatible(argumentType, expectedType, position)) { if (!csBuilder.addSubtypeConstraintIfCompatible(argumentType, expectedType, position)) {
if (!isReceiver) { if (!isReceiver) {
return unstableSmartCastOrSubtypeError(expressionArgument.receiver.unstableType, expectedType, position)?.let { return it } diagnosticsHolder.addDiagnosticIfNotNull(unstableSmartCastOrSubtypeError(expressionArgument.receiver.unstableType, expectedType, position))
return resolvedKtExpression
} }
val unstableType = expressionArgument.receiver.unstableType val unstableType = expressionArgument.receiver.unstableType
if (unstableType != null && csBuilder.addSubtypeConstraintIfCompatible(unstableType, expectedType, position)) { if (unstableType != null && csBuilder.addSubtypeConstraintIfCompatible(unstableType, expectedType, position)) {
return UnstableSmartCast(expressionArgument, unstableType) diagnosticsHolder.addDiagnostic(UnstableSmartCast(expressionArgument, unstableType))
} }
else if (csBuilder.addSubtypeConstraintIfCompatible(argumentType, expectedNullableType, position)) { else if (csBuilder.addSubtypeConstraintIfCompatible(argumentType, expectedNullableType, position)) {
return UnsafeCallError(expressionArgument) diagnosticsHolder.addDiagnostic(UnsafeCallError(expressionArgument))
} }
else { else {
csBuilder.addSubtypeConstraint(argumentType, expectedType, position) csBuilder.addSubtypeConstraint(argumentType, expectedType, position)
return null
} }
} }
return null return resolvedKtExpression
} }
/** /**
@@ -131,30 +135,33 @@ private fun captureFromTypeParameterUpperBoundIfNeeded(argumentType: UnwrappedTy
private fun checkSubCallArgument( private fun checkSubCallArgument(
csBuilder: ConstraintSystemBuilder, csBuilder: ConstraintSystemBuilder,
subCallArgument: SubKotlinCallArgument, subCallArgument: SubKotlinCallArgument,
expectedType: UnwrappedType, expectedType: UnwrappedType?,
diagnosticsHolder: KotlinDiagnosticsHolder,
isReceiver: Boolean isReceiver: Boolean
): KotlinCallDiagnostic? { ): ResolvedAtom {
val resolvedCall = subCallArgument.resolvedCall val subCallResult = subCallArgument.callResult
val expectedNullableType = expectedType.makeNullableAsSpecified(true)
val position = ArgumentConstraintPosition(subCallArgument)
csBuilder.addInnerCall(resolvedCall) if (expectedType == null) return subCallResult
val expectedNullableType = expectedType.makeNullableAsSpecified(true)
val position = if (isReceiver) ReceiverConstraintPosition(subCallArgument) else ArgumentConstraintPosition(subCallArgument)
// subArgument cannot has stable smartcast // subArgument cannot has stable smartcast
// return type can contains fixed type variables // return type can contains fixed type variables
val currentReturnType = csBuilder.buildCurrentSubstitutor().safeSubstitute(subCallArgument.receiver.receiverValue.type.unwrap()) val currentReturnType = csBuilder.buildCurrentSubstitutor().safeSubstitute(subCallArgument.receiver.receiverValue.type.unwrap())
if (subCallArgument.isSafeCall) { if (subCallArgument.isSafeCall) {
csBuilder.addSubtypeConstraint(currentReturnType, expectedNullableType, position) csBuilder.addSubtypeConstraint(currentReturnType, expectedNullableType, position)
return null return subCallResult
} }
if (isReceiver && !csBuilder.addSubtypeConstraintIfCompatible(currentReturnType, expectedType, position) && if (isReceiver && !csBuilder.addSubtypeConstraintIfCompatible(currentReturnType, expectedType, position) &&
csBuilder.addSubtypeConstraintIfCompatible(currentReturnType, expectedNullableType, position) csBuilder.addSubtypeConstraintIfCompatible(currentReturnType, expectedNullableType, position)
) { ) {
return UnsafeCallError(subCallArgument) diagnosticsHolder.addDiagnostic(UnsafeCallError(subCallArgument))
return subCallResult
} }
csBuilder.addSubtypeConstraint(currentReturnType, expectedType, position) csBuilder.addSubtypeConstraint(currentReturnType, expectedType, position)
return null return subCallResult
} }
@@ -16,12 +16,18 @@
package org.jetbrains.kotlin.resolve.calls.inference package org.jetbrains.kotlin.resolve.calls.inference
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.resolve.calls.components.PostponedArgumentsAnalyzer
import org.jetbrains.kotlin.resolve.calls.inference.components.NewTypeSubstitutor import org.jetbrains.kotlin.resolve.calls.inference.components.NewTypeSubstitutor
import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintPosition import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintPosition
import org.jetbrains.kotlin.resolve.calls.inference.model.NewTypeVariable import org.jetbrains.kotlin.resolve.calls.inference.model.NewTypeVariable
import org.jetbrains.kotlin.resolve.calls.model.* import org.jetbrains.kotlin.resolve.calls.model.CallableReferenceKotlinCallArgument
import org.jetbrains.kotlin.resolve.calls.model.KotlinCallArgument
import org.jetbrains.kotlin.resolve.calls.model.LHSResult
import org.jetbrains.kotlin.resolve.calls.model.SubKotlinCallArgument
import org.jetbrains.kotlin.types.TypeConstructor import org.jetbrains.kotlin.types.TypeConstructor
import org.jetbrains.kotlin.types.UnwrappedType import org.jetbrains.kotlin.types.UnwrappedType
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
interface ConstraintSystemOperation { interface ConstraintSystemOperation {
val hasContradiction: Boolean val hasContradiction: Boolean
@@ -36,23 +42,25 @@ interface ConstraintSystemOperation {
} }
interface ConstraintSystemBuilder : ConstraintSystemOperation { interface ConstraintSystemBuilder : ConstraintSystemOperation {
fun addInnerCall(innerCall: ResolvedKotlinCall.OnlyResolvedKotlinCall) val builtIns: KotlinBuiltIns
fun addPostponedArgument(postponedArgument: PostponedKotlinCallArgument)
// if runOperations return true, then this operation will be applied, and function return true // if runOperations return true, then this operation will be applied, and function return true
fun runTransaction(runOperations: ConstraintSystemOperation.() -> Boolean): Boolean fun runTransaction(runOperations: ConstraintSystemOperation.() -> Boolean): Boolean
fun buildCurrentSubstitutor(): NewTypeSubstitutor fun buildCurrentSubstitutor(): NewTypeSubstitutor
/**
* This function removes variables for which we know exact type.
* @return substitutor from typeVariable to result
*/
fun simplify(): NewTypeSubstitutor
} }
fun ConstraintSystemBuilder.addSubtypeConstraintIfCompatible(lowerType: UnwrappedType, upperType: UnwrappedType, position: ConstraintPosition) = fun ConstraintSystemBuilder.addSubtypeConstraintIfCompatible(lowerType: UnwrappedType, upperType: UnwrappedType, position: ConstraintPosition) =
runTransaction { runTransaction {
if (!hasContradiction) addSubtypeConstraint(lowerType, upperType, position) if (!hasContradiction) addSubtypeConstraint(lowerType, upperType, position)
!hasContradiction !hasContradiction
} }
fun PostponedArgumentsAnalyzer.Context.addSubsystemForArgument(argument: KotlinCallArgument?) {
when (argument) {
is SubKotlinCallArgument -> addOtherSystem(argument.callResult.constraintSystem)
is CallableReferenceKotlinCallArgument -> {
addSubsystemForArgument(argument.lhsResult.safeAs<LHSResult.Expression>()?.lshCallArgument)
}
}
}
@@ -20,6 +20,7 @@ import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.resolve.calls.inference.components.NewTypeSubstitutor import org.jetbrains.kotlin.resolve.calls.inference.components.NewTypeSubstitutor
import org.jetbrains.kotlin.resolve.calls.inference.components.NewTypeSubstitutorByConstructorMap import org.jetbrains.kotlin.resolve.calls.inference.components.NewTypeSubstitutorByConstructorMap
import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintStorage import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintStorage
import org.jetbrains.kotlin.resolve.calls.inference.model.NewConstraintSystemImpl
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
import org.jetbrains.kotlin.types.* import org.jetbrains.kotlin.types.*
@@ -27,6 +28,17 @@ fun ConstraintStorage.buildCurrentSubstitutor() = NewTypeSubstitutorByConstructo
it.key to it.value it.key to it.value
}) })
fun ConstraintStorage.buildResultingSubstitutor(): NewTypeSubstitutor {
val currentSubstitutorMap = fixedTypeVariables.entries.associate {
it.key to it.value
}
val uninferredSubstitutorMap = notFixedTypeVariables.entries.associate { (freshTypeConstructor, typeVariable) ->
freshTypeConstructor to ErrorUtils.createErrorTypeWithCustomConstructor("Uninferred type", typeVariable.typeVariable.freshTypeConstructor)
}
return NewTypeSubstitutorByConstructorMap(currentSubstitutorMap + uninferredSubstitutorMap)
}
val CallableDescriptor.returnTypeOrNothing: UnwrappedType val CallableDescriptor.returnTypeOrNothing: UnwrappedType
get() { get() {
returnType?.let { return it.unwrap() } returnType?.let { return it.unwrap() }
@@ -16,6 +16,7 @@
package org.jetbrains.kotlin.resolve.calls.inference package org.jetbrains.kotlin.resolve.calls.inference
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.resolve.calls.components.KotlinCallCompleter import org.jetbrains.kotlin.resolve.calls.components.KotlinCallCompleter
import org.jetbrains.kotlin.resolve.calls.components.PostponedArgumentsAnalyzer import org.jetbrains.kotlin.resolve.calls.components.PostponedArgumentsAnalyzer
import org.jetbrains.kotlin.resolve.calls.inference.components.KotlinConstraintSystemCompleter import org.jetbrains.kotlin.resolve.calls.inference.components.KotlinConstraintSystemCompleter
@@ -23,13 +24,14 @@ import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintStorage
import org.jetbrains.kotlin.resolve.calls.model.KotlinCallDiagnostic import org.jetbrains.kotlin.resolve.calls.model.KotlinCallDiagnostic
interface NewConstraintSystem { interface NewConstraintSystem {
val builtIns: KotlinBuiltIns
val hasContradiction: Boolean
val diagnostics: List<KotlinCallDiagnostic> val diagnostics: List<KotlinCallDiagnostic>
fun getBuilder(): ConstraintSystemBuilder fun getBuilder(): ConstraintSystemBuilder
// after this method we shouldn't mutate system via ConstraintSystemBuilder // after this method we shouldn't mutate system via ConstraintSystemBuilder
fun asReadOnlyStorage(): ConstraintStorage fun asReadOnlyStorage(): ConstraintStorage
fun asCallCompleterContext(): KotlinCallCompleter.Context
fun asConstraintSystemCompleterContext(): KotlinConstraintSystemCompleter.Context fun asConstraintSystemCompleterContext(): KotlinConstraintSystemCompleter.Context
fun asPostponedArgumentsAnalyzerContext(): PostponedArgumentsAnalyzer.Context fun asPostponedArgumentsAnalyzerContext(): PostponedArgumentsAnalyzer.Context
} }
@@ -22,7 +22,9 @@ import org.jetbrains.kotlin.resolve.calls.inference.model.VariableWithConstraint
import org.jetbrains.kotlin.resolve.calls.model.* import org.jetbrains.kotlin.resolve.calls.model.*
import org.jetbrains.kotlin.types.TypeConstructor import org.jetbrains.kotlin.types.TypeConstructor
import org.jetbrains.kotlin.types.UnwrappedType import org.jetbrains.kotlin.types.UnwrappedType
import org.jetbrains.kotlin.utils.addIfNotNull
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
class KotlinConstraintSystemCompleter( class KotlinConstraintSystemCompleter(
private val resultTypeResolver: ResultTypeResolver, private val resultTypeResolver: ResultTypeResolver,
@@ -34,7 +36,6 @@ class KotlinConstraintSystemCompleter(
} }
interface Context : VariableFixationFinder.Context, ResultTypeResolver.Context { interface Context : VariableFixationFinder.Context, ResultTypeResolver.Context {
override val postponedArguments: List<PostponedKotlinCallArgument>
override val notFixedTypeVariables: Map<TypeConstructor, VariableWithConstraints> override val notFixedTypeVariables: Map<TypeConstructor, VariableWithConstraints>
// type can be proper if it not contains not fixed type variables // type can be proper if it not contains not fixed type variables
@@ -48,23 +49,27 @@ class KotlinConstraintSystemCompleter(
fun runCompletion( fun runCompletion(
c: Context, c: Context,
completionMode: ConstraintSystemCompletionMode, completionMode: ConstraintSystemCompletionMode,
topLevelPrimitive: ResolvedAtom,
topLevelType: UnwrappedType, topLevelType: UnwrappedType,
analyze: (PostponedKotlinCallArgument) -> Unit analyze: (PostponedResolvedAtom) -> Unit
) { ) {
while (true) { while (true) {
if (analyzePostponeArgumentIfPossible(c, analyze)) continue if (analyzePostponeArgumentIfPossible(c, topLevelPrimitive, analyze)) continue
val variableForFixation = variableFixationFinder.findFirstVariableForFixation(c, completionMode, topLevelType) val allTypeVariables = getOrderedAllTypeVariables(c, topLevelPrimitive)
val postponedKtPrimitives = getOrderedNotAnalyzedPostponedArguments(topLevelPrimitive)
val variableForFixation = variableFixationFinder.findFirstVariableForFixation(
c, allTypeVariables, postponedKtPrimitives, completionMode, topLevelType)
if (shouldWeForceCallableReferenceResolution(completionMode, variableForFixation)) { if (shouldWeForceCallableReferenceResolution(completionMode, variableForFixation)) {
if (forceCallableReferenceResolution(c, analyze)) continue if (forceCallableReferenceResolution(topLevelPrimitive, analyze)) continue
} }
if (variableForFixation != null) { if (variableForFixation != null) {
if (variableForFixation.hasProperConstraint || completionMode == ConstraintSystemCompletionMode.FULL) { if (variableForFixation.hasProperConstraint || completionMode == ConstraintSystemCompletionMode.FULL) {
val variableWithConstraints = c.notFixedTypeVariables[variableForFixation.variable]!! val variableWithConstraints = c.notFixedTypeVariables[variableForFixation.variable]!!
fixVariable(c, topLevelType, variableWithConstraints) fixVariable(c, topLevelType, variableWithConstraints, postponedKtPrimitives)
if (!variableForFixation.hasProperConstraint) { if (!variableForFixation.hasProperConstraint) {
c.addError(NotEnoughInformationForTypeParameter(variableWithConstraints.typeVariable)) c.addError(NotEnoughInformationForTypeParameter(variableWithConstraints.typeVariable))
@@ -77,7 +82,7 @@ class KotlinConstraintSystemCompleter(
if (completionMode == ConstraintSystemCompletionMode.FULL) { if (completionMode == ConstraintSystemCompletionMode.FULL) {
// force resolution for all not-analyzed argument's // force resolution for all not-analyzed argument's
c.postponedArguments.filterNot { it.analyzed }.forEach(analyze) getOrderedNotAnalyzedPostponedArguments(topLevelPrimitive).forEach(analyze)
} }
} }
@@ -92,8 +97,8 @@ class KotlinConstraintSystemCompleter(
} }
// true if we do analyze // true if we do analyze
private fun analyzePostponeArgumentIfPossible(c: Context, analyze: (PostponedKotlinCallArgument) -> Unit): Boolean { private fun analyzePostponeArgumentIfPossible(c: Context, topLevelPrimitive: ResolvedAtom, analyze: (PostponedResolvedAtom) -> Unit): Boolean {
for (argument in getOrderedNotAnalyzedPostponedArguments(c)) { for (argument in getOrderedNotAnalyzedPostponedArguments(topLevelPrimitive)) {
if (canWeAnalyzeIt(c, argument)) { if (canWeAnalyzeIt(c, argument)) {
analyze(argument) analyze(argument)
return true return true
@@ -103,24 +108,55 @@ class KotlinConstraintSystemCompleter(
} }
// true if we find some callable reference and run resolution for it. Note that such resolution can be unsuccessful // true if we find some callable reference and run resolution for it. Note that such resolution can be unsuccessful
private fun forceCallableReferenceResolution(c: Context, analyze: (PostponedKotlinCallArgument) -> Unit): Boolean { private fun forceCallableReferenceResolution(topLevelPrimitive: ResolvedAtom, analyze: (PostponedResolvedAtom) -> Unit): Boolean {
val callableReferenceArgument = getOrderedNotAnalyzedPostponedArguments(c). val callableReferenceArgument = getOrderedNotAnalyzedPostponedArguments(topLevelPrimitive).
firstIsInstanceOrNull<PostponedCallableReferenceArgument>() ?: return false firstIsInstanceOrNull<ResolvedCallableReferenceAtom>() ?: return false
analyze(callableReferenceArgument) analyze(callableReferenceArgument)
return true return true
} }
private fun getOrderedNotAnalyzedPostponedArguments(c: Context): List<PostponedKotlinCallArgument> { private fun getOrderedNotAnalyzedPostponedArguments(topLevelPrimitive: ResolvedAtom): List<PostponedResolvedAtom> {
val notAnalyzedArguments = c.postponedArguments.filterNot { it.analyzed } fun ResolvedAtom.process(to: MutableList<PostponedResolvedAtom>) {
to.addIfNotNull(this.safeAs<PostponedResolvedAtom>()?.takeUnless { it.analyzed })
// todo insert logic here if (analyzed) {
return notAnalyzedArguments subResolvedAtoms.forEach { it.process(to) }
}
}
return arrayListOf<PostponedResolvedAtom>().apply { topLevelPrimitive.process(this) }
}
private fun getOrderedAllTypeVariables(c: Context, topLevelPrimitive: ResolvedAtom) : List<TypeConstructor> {
fun ResolvedAtom.process(to: MutableList<TypeConstructor>) {
val typeVariables = when (this) {
is ResolvedCallAtom -> substitutor.freshVariables
is ResolvedCallableReferenceAtom -> candidate?.freshSubstitutor?.freshVariables.orEmpty()
is ResolvedLambdaAtom -> listOfNotNull(typeVariableForLambdaReturnType)
else -> emptyList()
}
typeVariables.mapNotNullTo(to) {
val typeConstructor = it.freshTypeConstructor
typeConstructor.takeIf { c.notFixedTypeVariables.containsKey(typeConstructor) }
}
if (analyzed) {
subResolvedAtoms.forEach { it.process(to) }
}
}
val result = arrayListOf<TypeConstructor>().apply { topLevelPrimitive.process(this) }
assert(result.size == c.notFixedTypeVariables.size) {
val notFoundTypeVariables = c.notFixedTypeVariables.keys.toMutableSet().removeAll(result)
"Not all type variables found: $notFoundTypeVariables"
}
return result
} }
private fun canWeAnalyzeIt(c: Context, argument: PostponedKotlinCallArgument): Boolean { private fun canWeAnalyzeIt(c: Context, argument: PostponedResolvedAtom): Boolean {
if (argument is PostponedCollectionLiteralArgument || argument.analyzed) return false if (argument.analyzed) return false
return argument.inputTypes.all { c.canBeProper(it) } return argument.inputTypes.all { c.canBeProper(it) }
} }
@@ -128,9 +164,10 @@ class KotlinConstraintSystemCompleter(
private fun fixVariable( private fun fixVariable(
c: Context, c: Context,
topLevelType: UnwrappedType, topLevelType: UnwrappedType,
variableWithConstraints: VariableWithConstraints variableWithConstraints: VariableWithConstraints,
postponedResolveKtPrimitives: List<PostponedResolvedAtom>
) { ) {
val direction = TypeVariableDirectionCalculator(c, topLevelType).getDirection(variableWithConstraints) val direction = TypeVariableDirectionCalculator(c, postponedResolveKtPrimitives, topLevelType).getDirection(variableWithConstraints)
val resultType = resultTypeResolver.findResultType(c, variableWithConstraints, direction) val resultType = resultTypeResolver.findResultType(c, variableWithConstraints, direction)
@@ -150,4 +150,8 @@ class FreshVariableNewTypeSubstitutor(val freshVariables: List<TypeVariableFromC
return typeVariable.defaultType return typeVariable.defaultType
} }
companion object {
val Empty = FreshVariableNewTypeSubstitutor(emptyList())
}
} }
@@ -16,6 +16,7 @@
package org.jetbrains.kotlin.resolve.calls.inference.components package org.jetbrains.kotlin.resolve.calls.inference.components
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilder import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilder
import org.jetbrains.kotlin.resolve.calls.inference.model.NewConstraintSystemImpl import org.jetbrains.kotlin.resolve.calls.inference.model.NewConstraintSystemImpl
@@ -29,8 +30,8 @@ import org.jetbrains.kotlin.types.UnwrappedType
import org.jetbrains.kotlin.types.typeUtil.asTypeProjection import org.jetbrains.kotlin.types.typeUtil.asTypeProjection
class SimpleConstraintSystemImpl(constraintInjector: ConstraintInjector, resultTypeResolver: ResultTypeResolver) : SimpleConstraintSystem { class SimpleConstraintSystemImpl(constraintInjector: ConstraintInjector, builtIns: KotlinBuiltIns) : SimpleConstraintSystem {
val csBuilder: ConstraintSystemBuilder = NewConstraintSystemImpl(constraintInjector, resultTypeResolver).getBuilder() val csBuilder: ConstraintSystemBuilder = NewConstraintSystemImpl(constraintInjector, builtIns).getBuilder()
override fun registerTypeVariables(typeParameters: Collection<TypeParameterDescriptor>): TypeSubstitutor { override fun registerTypeVariables(typeParameters: Collection<TypeParameterDescriptor>): TypeSubstitutor {
val substitutionMap = typeParameters.associate { val substitutionMap = typeParameters.associate {
@@ -17,7 +17,7 @@
package org.jetbrains.kotlin.resolve.calls.inference.components package org.jetbrains.kotlin.resolve.calls.inference.components
import org.jetbrains.kotlin.resolve.calls.inference.model.VariableWithConstraints import org.jetbrains.kotlin.resolve.calls.inference.model.VariableWithConstraints
import org.jetbrains.kotlin.resolve.calls.model.PostponedKotlinCallArgument import org.jetbrains.kotlin.resolve.calls.model.PostponedResolvedAtom
import org.jetbrains.kotlin.types.TypeConstructor import org.jetbrains.kotlin.types.TypeConstructor
import org.jetbrains.kotlin.types.UnwrappedType import org.jetbrains.kotlin.types.UnwrappedType
import org.jetbrains.kotlin.types.typeUtil.contains import org.jetbrains.kotlin.types.typeUtil.contains
@@ -25,7 +25,7 @@ import org.jetbrains.kotlin.utils.SmartSet
class TypeVariableDependencyInformationProvider( class TypeVariableDependencyInformationProvider(
private val notFixedTypeVariables: Map<TypeConstructor, VariableWithConstraints>, private val notFixedTypeVariables: Map<TypeConstructor, VariableWithConstraints>,
private val postponedArguments: List<PostponedKotlinCallArgument>, private val postponedKtPrimitives: List<PostponedResolvedAtom>,
private val topLevelType: UnwrappedType? private val topLevelType: UnwrappedType?
) { ) {
// not oriented edges // not oriented edges
@@ -71,7 +71,7 @@ class TypeVariableDependencyInformationProvider(
postponeArgumentsEdges.getOrPut(from) { hashSetOf() }.add(to) postponeArgumentsEdges.getOrPut(from) { hashSetOf() }.add(to)
} }
for (argument in postponedArguments) { for (argument in postponedKtPrimitives) {
if (argument.analyzed) continue if (argument.analyzed) continue
val typeVariablesInOutputType = SmartSet.create<TypeConstructor>() val typeVariablesInOutputType = SmartSet.create<TypeConstructor>()
@@ -89,7 +89,7 @@ class TypeVariableDependencyInformationProvider(
} }
private fun computeRelatedToAllOutputTypes() { private fun computeRelatedToAllOutputTypes() {
for (argument in postponedArguments) { for (argument in postponedKtPrimitives) {
if (argument.analyzed) continue if (argument.analyzed) continue
(argument.outputType ?: continue).forAllMyTypeVariables { (argument.outputType ?: continue).forAllMyTypeVariables {
addAllRelatedNodes(relatedToAllOutputTypes, it, includePostponedEdges = false) addAllRelatedNodes(relatedToAllOutputTypes, it, includePostponedEdges = false)
@@ -19,6 +19,7 @@ package org.jetbrains.kotlin.resolve.calls.inference.components
import org.jetbrains.kotlin.resolve.calls.inference.model.Constraint import org.jetbrains.kotlin.resolve.calls.inference.model.Constraint
import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintKind import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintKind
import org.jetbrains.kotlin.resolve.calls.inference.model.VariableWithConstraints import org.jetbrains.kotlin.resolve.calls.inference.model.VariableWithConstraints
import org.jetbrains.kotlin.resolve.calls.model.PostponedResolvedAtom
import org.jetbrains.kotlin.types.FlexibleType import org.jetbrains.kotlin.types.FlexibleType
import org.jetbrains.kotlin.types.SimpleType import org.jetbrains.kotlin.types.SimpleType
import org.jetbrains.kotlin.types.UnwrappedType import org.jetbrains.kotlin.types.UnwrappedType
@@ -31,7 +32,8 @@ import org.jetbrains.kotlin.utils.SmartList
private typealias Variable = VariableWithConstraints private typealias Variable = VariableWithConstraints
class TypeVariableDirectionCalculator( class TypeVariableDirectionCalculator(
val c: VariableFixationFinder.Context, private val c: VariableFixationFinder.Context,
private val postponedKtPrimitives: List<PostponedResolvedAtom>,
topLevelType: UnwrappedType topLevelType: UnwrappedType
) { ) {
enum class ResolveDirection { enum class ResolveDirection {
@@ -57,7 +59,7 @@ class TypeVariableDirectionCalculator(
topReturnType.visitType(ResolveDirection.TO_SUBTYPE) { variableWithConstraints, direction -> topReturnType.visitType(ResolveDirection.TO_SUBTYPE) { variableWithConstraints, direction ->
enterToNode(variableWithConstraints, direction) enterToNode(variableWithConstraints, direction)
} }
for (postponedArgument in c.postponedArguments) { for (postponedArgument in postponedKtPrimitives) {
for (inputType in postponedArgument.inputTypes) { for (inputType in postponedArgument.inputTypes) {
inputType.visitType(ResolveDirection.TO_SUBTYPE) { variableWithConstraints, direction -> inputType.visitType(ResolveDirection.TO_SUBTYPE) { variableWithConstraints, direction ->
enterToNode(variableWithConstraints, direction) enterToNode(variableWithConstraints, direction)
@@ -17,11 +17,11 @@
package org.jetbrains.kotlin.resolve.calls.inference.components package org.jetbrains.kotlin.resolve.calls.inference.components
import org.jetbrains.kotlin.resolve.calls.inference.components.KotlinConstraintSystemCompleter.ConstraintSystemCompletionMode import org.jetbrains.kotlin.resolve.calls.inference.components.KotlinConstraintSystemCompleter.ConstraintSystemCompletionMode
import org.jetbrains.kotlin.resolve.calls.inference.components.KotlinConstraintSystemCompleter.ConstraintSystemCompletionMode.* import org.jetbrains.kotlin.resolve.calls.inference.components.KotlinConstraintSystemCompleter.ConstraintSystemCompletionMode.PARTIAL
import org.jetbrains.kotlin.resolve.calls.inference.model.Constraint import org.jetbrains.kotlin.resolve.calls.inference.model.Constraint
import org.jetbrains.kotlin.resolve.calls.inference.model.DeclaredUpperBoundConstraintPosition import org.jetbrains.kotlin.resolve.calls.inference.model.DeclaredUpperBoundConstraintPosition
import org.jetbrains.kotlin.resolve.calls.inference.model.VariableWithConstraints import org.jetbrains.kotlin.resolve.calls.inference.model.VariableWithConstraints
import org.jetbrains.kotlin.resolve.calls.model.PostponedKotlinCallArgument import org.jetbrains.kotlin.resolve.calls.model.PostponedResolvedAtom
import org.jetbrains.kotlin.types.TypeConstructor import org.jetbrains.kotlin.types.TypeConstructor
import org.jetbrains.kotlin.types.UnwrappedType import org.jetbrains.kotlin.types.UnwrappedType
import org.jetbrains.kotlin.types.typeUtil.contains import org.jetbrains.kotlin.types.typeUtil.contains
@@ -29,16 +29,17 @@ import org.jetbrains.kotlin.types.typeUtil.contains
class VariableFixationFinder { class VariableFixationFinder {
interface Context { interface Context {
val notFixedTypeVariables: Map<TypeConstructor, VariableWithConstraints> val notFixedTypeVariables: Map<TypeConstructor, VariableWithConstraints>
val postponedArguments: List<PostponedKotlinCallArgument>
} }
data class VariableForFixation(val variable: TypeConstructor, val hasProperConstraint: Boolean) data class VariableForFixation(val variable: TypeConstructor, val hasProperConstraint: Boolean)
fun findFirstVariableForFixation( fun findFirstVariableForFixation(
c: Context, c: Context,
allTypeVariables: List<TypeConstructor>,
postponedKtPrimitives: List<PostponedResolvedAtom>,
completionMode: ConstraintSystemCompletionMode, completionMode: ConstraintSystemCompletionMode,
topLevelType: UnwrappedType topLevelType: UnwrappedType
): VariableForFixation? = c.findTypeVariableForFixation(completionMode, topLevelType) ): VariableForFixation? = c.findTypeVariableForFixation(allTypeVariables, postponedKtPrimitives, completionMode, topLevelType)
private enum class TypeVariableFixationReadiness { private enum class TypeVariableFixationReadiness {
FORBIDDEN, FORBIDDEN,
@@ -52,6 +53,7 @@ class VariableFixationFinder {
variable: TypeConstructor, variable: TypeConstructor,
dependencyProvider: TypeVariableDependencyInformationProvider dependencyProvider: TypeVariableDependencyInformationProvider
): TypeVariableFixationReadiness = when { ): TypeVariableFixationReadiness = when {
!notFixedTypeVariables.contains(variable) ||
dependencyProvider.isVariableRelatedToTopLevelType(variable) -> TypeVariableFixationReadiness.FORBIDDEN dependencyProvider.isVariableRelatedToTopLevelType(variable) -> TypeVariableFixationReadiness.FORBIDDEN
!variableHasProperArgumentConstraints(variable) -> TypeVariableFixationReadiness.WITHOUT_PROPER_ARGUMENT_CONSTRAINT !variableHasProperArgumentConstraints(variable) -> TypeVariableFixationReadiness.WITHOUT_PROPER_ARGUMENT_CONSTRAINT
dependencyProvider.isVariableRelatedToAnyOutputType(variable) -> TypeVariableFixationReadiness.RELATED_TO_ANY_OUTPUT_TYPE dependencyProvider.isVariableRelatedToAnyOutputType(variable) -> TypeVariableFixationReadiness.RELATED_TO_ANY_OUTPUT_TYPE
@@ -60,14 +62,15 @@ class VariableFixationFinder {
} }
private fun Context.findTypeVariableForFixation( private fun Context.findTypeVariableForFixation(
allTypeVariables: List<TypeConstructor>,
postponedKtPrimitives: List<PostponedResolvedAtom>,
completionMode: ConstraintSystemCompletionMode, completionMode: ConstraintSystemCompletionMode,
topLevelType: UnwrappedType topLevelType: UnwrappedType
): VariableForFixation? { ): VariableForFixation? {
val dependencyProvider = TypeVariableDependencyInformationProvider(notFixedTypeVariables, postponedArguments, val dependencyProvider = TypeVariableDependencyInformationProvider(notFixedTypeVariables, postponedKtPrimitives,
topLevelType.takeIf { completionMode == PARTIAL }) topLevelType.takeIf { completionMode == PARTIAL })
val initialOrder = notFixedTypeVariables.keys.sortByInitialOrder() val candidate = allTypeVariables.maxBy { getTypeVariableReadiness(it, dependencyProvider) } ?: return null
val candidate = initialOrder.maxBy { getTypeVariableReadiness(it, dependencyProvider) } ?: return null
val candidateReadiness = getTypeVariableReadiness(candidate, dependencyProvider) val candidateReadiness = getTypeVariableReadiness(candidate, dependencyProvider)
return when (candidateReadiness) { return when (candidateReadiness) {
TypeVariableFixationReadiness.FORBIDDEN -> null TypeVariableFixationReadiness.FORBIDDEN -> null
@@ -94,7 +97,4 @@ class VariableFixationFinder {
private fun Context.isProperType(type: UnwrappedType): Boolean = private fun Context.isProperType(type: UnwrappedType): Boolean =
!type.contains { notFixedTypeVariables.containsKey(it.constructor) } !type.contains { notFixedTypeVariables.containsKey(it.constructor) }
private fun Collection<TypeConstructor>.sortByInitialOrder(): List<TypeConstructor> =
sortedBy { toString() } // todo
} }
@@ -50,9 +50,9 @@ class FixVariableConstraintPosition(val variable: NewTypeVariable) : ConstraintP
class KnownTypeParameterConstraintPosition(val typeArgument: KotlinType) : ConstraintPosition() { class KnownTypeParameterConstraintPosition(val typeArgument: KotlinType) : ConstraintPosition() {
override fun toString() = "TypeArgument $typeArgument" override fun toString() = "TypeArgument $typeArgument"
} }
class LambdaArgumentConstraintPosition(val lambdaArgument: PostponedLambdaArgument) : ConstraintPosition() { class LambdaArgumentConstraintPosition(val lambda: ResolvedLambdaAtom) : ConstraintPosition() {
override fun toString(): String { override fun toString(): String {
return "LambdaArgument $lambdaArgument" return "LambdaArgument $lambda"
} }
} }
@@ -52,8 +52,6 @@ interface ConstraintStorage {
val maxTypeDepthFromInitialConstraints: Int val maxTypeDepthFromInitialConstraints: Int
val errors: List<KotlinCallDiagnostic> val errors: List<KotlinCallDiagnostic>
val fixedTypeVariables: Map<TypeConstructor, UnwrappedType> val fixedTypeVariables: Map<TypeConstructor, UnwrappedType>
val postponedArguments: List<PostponedKotlinCallArgument>
val innerCalls: List<ResolvedKotlinCall.OnlyResolvedKotlinCall>
object Empty : ConstraintStorage { object Empty : ConstraintStorage {
override val allTypeVariables: Map<TypeConstructor, NewTypeVariable> get() = emptyMap() override val allTypeVariables: Map<TypeConstructor, NewTypeVariable> get() = emptyMap()
@@ -62,8 +60,6 @@ interface ConstraintStorage {
override val maxTypeDepthFromInitialConstraints: Int get() = 1 override val maxTypeDepthFromInitialConstraints: Int get() = 1
override val errors: List<KotlinCallDiagnostic> get() = emptyList() override val errors: List<KotlinCallDiagnostic> get() = emptyList()
override val fixedTypeVariables: Map<TypeConstructor, UnwrappedType> get() = emptyMap() override val fixedTypeVariables: Map<TypeConstructor, UnwrappedType> get() = emptyMap()
override val postponedArguments: List<PostponedKotlinCallArgument> get() = emptyList()
override val innerCalls: List<ResolvedKotlinCall.OnlyResolvedKotlinCall> get() = emptyList()
} }
} }
@@ -18,8 +18,6 @@ package org.jetbrains.kotlin.resolve.calls.inference.model
import org.jetbrains.kotlin.resolve.calls.inference.trimToSize import org.jetbrains.kotlin.resolve.calls.inference.trimToSize
import org.jetbrains.kotlin.resolve.calls.model.KotlinCallDiagnostic import org.jetbrains.kotlin.resolve.calls.model.KotlinCallDiagnostic
import org.jetbrains.kotlin.resolve.calls.model.PostponedKotlinCallArgument
import org.jetbrains.kotlin.resolve.calls.model.ResolvedKotlinCall
import org.jetbrains.kotlin.types.TypeConstructor import org.jetbrains.kotlin.types.TypeConstructor
import org.jetbrains.kotlin.types.UnwrappedType import org.jetbrains.kotlin.types.UnwrappedType
import java.util.* import java.util.*
@@ -105,6 +103,4 @@ internal class MutableConstraintStorage : ConstraintStorage {
override var maxTypeDepthFromInitialConstraints: Int = 1 override var maxTypeDepthFromInitialConstraints: Int = 1
override val errors: MutableList<KotlinCallDiagnostic> = ArrayList() override val errors: MutableList<KotlinCallDiagnostic> = ArrayList()
override val fixedTypeVariables: MutableMap<TypeConstructor, UnwrappedType> = LinkedHashMap() override val fixedTypeVariables: MutableMap<TypeConstructor, UnwrappedType> = LinkedHashMap()
override val postponedArguments: MutableList<PostponedKotlinCallArgument> = ArrayList()
override val innerCalls: MutableList<ResolvedKotlinCall.OnlyResolvedKotlinCall> = ArrayList()
} }
@@ -16,28 +16,28 @@
package org.jetbrains.kotlin.resolve.calls.inference.model package org.jetbrains.kotlin.resolve.calls.inference.model
import org.jetbrains.kotlin.resolve.calls.components.KotlinCallCompleter import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.resolve.calls.components.PostponedArgumentsAnalyzer import org.jetbrains.kotlin.resolve.calls.components.PostponedArgumentsAnalyzer
import org.jetbrains.kotlin.resolve.calls.inference.* import org.jetbrains.kotlin.resolve.calls.inference.*
import org.jetbrains.kotlin.resolve.calls.inference.components.* import org.jetbrains.kotlin.resolve.calls.inference.components.ConstraintInjector
import org.jetbrains.kotlin.resolve.calls.inference.components.KotlinConstraintSystemCompleter
import org.jetbrains.kotlin.resolve.calls.inference.components.NewTypeSubstitutor
import org.jetbrains.kotlin.resolve.calls.inference.components.ResultTypeResolver
import org.jetbrains.kotlin.resolve.calls.model.KotlinCallDiagnostic import org.jetbrains.kotlin.resolve.calls.model.KotlinCallDiagnostic
import org.jetbrains.kotlin.resolve.calls.model.PostponedKotlinCallArgument
import org.jetbrains.kotlin.resolve.calls.model.PostponedLambdaArgument
import org.jetbrains.kotlin.resolve.calls.model.ResolvedKotlinCall
import org.jetbrains.kotlin.resolve.calls.tower.isSuccess import org.jetbrains.kotlin.resolve.calls.tower.isSuccess
import org.jetbrains.kotlin.types.ErrorUtils
import org.jetbrains.kotlin.types.TypeConstructor import org.jetbrains.kotlin.types.TypeConstructor
import org.jetbrains.kotlin.types.UnwrappedType import org.jetbrains.kotlin.types.UnwrappedType
import org.jetbrains.kotlin.types.typeUtil.contains import org.jetbrains.kotlin.types.typeUtil.contains
import org.jetbrains.kotlin.utils.SmartList import org.jetbrains.kotlin.utils.SmartList
import java.util.*
class NewConstraintSystemImpl(val constraintInjector: ConstraintInjector, val resultTypeResolver: ResultTypeResolver): class NewConstraintSystemImpl(
private val constraintInjector: ConstraintInjector,
override val builtIns: KotlinBuiltIns
):
NewConstraintSystem, NewConstraintSystem,
ConstraintSystemBuilder, ConstraintSystemBuilder,
ConstraintInjector.Context, ConstraintInjector.Context,
ResultTypeResolver.Context, ResultTypeResolver.Context,
KotlinCallCompleter.Context,
KotlinConstraintSystemCompleter.Context, KotlinConstraintSystemCompleter.Context,
PostponedArgumentsAnalyzer.Context PostponedArgumentsAnalyzer.Context
{ {
@@ -69,12 +69,6 @@ class NewConstraintSystemImpl(val constraintInjector: ConstraintInjector, val re
return storage return storage
} }
override fun asCallCompleterContext(): KotlinCallCompleter.Context {
checkState(State.BUILDING, State.COMPLETION)
state = State.COMPLETION
return this
}
override fun asConstraintSystemCompleterContext() = apply { checkState(State.BUILDING) } override fun asConstraintSystemCompleterContext() = apply { checkState(State.BUILDING) }
override fun asPostponedArgumentsAnalyzerContext() = apply { checkState(State.BUILDING) } override fun asPostponedArgumentsAnalyzerContext() = apply { checkState(State.BUILDING) }
@@ -150,51 +144,11 @@ class NewConstraintSystemImpl(val constraintInjector: ConstraintInjector, val re
return false return false
} }
override fun addPostponedArgument(postponedArgument: PostponedKotlinCallArgument) {
checkState(State.BUILDING, State.COMPLETION)
storage.postponedArguments.add(postponedArgument)
}
private fun getVariablesForFixation(): Map<NewTypeVariable, UnwrappedType> {
val fixedVariables = LinkedHashMap<NewTypeVariable, UnwrappedType>()
for (variableWithConstrains in storage.notFixedTypeVariables.values) {
val resultType = resultTypeResolver.findResultIfThereIsEqualsConstraint(
apply { checkState(State.BUILDING) },
variableWithConstrains,
allowedFixToNotProperType = false
)
if (resultType != null) {
fixedVariables[variableWithConstrains.typeVariable] = resultType
}
}
return fixedVariables
}
override fun simplify(): NewTypeSubstitutor {
checkState(State.BUILDING)
var fixedVariables = getVariablesForFixation()
while (fixedVariables.isNotEmpty()) {
for ((variable, resultType) in fixedVariables) {
fixVariable(variable, resultType)
}
fixedVariables = getVariablesForFixation()
}
return storage.buildCurrentSubstitutor()
}
// ConstraintSystemBuilder, KotlinConstraintSystemCompleter.Context // ConstraintSystemBuilder, KotlinConstraintSystemCompleter.Context
override val hasContradiction: Boolean override val hasContradiction: Boolean
get() = diagnostics.any { !it.candidateApplicability.isSuccess }.apply { checkState(State.BUILDING, State.COMPLETION, State.TRANSACTION) } get() = diagnostics.any { !it.candidateApplicability.isSuccess }.apply { checkState(State.FREEZED, State.BUILDING, State.COMPLETION, State.TRANSACTION) }
// ConstraintSystemBuilder override fun addOtherSystem(otherSystem: ConstraintStorage) {
override fun addInnerCall(innerCall: ResolvedKotlinCall.OnlyResolvedKotlinCall) {
checkState(State.BUILDING, State.COMPLETION)
storage.innerCalls.add(innerCall)
val otherSystem = innerCall.candidate.lastCall.constraintSystem.asReadOnlyStorage()
storage.allTypeVariables.putAll(otherSystem.allTypeVariables) storage.allTypeVariables.putAll(otherSystem.allTypeVariables)
for ((variable, constraints) in otherSystem.notFixedTypeVariables) { for ((variable, constraints) in otherSystem.notFixedTypeVariables) {
notFixedTypeVariables[variable] = MutableVariableWithConstraints(constraints.typeVariable, constraints.constraints) notFixedTypeVariables[variable] = MutableVariableWithConstraints(constraints.typeVariable, constraints.constraints)
@@ -203,11 +157,8 @@ class NewConstraintSystemImpl(val constraintInjector: ConstraintInjector, val re
storage.maxTypeDepthFromInitialConstraints = Math.max(storage.maxTypeDepthFromInitialConstraints, otherSystem.maxTypeDepthFromInitialConstraints) storage.maxTypeDepthFromInitialConstraints = Math.max(storage.maxTypeDepthFromInitialConstraints, otherSystem.maxTypeDepthFromInitialConstraints)
storage.errors.addAll(otherSystem.errors) storage.errors.addAll(otherSystem.errors)
storage.fixedTypeVariables.putAll(otherSystem.fixedTypeVariables) storage.fixedTypeVariables.putAll(otherSystem.fixedTypeVariables)
storage.postponedArguments.addAll(otherSystem.postponedArguments)
storage.innerCalls.addAll(otherSystem.innerCalls)
} }
// ResultTypeResolver.Context, ConstraintSystemBuilder // ResultTypeResolver.Context, ConstraintSystemBuilder
override fun isProperType(type: UnwrappedType): Boolean { override fun isProperType(type: UnwrappedType): Boolean {
checkState(State.BUILDING, State.COMPLETION, State.TRANSACTION) checkState(State.BUILDING, State.COMPLETION, State.TRANSACTION)
@@ -246,16 +197,6 @@ class NewConstraintSystemImpl(val constraintInjector: ConstraintInjector, val re
storage.errors.add(error) storage.errors.add(error)
} }
// KotlinCallCompleter.Context, FixationOrderCalculator.Context
override val lambdaArguments: List<PostponedLambdaArgument> get() {
checkState(State.BUILDING, State.COMPLETION)
return storage.postponedArguments.filterIsInstance<PostponedLambdaArgument>()
}
// FixationOrderCalculator.Context, KotlinCallCompleter.Context, KotlinConstraintSystemCompleter.Context
override val postponedArguments: List<PostponedKotlinCallArgument>
get() = storage.postponedArguments.apply { checkState(State.BUILDING, State.COMPLETION) }
// KotlinConstraintSystemCompleter.Context // KotlinConstraintSystemCompleter.Context
override fun fixVariable(variable: NewTypeVariable, resultType: UnwrappedType) { override fun fixVariable(variable: NewTypeVariable, resultType: UnwrappedType) {
checkState(State.BUILDING, State.COMPLETION) checkState(State.BUILDING, State.COMPLETION)
@@ -272,12 +213,6 @@ class NewConstraintSystemImpl(val constraintInjector: ConstraintInjector, val re
storage.fixedTypeVariables[variable.freshTypeConstructor] = resultType storage.fixedTypeVariables[variable.freshTypeConstructor] = resultType
} }
// KotlinCallCompleter.Context
override val innerCalls: List<ResolvedKotlinCall.OnlyResolvedKotlinCall> get() {
checkState(State.COMPLETION)
return storage.innerCalls
}
// KotlinConstraintSystemCompleter.Context, PostponedArgumentsAnalyzer.Context // KotlinConstraintSystemCompleter.Context, PostponedArgumentsAnalyzer.Context
override fun canBeProper(type: UnwrappedType): Boolean { override fun canBeProper(type: UnwrappedType): Boolean {
checkState(State.BUILDING, State.COMPLETION) checkState(State.BUILDING, State.COMPLETION)
@@ -289,17 +224,4 @@ class NewConstraintSystemImpl(val constraintInjector: ConstraintInjector, val re
checkState(State.BUILDING, State.COMPLETION) checkState(State.BUILDING, State.COMPLETION)
return storage.buildCurrentSubstitutor() return storage.buildCurrentSubstitutor()
} }
// KotlinCallCompleter.Context
override fun buildResultingSubstitutor(): NewTypeSubstitutor {
checkState(State.COMPLETION)
val currentSubstitutorMap = storage.fixedTypeVariables.entries.associate {
it.key to it.value
}
val uninferredSubstitutorMap = storage.notFixedTypeVariables.entries.associate { (freshTypeConstructor, typeVariable) ->
freshTypeConstructor to ErrorUtils.createErrorTypeWithCustomConstructor("Uninferred type", typeVariable.typeVariable.freshTypeConstructor)
}
return NewTypeSubstitutorByConstructorMap(currentSubstitutorMap + uninferredSubstitutorMap)
}
} }
@@ -19,7 +19,7 @@ package org.jetbrains.kotlin.resolve.calls.model
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
interface KotlinCall { interface KotlinCall : ResolutionAtom {
val callKind: KotlinCallKind val callKind: KotlinCallKind
val explicitReceiver: ReceiverKotlinCallArgument? val explicitReceiver: ReceiverKotlinCallArgument?
@@ -43,6 +43,18 @@ private fun SimpleKotlinCallArgument.checkReceiverInvariants() {
assert(argumentName == null) { assert(argumentName == null) {
"Argument name should be null for receiver: $this, but it is $argumentName" "Argument name should be null for receiver: $this, but it is $argumentName"
} }
checkArgumentInvariants()
}
private fun KotlinCallArgument.checkArgumentInvariants() {
if (this is SubKotlinCallArgument) {
assert(callResult.type == CallResolutionResult.Type.PARTIAL) {
"SubCall should has type PARTIAL: $callResult"
}
assert(callResult.resultCallAtom != null) {
"SubCall should has resultCallAtom: $callResult"
}
}
} }
fun KotlinCall.checkCallInvariants() { fun KotlinCall.checkCallInvariants() {
@@ -52,6 +64,8 @@ fun KotlinCall.checkCallInvariants() {
(explicitReceiver as? SimpleKotlinCallArgument)?.checkReceiverInvariants() (explicitReceiver as? SimpleKotlinCallArgument)?.checkReceiverInvariants()
dispatchReceiverForInvokeExtension?.checkReceiverInvariants() dispatchReceiverForInvokeExtension?.checkReceiverInvariants()
argumentsInParenthesis.forEach(KotlinCallArgument::checkArgumentInvariants)
externalArgument?.checkArgumentInvariants()
if (callKind != KotlinCallKind.FUNCTION) { if (callKind != KotlinCallKind.FUNCTION) {
assert(externalArgument == null) { assert(externalArgument == null) {
@@ -26,12 +26,15 @@ import org.jetbrains.kotlin.resolve.scopes.receivers.TransientReceiver
import org.jetbrains.kotlin.types.UnwrappedType import org.jetbrains.kotlin.types.UnwrappedType
interface ReceiverKotlinCallArgument { interface ReceiverKotlinCallArgument : KotlinCallArgument {
val receiver: DetailedReceiver val receiver: DetailedReceiver
} }
class QualifierReceiverKotlinCallArgument(override val receiver: QualifierReceiver) : ReceiverKotlinCallArgument { class QualifierReceiverKotlinCallArgument(override val receiver: QualifierReceiver) : ReceiverKotlinCallArgument {
override fun toString() = "$receiver" override fun toString() = "$receiver"
override val isSpread get() = false
override val argumentName: Name? get() = null
} }
interface KotlinCallArgument { interface KotlinCallArgument {
@@ -39,7 +42,7 @@ interface KotlinCallArgument {
val argumentName: Name? val argumentName: Name?
} }
interface PostponableKotlinCallArgument : KotlinCallArgument interface PostponableKotlinCallArgument : KotlinCallArgument, ResolutionAtom
interface SimpleKotlinCallArgument : KotlinCallArgument, ReceiverKotlinCallArgument { interface SimpleKotlinCallArgument : KotlinCallArgument, ReceiverKotlinCallArgument {
override val receiver: ReceiverValueWithSmartCastInfo override val receiver: ReceiverValueWithSmartCastInfo
@@ -47,10 +50,10 @@ interface SimpleKotlinCallArgument : KotlinCallArgument, ReceiverKotlinCallArgum
val isSafeCall: Boolean val isSafeCall: Boolean
} }
interface ExpressionKotlinCallArgument : SimpleKotlinCallArgument interface ExpressionKotlinCallArgument : SimpleKotlinCallArgument, ResolutionAtom
interface SubKotlinCallArgument : SimpleKotlinCallArgument { interface SubKotlinCallArgument : SimpleKotlinCallArgument {
val resolvedCall: ResolvedKotlinCall.OnlyResolvedKotlinCall val callResult: CallResolutionResult
} }
interface LambdaKotlinCallArgument : PostponableKotlinCallArgument { interface LambdaKotlinCallArgument : PostponableKotlinCallArgument {
@@ -154,3 +154,19 @@ object AbstractSuperCall : KotlinCallDiagnostic(RUNTIME_ERROR) {
reporter.onCall(this) reporter.onCall(this)
} }
} }
// candidates result
class NoneCandidatesCallDiagnostic(val kotlinCall: KotlinCall) : KotlinCallDiagnostic(INAPPLICABLE) {
override fun report(reporter: DiagnosticReporter) {
reporter.onCall(this)
}
}
class ManyCandidatesCallDiagnostic(
val kotlinCall: KotlinCall,
val candidates: Collection<KotlinResolutionCandidate>
) : KotlinCallDiagnostic(INAPPLICABLE) {
override fun report(reporter: DiagnosticReporter) {
reporter.onCall(this)
}
}
@@ -16,11 +16,15 @@
package org.jetbrains.kotlin.resolve.calls.model package org.jetbrains.kotlin.resolve.calls.model
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.builtins.ReflectionTypes import org.jetbrains.kotlin.builtins.ReflectionTypes
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.resolve.calls.components.* import org.jetbrains.kotlin.resolve.calls.components.*
import org.jetbrains.kotlin.resolve.calls.inference.addSubsystemForArgument
import org.jetbrains.kotlin.resolve.calls.inference.components.ConstraintInjector import org.jetbrains.kotlin.resolve.calls.inference.components.ConstraintInjector
import org.jetbrains.kotlin.resolve.calls.inference.components.ResultTypeResolver import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintStorage
import org.jetbrains.kotlin.resolve.calls.inference.model.NewConstraintSystemImpl
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind
import org.jetbrains.kotlin.resolve.calls.tower.* import org.jetbrains.kotlin.resolve.calls.tower.*
import org.jetbrains.kotlin.resolve.descriptorUtil.hasDynamicExtensionAnnotation import org.jetbrains.kotlin.resolve.descriptorUtil.hasDynamicExtensionAnnotation
@@ -34,16 +38,29 @@ class KotlinCallComponents(
val statelessCallbacks: KotlinResolutionStatelessCallbacks, val statelessCallbacks: KotlinResolutionStatelessCallbacks,
val argumentsToParametersMapper: ArgumentsToParametersMapper, val argumentsToParametersMapper: ArgumentsToParametersMapper,
val typeArgumentsToParametersMapper: TypeArgumentsToParametersMapper, val typeArgumentsToParametersMapper: TypeArgumentsToParametersMapper,
val resultTypeResolver: ResultTypeResolver,
val constraintInjector: ConstraintInjector, val constraintInjector: ConstraintInjector,
val reflectionTypes: ReflectionTypes val reflectionTypes: ReflectionTypes,
val builtIns: KotlinBuiltIns
) )
class SimpleCandidateFactory( class SimpleCandidateFactory(
val callComponents: KotlinCallComponents, val callComponents: KotlinCallComponents,
val scopeTower: ImplicitScopeTower, val scopeTower: ImplicitScopeTower,
val kotlinCall: KotlinCall val kotlinCall: KotlinCall
): CandidateFactory<SimpleKotlinResolutionCandidate> { ): CandidateFactory<KotlinResolutionCandidate> {
val baseSystem: ConstraintStorage
init {
val baseSystem = NewConstraintSystemImpl(callComponents.constraintInjector, callComponents.builtIns)
baseSystem.addSubsystemForArgument(kotlinCall.explicitReceiver)
baseSystem.addSubsystemForArgument(kotlinCall.dispatchReceiverForInvokeExtension)
for (argument in kotlinCall.argumentsInParenthesis) {
baseSystem.addSubsystemForArgument(argument)
}
baseSystem.addSubsystemForArgument(kotlinCall.externalArgument)
this.baseSystem = baseSystem.asReadOnlyStorage()
}
// todo: try something else, because current method is ugly and unstable // todo: try something else, because current method is ugly and unstable
private fun createReceiverArgument( private fun createReceiverArgument(
@@ -64,37 +81,80 @@ class SimpleCandidateFactory(
else -> null else -> null
} }
fun createCandidate(givenCandidate: GivenCandidate): KotlinResolutionCandidate {
val isSafeCall = (kotlinCall.explicitReceiver as? SimpleKotlinCallArgument)?.isSafeCall ?: false
val explicitReceiverKind = if (givenCandidate.dispatchReceiver == null) ExplicitReceiverKind.NO_EXPLICIT_RECEIVER else ExplicitReceiverKind.DISPATCH_RECEIVER
val dispatchArgumentReceiver = givenCandidate.dispatchReceiver?.let { ReceiverExpressionKotlinCallArgument(it, isSafeCall) }
return createCandidate(givenCandidate.descriptor, explicitReceiverKind, dispatchArgumentReceiver, null,
listOf(), givenCandidate.knownTypeParametersResultingSubstitutor)
}
override fun createCandidate( override fun createCandidate(
towerCandidate: CandidateWithBoundDispatchReceiver, towerCandidate: CandidateWithBoundDispatchReceiver,
explicitReceiverKind: ExplicitReceiverKind, explicitReceiverKind: ExplicitReceiverKind,
extensionReceiver: ReceiverValueWithSmartCastInfo? extensionReceiver: ReceiverValueWithSmartCastInfo?
): SimpleKotlinResolutionCandidate { ): KotlinResolutionCandidate {
val dispatchArgumentReceiver = createReceiverArgument(kotlinCall.getExplicitDispatchReceiver(explicitReceiverKind), val dispatchArgumentReceiver = createReceiverArgument(kotlinCall.getExplicitDispatchReceiver(explicitReceiverKind),
towerCandidate.dispatchReceiver) towerCandidate.dispatchReceiver)
val extensionArgumentReceiver = createReceiverArgument(kotlinCall.getExplicitExtensionReceiver(explicitReceiverKind), extensionReceiver) val extensionArgumentReceiver = createReceiverArgument(kotlinCall.getExplicitExtensionReceiver(explicitReceiverKind), extensionReceiver)
if (ErrorUtils.isError(towerCandidate.descriptor)) { return createCandidate(towerCandidate.descriptor, explicitReceiverKind, dispatchArgumentReceiver,
return ErrorKotlinResolutionCandidate(callComponents, scopeTower, kotlinCall, explicitReceiverKind, dispatchArgumentReceiver, extensionArgumentReceiver, towerCandidate.descriptor) extensionArgumentReceiver, towerCandidate.diagnostics, knownSubstitutor = null)
}
private fun createCandidate(
descriptor: CallableDescriptor,
explicitReceiverKind: ExplicitReceiverKind,
dispatchArgumentReceiver: SimpleKotlinCallArgument?,
extensionArgumentReceiver: SimpleKotlinCallArgument?,
initialDiagnostics: Collection<KotlinCallDiagnostic>,
knownSubstitutor: TypeSubstitutor?
): KotlinResolutionCandidate {
val resolvedKtCall = MutableResolvedCallAtom(kotlinCall, descriptor, explicitReceiverKind,
dispatchArgumentReceiver, extensionArgumentReceiver)
if (ErrorUtils.isError(descriptor)) {
return KotlinResolutionCandidate(callComponents, scopeTower, baseSystem, resolvedKtCall, knownSubstitutor, listOf(ErrorDescriptorResolutionPart))
} }
val candidateDiagnostics = towerCandidate.diagnostics.toMutableList() val candidate = KotlinResolutionCandidate(callComponents, scopeTower, baseSystem, resolvedKtCall, knownSubstitutor)
if (callComponents.statelessCallbacks.isHiddenInResolution(towerCandidate.descriptor, kotlinCall)) {
candidateDiagnostics.add(HiddenDescriptor) initialDiagnostics.forEach(candidate::addDiagnostic)
if (callComponents.statelessCallbacks.isHiddenInResolution(descriptor, kotlinCall)) {
candidate.addDiagnostic(HiddenDescriptor)
} }
if (extensionReceiver != null) { if (extensionArgumentReceiver != null) {
val parameterIsDynamic = towerCandidate.descriptor.extensionReceiverParameter!!.value.type.isDynamic() val parameterIsDynamic = descriptor.extensionReceiverParameter!!.value.type.isDynamic()
val argumentIsDynamic = extensionReceiver.receiverValue.type.isDynamic() val argumentIsDynamic = extensionArgumentReceiver.receiver.receiverValue.type.isDynamic()
if (parameterIsDynamic != argumentIsDynamic || if (parameterIsDynamic != argumentIsDynamic ||
(parameterIsDynamic && !towerCandidate.descriptor.hasDynamicExtensionAnnotation())) { (parameterIsDynamic && !descriptor.hasDynamicExtensionAnnotation())) {
candidateDiagnostics.add(HiddenExtensionRelatedToDynamicTypes) candidate.addDiagnostic(HiddenExtensionRelatedToDynamicTypes)
} }
} }
return SimpleKotlinResolutionCandidate(callComponents, scopeTower, kotlinCall, explicitReceiverKind, dispatchArgumentReceiver, extensionArgumentReceiver, return candidate
towerCandidate.descriptor, null, candidateDiagnostics)
} }
fun createErrorCandidate(): KotlinResolutionCandidate {
val errorScope = ErrorUtils.createErrorScope("Error resolution candidate for call $kotlinCall")
val errorDescriptor = if (kotlinCall.callKind == KotlinCallKind.VARIABLE) {
errorScope.getContributedVariables(kotlinCall.name, scopeTower.location)
}
else {
errorScope.getContributedFunctions(kotlinCall.name, scopeTower.location)
}.first()
val dispatchReceiver = createReceiverArgument(kotlinCall.explicitReceiver, fromResolution = null)
val explicitReceiverKind = if (dispatchReceiver == null) ExplicitReceiverKind.NO_EXPLICIT_RECEIVER else ExplicitReceiverKind.DISPATCH_RECEIVER
return createCandidate(errorDescriptor, explicitReceiverKind, dispatchReceiver, extensionArgumentReceiver = null,
initialDiagnostics = listOf(), knownSubstitutor = null)
}
} }
enum class KotlinCallKind(vararg resolutionPart: ResolutionPart) { enum class KotlinCallKind(vararg resolutionPart: ResolutionPart) {
@@ -105,7 +165,7 @@ enum class KotlinCallKind(vararg resolutionPart: ResolutionPart) {
CheckAbstractSuperCallPart, CheckAbstractSuperCallPart,
NoTypeArguments, NoTypeArguments,
NoArguments, NoArguments,
CreateDescriptorWithFreshTypeVariables, CreateFreshVariablesSubstitutor,
CheckExplicitReceiverKindConsistency, CheckExplicitReceiverKindConsistency,
CheckReceivers CheckReceivers
), ),
@@ -116,10 +176,12 @@ enum class KotlinCallKind(vararg resolutionPart: ResolutionPart) {
CheckAbstractSuperCallPart, CheckAbstractSuperCallPart,
MapTypeArguments, MapTypeArguments,
MapArguments, MapArguments,
CreateDescriptorWithFreshTypeVariables, ArgumentsToCandidateParameterDescriptor,
CreateFreshVariablesSubstitutor,
CheckExplicitReceiverKindConsistency, CheckExplicitReceiverKindConsistency,
CheckReceivers, CheckReceivers,
CheckArguments CheckArguments,
CheckExternalArgument
), ),
UNSUPPORTED(); UNSUPPORTED();
@@ -127,7 +189,6 @@ enum class KotlinCallKind(vararg resolutionPart: ResolutionPart) {
} }
class GivenCandidate( class GivenCandidate(
val scopeTower: ImplicitScopeTower,
val descriptor: FunctionDescriptor, val descriptor: FunctionDescriptor,
val dispatchReceiver: ReceiverValueWithSmartCastInfo?, val dispatchReceiver: ReceiverValueWithSmartCastInfo?,
val knownTypeParametersResultingSubstitutor: TypeSubstitutor? val knownTypeParametersResultingSubstitutor: TypeSubstitutor?
@@ -1,96 +0,0 @@
/*
* Copyright 2010-2017 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.kotlin.resolve.calls.model
import org.jetbrains.kotlin.builtins.createFunctionType
import org.jetbrains.kotlin.builtins.getReceiverTypeFromFunctionType
import org.jetbrains.kotlin.builtins.getReturnTypeFromFunctionType
import org.jetbrains.kotlin.builtins.getValueParameterTypesFromFunctionType
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.resolve.calls.components.CallableReferenceCandidate
import org.jetbrains.kotlin.resolve.calls.components.getFunctionTypeFromCallableReferenceExpectedType
import org.jetbrains.kotlin.resolve.calls.inference.model.NewTypeVariable
import org.jetbrains.kotlin.types.SimpleType
import org.jetbrains.kotlin.types.UnwrappedType
import org.jetbrains.kotlin.types.typeUtil.builtIns
sealed class PostponedKotlinCallArgument {
abstract val argument: PostponableKotlinCallArgument
abstract val analyzed: Boolean
abstract val inputTypes: Collection<UnwrappedType>
abstract val outputType: UnwrappedType?
}
class PostponedLambdaArgument(
override val argument: LambdaKotlinCallArgument,
val isSuspend: Boolean,
val receiver: UnwrappedType?,
val parameters: List<UnwrappedType>,
val returnType: UnwrappedType
) : PostponedKotlinCallArgument() {
override var analyzed: Boolean = false
val type: SimpleType = createFunctionType(returnType.builtIns, Annotations.EMPTY, receiver, parameters, null, returnType, isSuspend) // todo support annotations
override val inputTypes: Collection<UnwrappedType> get() = receiver?.let { parameters + it } ?: parameters
override val outputType: UnwrappedType get() = returnType
lateinit var resultArguments: List<SimpleKotlinCallArgument>
lateinit var finalReturnType: UnwrappedType
}
class PostponedCallableReferenceArgument(
override val argument: CallableReferenceKotlinCallArgument,
val expectedType: UnwrappedType
) : PostponedKotlinCallArgument() {
override var analyzed: Boolean = false
override val inputTypes: Collection<UnwrappedType>
get() {
val functionType = getFunctionTypeFromCallableReferenceExpectedType(expectedType) ?: return emptyList()
val parameters = functionType.getValueParameterTypesFromFunctionType().map { it.type.unwrap() }
val receiver = functionType.getReceiverTypeFromFunctionType()?.unwrap()
return receiver?.let { parameters + it } ?: parameters
}
override val outputType: UnwrappedType?
get() {
val functionType = getFunctionTypeFromCallableReferenceExpectedType(expectedType) ?: return null
return functionType.getReturnTypeFromFunctionType().unwrap()
}
var analyzedAndThereIsResult: Boolean = false
lateinit var myTypeVariables: List<NewTypeVariable>
lateinit var callableResolutionCandidate: CallableReferenceCandidate
}
class PostponedCollectionLiteralArgument(
override val argument: CollectionLiteralKotlinCallArgument,
val expectedType: UnwrappedType
) : PostponedKotlinCallArgument() {
// for now we consider all such arguments as analyzed because they processed via special logic anyway
override val analyzed get() = true
override val inputTypes: Collection<UnwrappedType>
get() = emptyList()
override val outputType: UnwrappedType?
get() = null
}
@@ -0,0 +1,173 @@
/*
* Copyright 2010-2017 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.kotlin.resolve.calls.model
import org.jetbrains.kotlin.builtins.getReceiverTypeFromFunctionType
import org.jetbrains.kotlin.builtins.getReturnTypeFromFunctionType
import org.jetbrains.kotlin.builtins.getValueParameterTypesFromFunctionType
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
import org.jetbrains.kotlin.resolve.calls.components.CallableReferenceCandidate
import org.jetbrains.kotlin.resolve.calls.components.TypeArgumentsToParametersMapper
import org.jetbrains.kotlin.resolve.calls.components.getFunctionTypeFromCallableReferenceExpectedType
import org.jetbrains.kotlin.resolve.calls.inference.components.FreshVariableNewTypeSubstitutor
import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintStorage
import org.jetbrains.kotlin.resolve.calls.inference.model.TypeVariableForLambdaReturnType
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind
import org.jetbrains.kotlin.types.UnwrappedType
/**
* Call, Callable reference, lambda & function expression, collection literal.
* In future we should add literals here, because they have similar lifecycle.
*
* Expression with type is also primitive. This is done for simplification. todo
*/
interface ResolutionAtom
sealed class ResolvedAtom {
abstract val atom: ResolutionAtom? // CallResolutionResult has no ResolutionAtom
var analyzed: Boolean = false
private set
lateinit var subResolvedAtoms: List<ResolvedAtom>
private set
lateinit var diagnostics: Collection<KotlinCallDiagnostic>
private set
protected open fun setAnalyzedResults(subResolvedAtoms: List<ResolvedAtom>, diagnostics: Collection<KotlinCallDiagnostic>) {
assert(!analyzed) {
"Already analyzed: $this"
}
analyzed = true
this.subResolvedAtoms = subResolvedAtoms
this.diagnostics = diagnostics
}
}
abstract class ResolvedCallAtom : ResolvedAtom() {
abstract override val atom: KotlinCall
abstract val candidateDescriptor: CallableDescriptor
abstract val explicitReceiverKind: ExplicitReceiverKind
abstract val dispatchReceiverArgument: SimpleKotlinCallArgument?
abstract val extensionReceiverArgument: SimpleKotlinCallArgument?
abstract val typeArgumentMappingByOriginal: TypeArgumentsToParametersMapper.TypeArgumentsMapping
abstract val argumentMappingByOriginal: Map<ValueParameterDescriptor, ResolvedCallArgument>
abstract val substitutor: FreshVariableNewTypeSubstitutor
}
class ResolvedExpressionAtom(override val atom: ExpressionKotlinCallArgument) : ResolvedAtom() {
init {
setAnalyzedResults(listOf(), listOf())
}
}
sealed class PostponedResolvedAtom : ResolvedAtom() {
abstract val inputTypes: Collection<UnwrappedType>
abstract val outputType: UnwrappedType?
}
class ResolvedLambdaAtom(
override val atom: LambdaKotlinCallArgument,
val isSuspend: Boolean,
val receiver: UnwrappedType?,
val parameters: List<UnwrappedType>,
val returnType: UnwrappedType,
val typeVariableForLambdaReturnType: TypeVariableForLambdaReturnType?
) : PostponedResolvedAtom() {
lateinit var resultArguments: List<KotlinCallArgument>
private set
fun setAnalyzedResults(
resultArguments: List<KotlinCallArgument>,
subResolvedAtoms: List<ResolvedAtom>,
diagnostics: Collection<KotlinCallDiagnostic>
) {
this.resultArguments = resultArguments
setAnalyzedResults(subResolvedAtoms, diagnostics)
}
override val inputTypes: Collection<UnwrappedType> get() = receiver?.let { parameters + it } ?: parameters
override val outputType: UnwrappedType get() = returnType
}
class ResolvedCallableReferenceAtom(
override val atom: CallableReferenceKotlinCallArgument,
val expectedType: UnwrappedType?
) : PostponedResolvedAtom() {
var candidate: CallableReferenceCandidate? = null
private set
fun setAnalyzedResults(
candidate: CallableReferenceCandidate?,
subResolvedAtoms: List<ResolvedAtom>,
diagnostics: Collection<KotlinCallDiagnostic>
) {
this.candidate = candidate
setAnalyzedResults(subResolvedAtoms, diagnostics)
}
override val inputTypes: Collection<UnwrappedType>
get() {
val functionType = getFunctionTypeFromCallableReferenceExpectedType(expectedType) ?: return emptyList()
val parameters = functionType.getValueParameterTypesFromFunctionType().map { it.type.unwrap() }
val receiver = functionType.getReceiverTypeFromFunctionType()?.unwrap()
return receiver?.let { parameters + it } ?: parameters
}
override val outputType: UnwrappedType?
get() {
val functionType = getFunctionTypeFromCallableReferenceExpectedType(expectedType) ?: return null
return functionType.getReturnTypeFromFunctionType().unwrap()
}
}
class ResolvedCollectionLiteralAtom(
override val atom: CollectionLiteralKotlinCallArgument,
val expectedType: UnwrappedType?
) : ResolvedAtom() {
init {
setAnalyzedResults(listOf(), listOf())
}
}
class CallResolutionResult(
val type: Type,
val resultCallAtom: ResolvedCallAtom?,
diagnostics: List<KotlinCallDiagnostic>,
val constraintSystem: ConstraintStorage
) : ResolvedAtom() {
override val atom: ResolutionAtom? get() = null
enum class Type {
COMPLETED, // resultSubstitutor possible create use constraintSystem
PARTIAL,
ERROR // if resultCallAtom == null it means that there is errors NoneCandidates or ManyCandidates
}
init {
setAnalyzedResults(listOfNotNull(resultCallAtom), diagnostics)
}
override fun toString() = "$type, resultCallAtom = $resultCallAtom, (${diagnostics.joinToString()})"
}
val ResolvedCallAtom.freshReturnType: UnwrappedType? get() {
val returnType = candidateDescriptor.returnType ?: return null
return substitutor.safeSubstitute(returnType.unwrap())
}
@@ -20,127 +20,163 @@ import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
import org.jetbrains.kotlin.renderer.DescriptorRenderer import org.jetbrains.kotlin.renderer.DescriptorRenderer
import org.jetbrains.kotlin.resolve.calls.components.TypeArgumentsToParametersMapper import org.jetbrains.kotlin.resolve.calls.components.TypeArgumentsToParametersMapper
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilder
import org.jetbrains.kotlin.resolve.calls.inference.NewConstraintSystem import org.jetbrains.kotlin.resolve.calls.inference.NewConstraintSystem
import org.jetbrains.kotlin.resolve.calls.inference.components.FreshVariableNewTypeSubstitutor
import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintStorage
import org.jetbrains.kotlin.resolve.calls.inference.model.NewConstraintSystemImpl import org.jetbrains.kotlin.resolve.calls.inference.model.NewConstraintSystemImpl
import org.jetbrains.kotlin.resolve.calls.inference.model.NewTypeVariable
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind
import org.jetbrains.kotlin.resolve.calls.tower.* import org.jetbrains.kotlin.resolve.calls.tower.*
import org.jetbrains.kotlin.types.TypeSubstitutor import org.jetbrains.kotlin.types.TypeSubstitutor
import java.util.*
interface ResolutionPart { abstract class ResolutionPart {
fun SimpleKotlinResolutionCandidate.process(): List<KotlinCallDiagnostic> abstract fun KotlinResolutionCandidate.process(workIndex: Int)
open fun KotlinResolutionCandidate.workCount(): Int = 1
// helper functions
protected inline val KotlinResolutionCandidate.candidateDescriptor get() = resolvedCall.candidateDescriptor
protected inline val KotlinResolutionCandidate.kotlinCall get() = resolvedCall.atom
} }
sealed class KotlinResolutionCandidate : Candidate { interface KotlinDiagnosticsHolder {
abstract val kotlinCall: KotlinCall fun addDiagnostic(diagnostic: KotlinCallDiagnostic)
abstract val lastCall: SimpleKotlinResolutionCandidate class SimpleHolder : KotlinDiagnosticsHolder {
} private val diagnostics = arrayListOf<KotlinCallDiagnostic>()
class VariableAsFunctionKotlinResolutionCandidate( override fun addDiagnostic(diagnostic: KotlinCallDiagnostic) {
override val kotlinCall: KotlinCall, diagnostics.add(diagnostic)
val resolvedVariable: SimpleKotlinResolutionCandidate,
val invokeCandidate: SimpleKotlinResolutionCandidate
) : KotlinResolutionCandidate() {
override val isSuccessful: Boolean get() = resolvedVariable.isSuccessful && invokeCandidate.isSuccessful
override val resultingApplicability: ResolutionCandidateApplicability
get() = maxOf(resolvedVariable.resultingApplicability, invokeCandidate.resultingApplicability)
override val lastCall: SimpleKotlinResolutionCandidate get() = invokeCandidate
}
sealed class AbstractSimpleKotlinResolutionCandidate(
val constraintSystem: NewConstraintSystem,
initialDiagnostics: Collection<KotlinCallDiagnostic> = emptyList()
) : KotlinResolutionCandidate() {
override val isSuccessful: Boolean
get() {
process(stopOnFirstError = true)
return !hasErrors
} }
override val resultingApplicability: ResolutionCandidateApplicability fun getDiagnostics(): List<KotlinCallDiagnostic> = diagnostics
get() {
process(stopOnFirstError = false)
return getResultApplicability(diagnostics + constraintSystem.diagnostics)
}
private val diagnostics = ArrayList<KotlinCallDiagnostic>()
protected var step = 0
private set
protected var hasErrors = false
private set
private fun process(stopOnFirstError: Boolean) {
while (step < resolutionSequence.size && (!stopOnFirstError || !hasErrors)) {
addDiagnostics(resolutionSequence[step].run { lastCall.process() })
step++
}
} }
private fun addDiagnostics(diagnostics: Collection<KotlinCallDiagnostic>) {
hasErrors = hasErrors || diagnostics.any { !it.candidateApplicability.isSuccess } ||
constraintSystem.diagnostics.any { !it.candidateApplicability.isSuccess }
this.diagnostics.addAll(diagnostics)
}
init {
addDiagnostics(initialDiagnostics)
}
fun getCandidateDiagnostics(): List<KotlinCallDiagnostic> = diagnostics
abstract val resolutionSequence: List<ResolutionPart>
} }
open class SimpleKotlinResolutionCandidate( fun KotlinDiagnosticsHolder.addDiagnosticIfNotNull(diagnostic: KotlinCallDiagnostic?) {
diagnostic?.let { addDiagnostic(it) }
}
/**
* baseSystem contains all information from arguments, i.e. it is union of all system of arguments
* Also by convention we suppose that baseSystem has no contradiction
*/
class KotlinResolutionCandidate(
val callComponents: KotlinCallComponents, val callComponents: KotlinCallComponents,
val scopeTower: ImplicitScopeTower, val scopeTower: ImplicitScopeTower,
override val kotlinCall: KotlinCall, private val baseSystem: ConstraintStorage,
val explicitReceiverKind: ExplicitReceiverKind, val resolvedCall: MutableResolvedCallAtom,
val dispatchReceiverArgument: SimpleKotlinCallArgument?, val knownTypeParametersResultingSubstitutor: TypeSubstitutor? = null,
val extensionReceiver: SimpleKotlinCallArgument?, private val resolutionSequence: List<ResolutionPart> = resolvedCall.atom.callKind.resolutionSequence
val candidateDescriptor: CallableDescriptor, ) : Candidate, KotlinDiagnosticsHolder {
val knownTypeParametersResultingSubstitutor: TypeSubstitutor?, private var newSystem: NewConstraintSystemImpl? = null
initialDiagnostics: Collection<KotlinCallDiagnostic> private val diagnostics = arrayListOf<KotlinCallDiagnostic>()
) : AbstractSimpleKotlinResolutionCandidate(NewConstraintSystemImpl(callComponents.constraintInjector, callComponents.resultTypeResolver), initialDiagnostics) { private var currentApplicability = ResolutionCandidateApplicability.RESOLVED
val csBuilder: ConstraintSystemBuilder get() = constraintSystem.getBuilder() private var subResolvedAtoms: MutableList<ResolvedAtom> = arrayListOf()
lateinit var typeArgumentMappingByOriginal: TypeArgumentsToParametersMapper.TypeArgumentsMapping private val stepCount = resolutionSequence.sumBy { it.run { workCount() } }
lateinit var argumentMappingByOriginal: Map<ValueParameterDescriptor, ResolvedCallArgument> private var step = 0
lateinit var descriptorWithFreshTypes: CallableDescriptor
lateinit var typeVariablesForFreshTypeParameters: List<NewTypeVariable>
override val lastCall: SimpleKotlinResolutionCandidate get() = this fun getSystem(): NewConstraintSystem {
override val resolutionSequence: List<ResolutionPart> get() = kotlinCall.callKind.resolutionSequence if (newSystem == null) {
newSystem = NewConstraintSystemImpl(callComponents.constraintInjector, callComponents.builtIns)
newSystem!!.addOtherSystem(baseSystem)
}
return newSystem!!
}
internal val csBuilder get() = getSystem().getBuilder()
override fun addDiagnostic(diagnostic: KotlinCallDiagnostic) {
diagnostics.add(diagnostic)
currentApplicability = maxOf(diagnostic.candidateApplicability, currentApplicability)
}
fun addResolvedKtPrimitive(resolvedAtom: ResolvedAtom) {
subResolvedAtoms.add(resolvedAtom)
}
private fun processParts(stopOnFirstError: Boolean) {
if (stopOnFirstError && step > 0) return // error already happened
if (step == stepCount) return
var partIndex = 0
var workStep = step
while (workStep > 0) {
val workCount = resolutionSequence[partIndex].run { workCount() }
if (workStep >= workCount) {
partIndex++
workStep -= workCount
}
}
if (partIndex < resolutionSequence.size) {
if (processPart(resolutionSequence[partIndex], stopOnFirstError, workStep)) return
partIndex++
}
while (partIndex < resolutionSequence.size) {
if (processPart(resolutionSequence[partIndex], stopOnFirstError)) return
partIndex++
}
if (step == stepCount) {
resolvedCall.setAnalyzedResults(subResolvedAtoms, diagnostics + getSystem().diagnostics)
}
}
// true if part was interrupted
private fun processPart(part: ResolutionPart, stopOnFirstError: Boolean, startWorkIndex: Int = 0): Boolean {
for (workIndex in startWorkIndex until (part.run { workCount() })) {
if (stopOnFirstError && !currentApplicability.isSuccess) return true
part.run { process(workIndex) }
step++
}
return false
}
val variableCandidateIfInvoke: KotlinResolutionCandidate?
get() = callComponents.statelessCallbacks.getVariableCandidateIfInvoke(resolvedCall.atom)
private val variableApplicability
get() = variableCandidateIfInvoke?.resultingApplicability ?: ResolutionCandidateApplicability.RESOLVED
override val isSuccessful: Boolean
get() {
processParts(stopOnFirstError = true)
return currentApplicability.isSuccess && variableApplicability.isSuccess
}
override val resultingApplicability: ResolutionCandidateApplicability
get() {
processParts(stopOnFirstError = false)
val systemApplicability = getResultApplicability(getSystem().diagnostics)
return maxOf(currentApplicability, systemApplicability, variableApplicability)
}
override fun toString(): String { override fun toString(): String {
val descriptor = DescriptorRenderer.COMPACT.render(candidateDescriptor) val descriptor = DescriptorRenderer.COMPACT.render(resolvedCall.candidateDescriptor)
val okOrFail = if (hasErrors) "FAIL" else "OK" val okOrFail = if (currentApplicability.isSuccess) "OK" else "FAIL"
val step = "$step/${resolutionSequence.size}" val step = "$step/$stepCount"
return "$okOrFail($step): $descriptor" return "$okOrFail($step): $descriptor"
} }
} }
class ErrorKotlinResolutionCandidate( class MutableResolvedCallAtom(
callComponents: KotlinCallComponents, override val atom: KotlinCall,
scopeTower: ImplicitScopeTower, override val candidateDescriptor: CallableDescriptor, // original candidate descriptor
kotlinCall: KotlinCall, override val explicitReceiverKind: ExplicitReceiverKind,
explicitReceiverKind: ExplicitReceiverKind, override val dispatchReceiverArgument: SimpleKotlinCallArgument?,
dispatchReceiverArgument: SimpleKotlinCallArgument?, override val extensionReceiverArgument: SimpleKotlinCallArgument?
extensionReceiver: SimpleKotlinCallArgument?, ) : ResolvedCallAtom() {
candidateDescriptor: CallableDescriptor override lateinit var typeArgumentMappingByOriginal: TypeArgumentsToParametersMapper.TypeArgumentsMapping
) : SimpleKotlinResolutionCandidate(callComponents, scopeTower, kotlinCall, explicitReceiverKind, dispatchReceiverArgument, override lateinit var argumentMappingByOriginal: Map<ValueParameterDescriptor, ResolvedCallArgument>
extensionReceiver, candidateDescriptor, null, listOf()) { override lateinit var substitutor: FreshVariableNewTypeSubstitutor
override val resolutionSequence: List<ResolutionPart> get() = emptyList() lateinit var argumentToCandidateParameter: Map<KotlinCallArgument, ValueParameterDescriptor>
init { override public fun setAnalyzedResults(subResolvedAtoms: List<ResolvedAtom>, diagnostics: Collection<KotlinCallDiagnostic>) {
typeArgumentMappingByOriginal = TypeArgumentsToParametersMapper.TypeArgumentsMapping.NoExplicitArguments super.setAnalyzedResults(subResolvedAtoms, diagnostics)
argumentMappingByOriginal = emptyMap()
descriptorWithFreshTypes = candidateDescriptor
} }
override fun toString(): String = "$atom, candidate = $candidateDescriptor"
} }
@@ -16,55 +16,6 @@
package org.jetbrains.kotlin.resolve.calls.model package org.jetbrains.kotlin.resolve.calls.model
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind
import org.jetbrains.kotlin.resolve.calls.tower.ResolutionCandidateApplicability
import org.jetbrains.kotlin.resolve.calls.tower.getResultApplicability
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValueWithSmartCastInfo
import org.jetbrains.kotlin.types.UnwrappedType
sealed class ResolvedKotlinCall {
abstract val resultingApplicability: ResolutionCandidateApplicability
class CompletedResolvedKotlinCall(
val completedCall: CompletedKotlinCall,
val allInnerCalls: Collection<CompletedKotlinCall>,
val lambdaArguments: List<PostponedLambdaArgument>
): ResolvedKotlinCall() {
override val resultingApplicability get() = completedCall.resultingApplicability
}
class OnlyResolvedKotlinCall(val candidate: KotlinResolutionCandidate) : ResolvedKotlinCall() {
override val resultingApplicability get() = candidate.resultingApplicability
}
}
sealed class CompletedKotlinCall {
abstract val resultingApplicability: ResolutionCandidateApplicability
class Simple(
val kotlinCall: KotlinCall,
val candidateDescriptor: CallableDescriptor,
val resultingDescriptor: CallableDescriptor,
val diagnostics: List<KotlinCallDiagnostic>,
val explicitReceiverKind: ExplicitReceiverKind,
val dispatchReceiver: ReceiverValueWithSmartCastInfo?,
val extensionReceiver: ReceiverValueWithSmartCastInfo?,
val typeArguments: List<UnwrappedType>,
val argumentMappingByOriginal: Map<ValueParameterDescriptor, ResolvedCallArgument>
): CompletedKotlinCall() {
override val resultingApplicability = getResultApplicability(diagnostics)
}
class VariableAsFunction(
val kotlinCall: KotlinCall,
val variableCall: Simple,
val invokeCall: Simple
): CompletedKotlinCall() {
override val resultingApplicability get() = maxOf(variableCall.resultingApplicability, invokeCall.resultingApplicability)
}
}
sealed class ResolvedCallArgument { sealed class ResolvedCallArgument {
abstract val arguments: List<KotlinCallArgument> abstract val arguments: List<KotlinCallArgument>
@@ -60,7 +60,7 @@ interface CandidateWithBoundDispatchReceiver {
val dispatchReceiver: ReceiverValueWithSmartCastInfo? val dispatchReceiver: ReceiverValueWithSmartCastInfo?
} }
fun getResultApplicability(diagnostics: List<KotlinCallDiagnostic>) = diagnostics.maxBy { it.candidateApplicability }?.candidateApplicability fun getResultApplicability(diagnostics: Collection<KotlinCallDiagnostic>) = diagnostics.maxBy { it.candidateApplicability }?.candidateApplicability
?: RESOLVED ?: RESOLVED
enum class ResolutionCandidateApplicability { enum class ResolutionCandidateApplicability {
@@ -41,4 +41,9 @@ internal class CandidateWithBoundDispatchReceiverImpl(
override val dispatchReceiver: ReceiverValueWithSmartCastInfo?, override val dispatchReceiver: ReceiverValueWithSmartCastInfo?,
override val descriptor: CallableDescriptor, override val descriptor: CallableDescriptor,
override val diagnostics: List<ResolutionDiagnostic> override val diagnostics: List<ResolutionDiagnostic>
) : CandidateWithBoundDispatchReceiver ) : CandidateWithBoundDispatchReceiver
fun <C : Candidate> C.forceResolution(): C {
resultingApplicability
return this
}