[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.FqNameUnsafe;
|
||||
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.model.CallResolutionResult;
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
|
||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo;
|
||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValue;
|
||||
@@ -122,7 +122,7 @@ public interface BindingContext {
|
||||
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<Call, TailRecursionKind> TAIL_RECURSION_CALL = Slices.createSimpleSlice();
|
||||
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.model.MutableResolvedCall;
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
|
||||
import org.jetbrains.kotlin.resolve.calls.tower.StubOnlyResolvedCall;
|
||||
import org.jetbrains.kotlin.resolve.calls.tower.StubOnlyVariableAsFunctionCall;
|
||||
import org.jetbrains.kotlin.resolve.calls.tower.KotlinToResolvedCallTransformerKt;
|
||||
import org.jetbrains.kotlin.types.KotlinType;
|
||||
|
||||
import java.util.Collection;
|
||||
@@ -61,7 +60,7 @@ public class OverloadResolutionResultsUtil {
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (resultingCall instanceof StubOnlyResolvedCall || resultingCall instanceof StubOnlyVariableAsFunctionCall) {
|
||||
if (KotlinToResolvedCallTransformerKt.isNewNotCompleted(resultingCall)) {
|
||||
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.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.annotations.Annotations
|
||||
import org.jetbrains.kotlin.psi.KtExpression
|
||||
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.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.components.KotlinResolutionCallbacks
|
||||
import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext
|
||||
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.tasks.ExplicitReceiverKind
|
||||
import org.jetbrains.kotlin.resolve.calls.tasks.TracingStrategyImpl
|
||||
import org.jetbrains.kotlin.resolve.calls.util.CallMaker
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
|
||||
import org.jetbrains.kotlin.types.*
|
||||
import org.jetbrains.kotlin.types.expressions.DoubleColonExpressionResolver
|
||||
import org.jetbrains.kotlin.types.TypeApproximator
|
||||
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.KotlinTypeInfo
|
||||
import org.jetbrains.kotlin.types.typeUtil.asTypeProjection
|
||||
import org.jetbrains.kotlin.types.typeUtil.isUnit
|
||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||
|
||||
@@ -51,10 +49,9 @@ class KotlinResolutionCallbacksImpl(
|
||||
val topLevelCallContext: BasicCallResolutionContext,
|
||||
val expressionTypingServices: ExpressionTypingServices,
|
||||
val typeApproximator: TypeApproximator,
|
||||
val kotlinToResolvedCallTransformer: KotlinToResolvedCallTransformer,
|
||||
val argumentTypeResolver: ArgumentTypeResolver,
|
||||
val doubleColonExpressionResolver: DoubleColonExpressionResolver,
|
||||
val languageVersionSettings: LanguageVersionSettings
|
||||
val languageVersionSettings: LanguageVersionSettings,
|
||||
val kotlinToResolvedCallTransformer: KotlinToResolvedCallTransformer
|
||||
): KotlinResolutionCallbacks {
|
||||
val trace: BindingTrace = topLevelCallContext.trace
|
||||
|
||||
@@ -143,72 +140,8 @@ class KotlinResolutionCallbacksImpl(
|
||||
return KtPsiUtil.deparenthesize(lastExpression)
|
||||
}
|
||||
|
||||
override fun bindStubResolvedCallForCandidate(candidate: KotlinResolutionCandidate) {
|
||||
override fun bindStubResolvedCallForCandidate(candidate: ResolvedCallAtom) {
|
||||
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.SimpleKotlinCallArgument
|
||||
import org.jetbrains.kotlin.resolve.isHiddenInResolution
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
|
||||
class KotlinResolutionStatelessCallbacksImpl(
|
||||
private val languageVersionSettings: LanguageVersionSettings
|
||||
@@ -54,4 +55,7 @@ class KotlinResolutionStatelessCallbacksImpl(
|
||||
|
||||
override fun getScopeTowerForCallableReferenceArgument(argument: CallableReferenceKotlinCallArgument): ImplicitScopeTower =
|
||||
(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
|
||||
|
||||
import org.jetbrains.kotlin.builtins.replaceReturnType
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.impl.FunctionDescriptorImpl
|
||||
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
||||
import org.jetbrains.kotlin.diagnostics.Errors
|
||||
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.checkers.CallChecker
|
||||
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.context.BasicCallResolutionContext
|
||||
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.resolvedCallUtil.makeNullableTypeIfSafeReceiver
|
||||
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.constants.evaluate.ConstantExpressionEvaluator
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
|
||||
import org.jetbrains.kotlin.types.ErrorUtils
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.TypeUtils
|
||||
import org.jetbrains.kotlin.types.UnwrappedType
|
||||
import org.jetbrains.kotlin.types.*
|
||||
import org.jetbrains.kotlin.types.checker.NewCapturedType
|
||||
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.typeUtil.contains
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.cast
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
import java.util.*
|
||||
|
||||
|
||||
@@ -56,91 +63,71 @@ class KotlinToResolvedCallTransformer(
|
||||
private val languageFeatureSettings: LanguageVersionSettings,
|
||||
private val dataFlowAnalyzer: DataFlowAnalyzer,
|
||||
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(
|
||||
baseResolvedCall: ResolvedKotlinCall,
|
||||
context: BasicCallResolutionContext,
|
||||
trace: BindingTrace? // if trace is not null then all information will be reported to this trace
|
||||
baseResolvedCall: CallResolutionResult,
|
||||
context: BasicCallResolutionContext
|
||||
): ResolvedCall<D> {
|
||||
if (baseResolvedCall is ResolvedKotlinCall.CompletedResolvedKotlinCall) {
|
||||
val allResolvedCalls = baseResolvedCall.allInnerCalls.mapTo(ArrayList<ResolvedCall<*>>()) { transformAndReportCompletedCall<CallableDescriptor>(it, context, trace) }
|
||||
val result = transformAndReportCompletedCall<D>(baseResolvedCall.completedCall, context, trace)
|
||||
allResolvedCalls.add(result)
|
||||
val candidate = baseResolvedCall.resultCallAtom!!
|
||||
when (baseResolvedCall.type) {
|
||||
CallResolutionResult.Type.PARTIAL -> {
|
||||
context.trace.record(BindingContext.ONLY_RESOLVED_CALL, candidate.atom.psiKotlinCall.psiCall, baseResolvedCall)
|
||||
|
||||
if (trace != null) {
|
||||
// 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<*>)
|
||||
}
|
||||
return createStubResolvedCallAndWriteItToTrace(candidate, context.trace)
|
||||
}
|
||||
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> {
|
||||
val result = when (candidate) {
|
||||
is VariableAsFunctionKotlinResolutionCandidate -> {
|
||||
val variableStub = StubOnlyResolvedCall<VariableDescriptor>(candidate.resolvedVariable)
|
||||
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
|
||||
fun <D : CallableDescriptor> createStubResolvedCallAndWriteItToTrace(candidate: ResolvedCallAtom, trace: BindingTrace): ResolvedCall<D> {
|
||||
val result = onlyTransform<D>(candidate)
|
||||
val psiKotlinCall = candidate.atom.psiKotlinCall
|
||||
val tracing = psiKotlinCall.safeAs<PSIKotlinCallForInvoke>()?.baseCall?.tracingStrategy ?: psiKotlinCall.tracingStrategy
|
||||
|
||||
tracing.bindReference(trace, result)
|
||||
tracing.bindResolvedCall(trace, result)
|
||||
}
|
||||
tracing.bindReference(trace, result)
|
||||
tracing.bindResolvedCall(trace, result)
|
||||
return result
|
||||
}
|
||||
|
||||
|
||||
private fun <D : CallableDescriptor> transformAndReportCompletedCall(
|
||||
completedCall: CompletedKotlinCall,
|
||||
context: BasicCallResolutionContext,
|
||||
trace: BindingTrace?
|
||||
fun <D : CallableDescriptor> transformToResolvedCall(
|
||||
completedCallAtom: ResolvedCallAtom,
|
||||
completed: Boolean,
|
||||
resultSubstitutor: NewTypeSubstitutor = FreshVariableNewTypeSubstitutor.Empty
|
||||
): ResolvedCall<D> {
|
||||
fun <C> C.runIfTraceNotNull(action: (BasicCallResolutionContext, BindingTrace, C) -> Unit): C {
|
||||
if (trace != null) action(context, trace, this)
|
||||
return this
|
||||
val psiKotlinCall = completedCallAtom.atom.psiKotlinCall
|
||||
return if (psiKotlinCall is PSIKotlinCallForInvoke) {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
NewVariableAsFunctionResolvedCallImpl(
|
||||
NewResolvedCallImpl(psiKotlinCall.variableCall.resolvedCall, completed, resultSubstitutor),
|
||||
NewResolvedCallImpl(completedCallAtom, completed, resultSubstitutor)
|
||||
) as ResolvedCall<D>
|
||||
}
|
||||
|
||||
return when (completedCall) {
|
||||
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>)
|
||||
}
|
||||
else {
|
||||
NewResolvedCallImpl(completedCallAtom, completed, resultSubstitutor)
|
||||
}
|
||||
}
|
||||
|
||||
private fun runCallCheckers(resolvedCall: ResolvedCall<*>, callCheckerContext: CallCheckerContext) {
|
||||
fun runCallCheckers(resolvedCall: ResolvedCall<*>, callCheckerContext: CallCheckerContext) {
|
||||
val calleeExpression = if (resolvedCall is VariableAsFunctionResolvedCall)
|
||||
resolvedCall.variableCall.call.calleeExpression
|
||||
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
|
||||
private fun runArgumentsChecks(
|
||||
fun runArgumentsChecks(
|
||||
context: BasicCallResolutionContext,
|
||||
trace: BindingTrace,
|
||||
resolvedCall: NewResolvedCallImpl<*>
|
||||
@@ -320,19 +258,24 @@ class KotlinToResolvedCallTransformer(
|
||||
return expressionType != null && TypeUtils.isNullableType(expressionType)
|
||||
}
|
||||
|
||||
private fun bindResolvedCall(context: BasicCallResolutionContext, trace: BindingTrace, simpleResolvedCall: NewResolvedCallImpl<*>) {
|
||||
reportCallDiagnostic(context, trace, simpleResolvedCall.completedCall)
|
||||
val tracing = simpleResolvedCall.completedCall.kotlinCall.psiKotlinCall.tracingStrategy
|
||||
internal fun bindAndReport(context: BasicCallResolutionContext, trace: BindingTrace, resolvedCall: ResolvedCall<*>) {
|
||||
resolvedCall.safeAs<NewResolvedCallImpl<*>>()?.let { bindAndReport(context, trace, it) }
|
||||
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.bindResolvedCall(trace, simpleResolvedCall)
|
||||
}
|
||||
|
||||
private fun bindResolvedCall(context: BasicCallResolutionContext, trace: BindingTrace, variableAsFunction: NewVariableAsFunctionResolvedCallImpl) {
|
||||
reportCallDiagnostic(context, trace, variableAsFunction.variableCall.completedCall)
|
||||
reportCallDiagnostic(context, trace, variableAsFunction.functionCall.completedCall)
|
||||
private fun bindAndReport(context: BasicCallResolutionContext, trace: BindingTrace, variableAsFunction: NewVariableAsFunctionResolvedCallImpl) {
|
||||
reportCallDiagnostic(context, trace, variableAsFunction.variableCall.resolvedCallAtom, variableAsFunction.variableCall.resultingDescriptor)
|
||||
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.bindResolvedCall(trace, variableAsFunction)
|
||||
variableAsFunction.functionCall.kotlinCall.psiKotlinCall.tracingStrategy.bindReference(trace, variableAsFunction.functionCall)
|
||||
@@ -341,13 +284,17 @@ class KotlinToResolvedCallTransformer(
|
||||
private fun reportCallDiagnostic(
|
||||
context: BasicCallResolutionContext,
|
||||
trace: BindingTrace,
|
||||
completedCall: CompletedKotlinCall.Simple
|
||||
completedCallAtom: ResolvedCallAtom,
|
||||
resultingDescriptor: CallableDescriptor
|
||||
) {
|
||||
val trackingTrace = TrackingBindingTrace(trace)
|
||||
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
|
||||
diagnostic.report(diagnosticReporter)
|
||||
|
||||
@@ -460,24 +407,46 @@ sealed class NewAbstractResolvedCall<D : CallableDescriptor>(): ResolvedCall<D>
|
||||
}
|
||||
|
||||
class NewResolvedCallImpl<D : CallableDescriptor>(
|
||||
val completedCall: CompletedKotlinCall.Simple
|
||||
val resolvedCallAtom: ResolvedCallAtom,
|
||||
val completed: Boolean,
|
||||
substitutor: NewTypeSubstitutor
|
||||
): 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>
|
||||
get() = completedCall.argumentMappingByOriginal
|
||||
get() = resolvedCallAtom.argumentMappingByOriginal
|
||||
|
||||
override fun getCandidateDescriptor(): D = completedCall.candidateDescriptor as D
|
||||
override fun getResultingDescriptor(): D = completedCall.resultingDescriptor as D
|
||||
override fun getExtensionReceiver(): ReceiverValue? = completedCall.extensionReceiver?.receiverValue
|
||||
override fun getDispatchReceiver(): ReceiverValue? = completedCall.dispatchReceiver?.receiverValue
|
||||
override fun getExplicitReceiverKind(): ExplicitReceiverKind = completedCall.explicitReceiverKind
|
||||
override fun getCandidateDescriptor(): D = resolvedCallAtom.candidateDescriptor as D
|
||||
override fun getResultingDescriptor(): D = resultingDescriptor as D
|
||||
override fun getExtensionReceiver(): ReceiverValue? = resolvedCallAtom.extensionReceiverArgument?.receiver?.receiverValue
|
||||
override fun getDispatchReceiver(): ReceiverValue? = resolvedCallAtom.dispatchReceiverArgument?.receiver?.receiverValue
|
||||
override fun getExplicitReceiverKind(): ExplicitReceiverKind = resolvedCallAtom.explicitReceiverKind
|
||||
|
||||
override fun getTypeArguments(): Map<TypeParameterDescriptor, KotlinType> {
|
||||
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
|
||||
@@ -490,30 +459,18 @@ fun ResolutionCandidateApplicability.toResolutionStatus(): ResolutionStatus = wh
|
||||
}
|
||||
|
||||
class NewVariableAsFunctionResolvedCallImpl(
|
||||
val completedCall: CompletedKotlinCall.VariableAsFunction,
|
||||
override val variableCall: NewResolvedCallImpl<VariableDescriptor>,
|
||||
override val functionCall: NewResolvedCallImpl<FunctionDescriptor>
|
||||
): VariableAsFunctionResolvedCall, ResolvedCall<FunctionDescriptor> by functionCall
|
||||
|
||||
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
|
||||
): VariableAsFunctionResolvedCall, ResolvedCall<FunctionDescriptor> by functionCall {
|
||||
val baseCall get() = functionCall.resolvedCallAtom.atom.psiKotlinCall.cast<PSIKotlinCallForInvoke>().baseCall
|
||||
}
|
||||
|
||||
class StubOnlyVariableAsFunctionCall(
|
||||
override val variableCall: StubOnlyResolvedCall<VariableDescriptor>,
|
||||
override val functionCall: StubOnlyResolvedCall<FunctionDescriptor>
|
||||
) : VariableAsFunctionResolvedCall, ResolvedCall<FunctionDescriptor> by functionCall
|
||||
fun ResolvedCall<*>.isNewNotCompleted(): Boolean {
|
||||
if (this is NewVariableAsFunctionResolvedCallImpl) {
|
||||
return !functionCall.completed
|
||||
}
|
||||
if (this is NewResolvedCallImpl<*>) {
|
||||
return !completed
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -147,7 +147,7 @@ class SubKotlinCallArgumentImpl(
|
||||
override val dataFlowInfoBeforeThisArgument: DataFlowInfo,
|
||||
override val dataFlowInfoAfterThisArgument: DataFlowInfo,
|
||||
override val receiver: ReceiverValueWithSmartCastInfo,
|
||||
override val resolvedCall: ResolvedKotlinCall.OnlyResolvedKotlinCall
|
||||
override val callResult: CallResolutionResult
|
||||
): SimplePSIKotlinCallArgument(), SubKotlinCallArgument {
|
||||
override val isSpread: Boolean get() = valueArgument.getSpreadElement() != null
|
||||
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
|
||||
val baseType = typeInfoForArgument.type?.unwrap() ?:
|
||||
onlyResolvedCall?.candidate?.lastCall?.descriptorWithFreshTypes?.returnType?.unwrap() ?:
|
||||
onlyResolvedCall?.resultCallAtom?.freshReturnType ?:
|
||||
return null
|
||||
|
||||
// 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 {
|
||||
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.model.*
|
||||
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.DataFlowValueFactory
|
||||
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.types.*
|
||||
import org.jetbrains.kotlin.types.expressions.*
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult
|
||||
import java.util.*
|
||||
|
||||
@@ -93,7 +95,7 @@ class PSICallResolver(
|
||||
var result = kotlinCallResolver.resolveCall(scopeTower, resolutionCallbacks, kotlinCall, expectedType, factoryProviderForInvoke)
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
@@ -117,12 +119,12 @@ class PSICallResolver(
|
||||
val resolutionCallbacks = createResolutionCallbacks(context)
|
||||
|
||||
val givenCandidates = resolutionCandidates.map {
|
||||
GivenCandidate(scopeTower, it.descriptor as FunctionDescriptor,
|
||||
GivenCandidate(it.descriptor as FunctionDescriptor,
|
||||
it.dispatchReceiver?.let { context.transformToReceiverWithSmartCastInfo(it) },
|
||||
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)
|
||||
|
||||
}
|
||||
@@ -135,7 +137,7 @@ class PSICallResolver(
|
||||
scopeTower: ImplicitScopeTower,
|
||||
resolutionCallbacks: KotlinResolutionCallbacksImpl,
|
||||
expectedType: UnwrappedType?
|
||||
): Collection<ResolvedKotlinCall> {
|
||||
): CallResolutionResult {
|
||||
val deprecatedName = OperatorConventions.REM_TO_MOD_OPERATION_NAMES[remOperatorName]!!
|
||||
val callWithDeprecatedName = toKotlinCall(context, resolutionKind.kotlinCallKind, context.call, deprecatedName, tracingStrategy)
|
||||
val refinedProviderForInvokeFactory = FactoryProviderForInvoke(context, scopeTower, callWithDeprecatedName)
|
||||
@@ -148,8 +150,8 @@ class PSICallResolver(
|
||||
}
|
||||
|
||||
private fun createResolutionCallbacks(context: BasicCallResolutionContext) =
|
||||
KotlinResolutionCallbacksImpl(context, expressionTypingServices, typeApproximator, kotlinToResolvedCallTransformer,
|
||||
argumentTypeResolver, doubleColonExpressionResolver, languageVersionSettings)
|
||||
KotlinResolutionCallbacksImpl(context, expressionTypingServices, typeApproximator,
|
||||
argumentTypeResolver, languageVersionSettings, kotlinToResolvedCallTransformer)
|
||||
|
||||
private fun calculateExpectedType(context: BasicCallResolutionContext): UnwrappedType? {
|
||||
val expectedType = context.expectedType.unwrap()
|
||||
@@ -167,60 +169,67 @@ class PSICallResolver(
|
||||
|
||||
private fun <D : CallableDescriptor> convertToOverloadResolutionResults(
|
||||
context: BasicCallResolutionContext,
|
||||
result: Collection<ResolvedKotlinCall>,
|
||||
result: CallResolutionResult,
|
||||
tracingStrategy: TracingStrategy
|
||||
): OverloadResolutionResults<D> {
|
||||
val trace = context.trace
|
||||
when (result.size) {
|
||||
0 -> {
|
||||
tracingStrategy.unresolvedReference(trace)
|
||||
return OverloadResolutionResultsImpl.nameNotFound()
|
||||
|
||||
result.diagnostics.firstIsInstanceOrNull<NoneCandidatesCallDiagnostic>()?.let {
|
||||
tracingStrategy.unresolvedReference(trace)
|
||||
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 -> {
|
||||
val singleCandidate = result.single()
|
||||
|
||||
val isInapplicableReceiver = singleCandidate.resultingApplicability == ResolutionCandidateApplicability.INAPPLICABLE_WRONG_RECEIVER
|
||||
|
||||
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 {
|
||||
tracingStrategy.recordAmbiguity(trace, resolvedCalls)
|
||||
if (resolvedCalls.first().status == ResolutionStatus.INCOMPLETE_TYPE_INFERENCE) {
|
||||
tracingStrategy.cannotCompleteResolve(trace, resolvedCalls)
|
||||
}
|
||||
else {
|
||||
tracingStrategy.recordAmbiguity(trace, resolvedCalls)
|
||||
if (resolvedCalls.first().status == ResolutionStatus.INCOMPLETE_TYPE_INFERENCE) {
|
||||
tracingStrategy.cannotCompleteResolve(trace, resolvedCalls)
|
||||
}
|
||||
else {
|
||||
tracingStrategy.ambiguity(trace, resolvedCalls)
|
||||
}
|
||||
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 {
|
||||
it is ResolvedKotlinCall.CompletedResolvedKotlinCall &&
|
||||
!it.completedCall.resultingApplicability.isSuccess
|
||||
!it.resultingApplicability.isSuccess
|
||||
}
|
||||
|
||||
private fun Collection<ResolvedKotlinCall>.areAllCompletedAndInapplicable() =
|
||||
all {
|
||||
val applicability = it.resultingApplicability
|
||||
applicability == ResolutionCandidateApplicability.INAPPLICABLE ||
|
||||
applicability == ResolutionCandidateApplicability.INAPPLICABLE_WRONG_RECEIVER ||
|
||||
applicability == ResolutionCandidateApplicability.HIDDEN
|
||||
}
|
||||
private fun CallResolutionResult.areAllInapplicable(): Boolean {
|
||||
val candidates = diagnostics.firstIsInstanceOrNull<ManyCandidatesCallDiagnostic>()?.candidates?.map { it.resolvedCall }
|
||||
?: listOfNotNull(resultCallAtom)
|
||||
|
||||
return candidates.all {
|
||||
val applicability = getResultApplicability(it.diagnostics)
|
||||
applicability == ResolutionCandidateApplicability.INAPPLICABLE ||
|
||||
applicability == ResolutionCandidateApplicability.INAPPLICABLE_WRONG_RECEIVER ||
|
||||
applicability == ResolutionCandidateApplicability.HIDDEN
|
||||
}
|
||||
}
|
||||
|
||||
// true if we found something
|
||||
private fun reportAdditionalDiagnosticIfNoCandidates(
|
||||
@@ -285,18 +294,9 @@ class PSICallResolver(
|
||||
override fun transformCandidate(
|
||||
variable: KotlinResolutionCandidate,
|
||||
invoke: KotlinResolutionCandidate
|
||||
): VariableAsFunctionKotlinResolutionCandidate {
|
||||
assert(variable is SimpleKotlinResolutionCandidate) {
|
||||
"VariableAsFunction variable is not allowed here: $variable"
|
||||
}
|
||||
assert(invoke is SimpleKotlinResolutionCandidate) {
|
||||
"VariableAsFunction candidate is not allowed here: $invoke"
|
||||
}
|
||||
) = invoke
|
||||
|
||||
return VariableAsFunctionKotlinResolutionCandidate(kotlinCall, variable as SimpleKotlinResolutionCandidate, invoke as SimpleKotlinResolutionCandidate)
|
||||
}
|
||||
|
||||
override fun factoryForVariable(stripExplicitReceiver: Boolean): CandidateFactory<SimpleKotlinResolutionCandidate> {
|
||||
override fun factoryForVariable(stripExplicitReceiver: Boolean): CandidateFactory<KotlinResolutionCandidate> {
|
||||
val explicitReceiver = if (stripExplicitReceiver) null else kotlinCall.explicitReceiver
|
||||
val variableCall = PSIKotlinCallForVariable(kotlinCall, explicitReceiver, kotlinCall.name)
|
||||
return SimpleCandidateFactory(callComponents, scopeTower, variableCall)
|
||||
@@ -304,58 +304,59 @@ class PSICallResolver(
|
||||
|
||||
override fun factoryForInvoke(variable: KotlinResolutionCandidate, useExplicitReceiver: Boolean):
|
||||
Pair<ReceiverValueWithSmartCastInfo, CandidateFactory<KotlinResolutionCandidate>>? {
|
||||
assert(variable is SimpleKotlinResolutionCandidate) {
|
||||
"VariableAsFunction variable is not allowed here: $variable"
|
||||
}
|
||||
if (isRecursiveVariableResolution(variable as SimpleKotlinResolutionCandidate)) return null
|
||||
if (isRecursiveVariableResolution(variable)) return null
|
||||
|
||||
assert(variable.isSuccessful) {
|
||||
"Variable call should be successful: $variable " +
|
||||
"Descriptor: ${variable.descriptorWithFreshTypes}"
|
||||
"Descriptor: ${variable.resolvedCall.candidateDescriptor}"
|
||||
}
|
||||
val variableCallArgument = createReceiverCallArgument(variable)
|
||||
|
||||
val explicitReceiver = kotlinCall.explicitReceiver
|
||||
val callForInvoke = if (useExplicitReceiver && explicitReceiver is SimpleKotlinCallArgument) {
|
||||
PSIKotlinCallForInvoke(kotlinCall, explicitReceiver, variableCallArgument)
|
||||
PSIKotlinCallForInvoke(kotlinCall, variable, explicitReceiver, variableCallArgument)
|
||||
}
|
||||
else {
|
||||
PSIKotlinCallForInvoke(kotlinCall, variableCallArgument, null)
|
||||
PSIKotlinCallForInvoke(kotlinCall, variable, variableCallArgument, null)
|
||||
}
|
||||
|
||||
return variableCallArgument.receiver to SimpleCandidateFactory(callComponents, scopeTower, callForInvoke)
|
||||
}
|
||||
|
||||
// todo: create special check that there is no invoke on variable
|
||||
private fun isRecursiveVariableResolution(variable: SimpleKotlinResolutionCandidate): Boolean {
|
||||
val variableType = variable.candidateDescriptor.returnType
|
||||
private fun isRecursiveVariableResolution(variable: KotlinResolutionCandidate): Boolean {
|
||||
val variableType = variable.resolvedCall.candidateDescriptor.returnType
|
||||
return variableType is DeferredType && variableType.isComputing
|
||||
}
|
||||
|
||||
// todo: review
|
||||
private fun createReceiverCallArgument(variable: SimpleKotlinResolutionCandidate): SimpleKotlinCallArgument {
|
||||
private fun createReceiverCallArgument(variable: KotlinResolutionCandidate): SimpleKotlinCallArgument {
|
||||
variable.forceResolution()
|
||||
val variableReceiver = createReceiverValueWithSmartCastInfo(variable)
|
||||
if (variableReceiver.possibleTypes.isNotEmpty()) {
|
||||
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),
|
||||
psiKotlinCall.resultDataFlowInfo, psiKotlinCall.resultDataFlowInfo, variableReceiver,
|
||||
ResolvedKotlinCall.OnlyResolvedKotlinCall(variable))
|
||||
variableResult)
|
||||
}
|
||||
|
||||
// todo: decrease hacks count
|
||||
private fun createReceiverValueWithSmartCastInfo(variable: SimpleKotlinResolutionCandidate): ReceiverValueWithSmartCastInfo {
|
||||
val callForVariable = variable.kotlinCall as PSIKotlinCallForVariable
|
||||
private fun createReceiverValueWithSmartCastInfo(variable: KotlinResolutionCandidate): ReceiverValueWithSmartCastInfo {
|
||||
val callForVariable = variable.resolvedCall.atom as PSIKotlinCallForVariable
|
||||
val calleeExpression = callForVariable.baseCall.psiCall.calleeExpression as? KtReferenceExpression ?:
|
||||
error("Unexpected call : ${callForVariable.baseCall.psiCall}")
|
||||
|
||||
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)
|
||||
|
||||
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)
|
||||
return ReceiverValueWithSmartCastInfo(variableReceiver, context.dataFlowInfo.getCollectedTypes(dataFlowValue), dataFlowValue.isStable)
|
||||
}
|
||||
|
||||
@@ -79,6 +79,7 @@ class PSIKotlinCallForVariable(
|
||||
|
||||
class PSIKotlinCallForInvoke(
|
||||
val baseCall: PSIKotlinCallImpl,
|
||||
val variableCall: KotlinResolutionCandidate,
|
||||
override val explicitReceiver: SimpleKotlinCallArgument,
|
||||
override val dispatchReceiverForInvokeExtension: SimpleKotlinCallArgument?
|
||||
) : 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)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user