[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:
@@ -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);
|
||||||
|
|||||||
+2
-3
@@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+10
-77
@@ -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)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
+4
@@ -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
|
||||||
}
|
}
|
||||||
+123
-166
@@ -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() {
|
||||||
|
|||||||
+201
@@ -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)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+28
-23
@@ -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)
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+4
-2
@@ -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
|
||||||
|
|||||||
+4
-1
@@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
+37
-27
@@ -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,
|
||||||
|
|||||||
+2
-7
@@ -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)
|
|
||||||
}
|
}
|
||||||
+48
-118
@@ -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)) {
|
||||||
|
|||||||
+9
-12
@@ -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] })
|
||||||
)
|
)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+45
-45
@@ -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)
|
||||||
}
|
}
|
||||||
|
|||||||
+21
-14
@@ -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())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+145
-119
@@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+33
-26
@@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+19
-11
@@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+12
@@ -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() }
|
||||||
|
|||||||
+3
-1
@@ -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
|
||||||
}
|
}
|
||||||
+57
-20
@@ -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)
|
||||||
|
|
||||||
+4
@@ -150,4 +150,8 @@ class FreshVariableNewTypeSubstitutor(val freshVariables: List<TypeVariableFromC
|
|||||||
|
|
||||||
return typeVariable.defaultType
|
return typeVariable.defaultType
|
||||||
}
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
val Empty = FreshVariableNewTypeSubstitutor(emptyList())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+3
-2
@@ -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 {
|
||||||
|
|||||||
+4
-4
@@ -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)
|
||||||
|
|||||||
+4
-2
@@ -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)
|
||||||
|
|||||||
+10
-10
@@ -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
|
|
||||||
|
|
||||||
}
|
}
|
||||||
+2
-2
@@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
-4
@@ -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()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
-4
@@ -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()
|
|
||||||
}
|
}
|
||||||
+11
-89
@@ -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) {
|
||||||
|
|||||||
+7
-4
@@ -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 {
|
||||||
|
|||||||
+16
@@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
+82
-21
@@ -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?
|
||||||
|
|||||||
-96
@@ -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())
|
||||||
|
}
|
||||||
+131
-95
@@ -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"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
-49
@@ -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>
|
||||||
|
|||||||
+1
-1
@@ -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
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user