[NI] Introduced ResolutionAtom's

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

Future improvements:
  - optimize constraint system usage inside ResolutionCandidate
  - improve constraint system API
  - improve diagnostic handlers
This commit is contained in:
Stanislav Erokhin
2017-08-15 19:07:09 +03:00
parent 76012f6603
commit cb1270836c
44 changed files with 1367 additions and 1167 deletions
@@ -29,8 +29,8 @@ import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor;
import org.jetbrains.kotlin.name.FqName;
import org.jetbrains.kotlin.name.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);
@@ -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;
}
}
@@ -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)
}
}
@@ -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
}
@@ -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() {
@@ -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)
}
}