FIR: Support postponed callable references resolution
^KT-32725 In Progress
This commit is contained in:
@@ -18,14 +18,12 @@ import org.jetbrains.kotlin.fir.references.impl.FirResolvedCallableReferenceImpl
|
||||
import org.jetbrains.kotlin.fir.references.impl.FirSimpleNamedReference
|
||||
import org.jetbrains.kotlin.fir.resolve.*
|
||||
import org.jetbrains.kotlin.fir.resolve.calls.*
|
||||
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
|
||||
import org.jetbrains.kotlin.fir.resolve.transformers.StoreNameReference
|
||||
import org.jetbrains.kotlin.fir.resolve.transformers.StoreReceiver
|
||||
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.FirExpressionsResolveTransformer
|
||||
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.resultType
|
||||
import org.jetbrains.kotlin.fir.resolve.transformers.phasedFir
|
||||
import org.jetbrains.kotlin.fir.resolve.typeForQualifier
|
||||
import org.jetbrains.kotlin.fir.resolve.typeFromCallee
|
||||
import org.jetbrains.kotlin.fir.resolve.transformers.*
|
||||
import org.jetbrains.kotlin.fir.scopes.FirScope
|
||||
import org.jetbrains.kotlin.fir.scopes.impl.FirLocalScope
|
||||
import org.jetbrains.kotlin.fir.symbols.AbstractFirBasedSymbol
|
||||
@@ -226,7 +224,8 @@ class FirCallResolver(
|
||||
): Boolean {
|
||||
val callableReferenceAccess = resolvedCallableReferenceAtom.atom
|
||||
val lhs = resolvedCallableReferenceAtom.lhs
|
||||
val expectedType = resolvedCallableReferenceAtom.expectedType ?: return false
|
||||
val coneSubstitutor = constraintSystemBuilder.buildCurrentSubstitutor() as ConeSubstitutor
|
||||
val expectedType = resolvedCallableReferenceAtom.expectedType?.let(coneSubstitutor::substituteOrSelf) ?: return false
|
||||
|
||||
val result = CandidateCollector(this, resolutionStageRunner)
|
||||
val consumer =
|
||||
@@ -250,7 +249,8 @@ class FirCallResolver(
|
||||
return false
|
||||
}
|
||||
reducedCandidates.size > 1 -> {
|
||||
// TODO: add postponed atom
|
||||
if (resolvedCallableReferenceAtom.postponed) return false
|
||||
resolvedCallableReferenceAtom.postponed = true
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
+62
-2
@@ -11,8 +11,10 @@ import org.jetbrains.kotlin.fir.resolve.DoubleColonLHS
|
||||
import org.jetbrains.kotlin.fir.resolve.constructType
|
||||
import org.jetbrains.kotlin.fir.resolve.firSymbolProvider
|
||||
import org.jetbrains.kotlin.fir.symbols.StandardClassIds
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.ConeClassLikeLookupTagImpl
|
||||
import org.jetbrains.kotlin.fir.symbols.invoke
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
import org.jetbrains.kotlin.fir.types.impl.ConeClassTypeImpl
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilder
|
||||
import org.jetbrains.kotlin.resolve.calls.model.PostponedResolvedAtomMarker
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
@@ -211,6 +213,7 @@ abstract class ResolvedCallableReferenceAtom(
|
||||
val lhs: DoubleColonLHS?
|
||||
) : PostponedResolvedAtomMarker {
|
||||
override var analyzed: Boolean = false
|
||||
var postponed: Boolean = false
|
||||
|
||||
var resultingCandidate: Pair<Candidate, CandidateApplicability>? = null
|
||||
}
|
||||
@@ -221,6 +224,63 @@ class EagerCallableReferenceAtom(
|
||||
lhs: DoubleColonLHS?
|
||||
) : ResolvedCallableReferenceAtom(atom, expectedType, lhs) {
|
||||
|
||||
override val inputTypes: Collection<ConeKotlinType> get() = emptyList()
|
||||
override val outputType: ConeKotlinType? get() = null
|
||||
override val inputTypes: Collection<ConeKotlinType>
|
||||
get() {
|
||||
if (!postponed) return emptyList()
|
||||
return extractInputOutputTypesFromCallableReferenceExpectedType(expectedType)?.inputTypes ?: listOfNotNull(expectedType)
|
||||
}
|
||||
override val outputType: ConeKotlinType?
|
||||
get() {
|
||||
if (!postponed) return null
|
||||
return extractInputOutputTypesFromCallableReferenceExpectedType(expectedType)?.outputType
|
||||
}
|
||||
}
|
||||
|
||||
private data class InputOutputTypes(val inputTypes: List<ConeKotlinType>, val outputType: ConeKotlinType)
|
||||
|
||||
private fun extractInputOutputTypesFromCallableReferenceExpectedType(expectedType: ConeKotlinType?): InputOutputTypes? {
|
||||
if (expectedType == null) return null
|
||||
|
||||
return when {
|
||||
expectedType.isBuiltinFunctionalType || expectedType.isSuspendFunctionType ->
|
||||
extractInputOutputTypesFromFunctionType(expectedType)
|
||||
|
||||
// ReflectionTypes.isBaseTypeForNumberedReferenceTypes(expectedType) ->
|
||||
// InputOutputTypes(emptyList(), expectedType.arguments.single().type.unwrap())
|
||||
//
|
||||
// ReflectionTypes.isNumberedKFunction(expectedType) -> {
|
||||
// val functionFromSupertype = expectedType.immediateSupertypes().first { it.isFunctionType }.unwrap()
|
||||
// extractInputOutputTypesFromFunctionType(functionFromSupertype)
|
||||
// }
|
||||
//
|
||||
// ReflectionTypes.isNumberedKSuspendFunction(expectedType) -> {
|
||||
// val kSuspendFunctionType = expectedType.immediateSupertypes().first { it.isSuspendFunctionType }.unwrap()
|
||||
// extractInputOutputTypesFromFunctionType(kSuspendFunctionType)
|
||||
// }
|
||||
//
|
||||
// ReflectionTypes.isNumberedKPropertyOrKMutablePropertyType(expectedType) -> {
|
||||
// val functionFromSupertype = expectedType.supertypes().first { it.isFunctionType }.unwrap()
|
||||
// extractInputOutputTypesFromFunctionType(functionFromSupertype)
|
||||
// }
|
||||
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
private fun extractInputOutputTypesFromFunctionType(functionType: ConeKotlinType): InputOutputTypes {
|
||||
val receiver = null// TODO: functionType.receiverType()
|
||||
val parameters = functionType.valueParameterTypes.map {
|
||||
it ?: ConeClassTypeImpl(
|
||||
ConeClassLikeLookupTagImpl(StandardClassIds.Nothing), emptyArray(),
|
||||
isNullable = false
|
||||
)
|
||||
}
|
||||
|
||||
val inputTypes = /*listOfNotNull(receiver) +*/ parameters
|
||||
val outputType = functionType.returnType ?: ConeClassTypeImpl(
|
||||
ConeClassLikeLookupTagImpl(StandardClassIds.Any), emptyArray(),
|
||||
isNullable = true
|
||||
)
|
||||
|
||||
return InputOutputTypes(inputTypes, outputType)
|
||||
}
|
||||
|
||||
+7
-1
@@ -5,6 +5,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.fir.resolve.calls
|
||||
|
||||
import org.jetbrains.kotlin.fir.FirCallResolver
|
||||
import org.jetbrains.kotlin.fir.declarations.FirAnonymousFunction
|
||||
import org.jetbrains.kotlin.fir.expressions.FirExpression
|
||||
import org.jetbrains.kotlin.fir.references.impl.FirErrorNamedReferenceImpl
|
||||
@@ -43,7 +44,8 @@ class PostponedArgumentsAnalyzer(
|
||||
private val typeProvider: (FirExpression) -> FirTypeRef?,
|
||||
private val components: InferenceComponents,
|
||||
private val candidate: Candidate,
|
||||
private val replacements: MutableMap<FirExpression, FirExpression>
|
||||
private val replacements: MutableMap<FirExpression, FirExpression>,
|
||||
private val callResolver: FirCallResolver
|
||||
) {
|
||||
|
||||
fun analyze(
|
||||
@@ -70,6 +72,10 @@ class PostponedArgumentsAnalyzer(
|
||||
}
|
||||
|
||||
private fun processCallableReference(atom: ResolvedCallableReferenceAtom) {
|
||||
if (atom.postponed) {
|
||||
callResolver.resolveCallableReference(candidate.csBuilder, atom)
|
||||
}
|
||||
|
||||
val callableReferenceAccess = atom.atom
|
||||
atom.analyzed = true
|
||||
val (candidate, applicability) = atom.resultingCandidate ?: Pair(null, CandidateApplicability.INAPPLICABLE)
|
||||
|
||||
+3
-1
@@ -71,7 +71,9 @@ class FirCallCompleter(
|
||||
val replacements = mutableMapOf<FirExpression, FirExpression>()
|
||||
|
||||
val analyzer =
|
||||
PostponedArgumentsAnalyzer(LambdaAnalyzerImpl(replacements), { it.resultType }, inferenceComponents, candidate, replacements)
|
||||
PostponedArgumentsAnalyzer(
|
||||
LambdaAnalyzerImpl(replacements), { it.resultType }, inferenceComponents, candidate, replacements, transformer.callResolver
|
||||
)
|
||||
|
||||
completer.complete(candidate.system.asConstraintSystemCompleterContext(), completionMode, listOf(call), initialType) {
|
||||
analyzer.analyze(candidate.system.asPostponedArgumentsAnalyzerContext(), it)
|
||||
|
||||
+1
-1
@@ -17,7 +17,7 @@ FILE: applicableCallableReferenceFromDistantScope.kt
|
||||
}
|
||||
|
||||
public final fun test(): R|kotlin/Unit| {
|
||||
lval s: R|kotlin/String| = this@R|/Scope|.R|/Scope.bar|<R|kotlin/String|>(::<Unresolved reference: foo>#)
|
||||
lval s: R|kotlin/String| = this@R|/Scope|.R|/Scope.bar|<R|kotlin/String|>(::R|/foo|)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+4
-4
@@ -15,10 +15,10 @@ FILE: eagerAndPostponedCallableReferences.kt
|
||||
^foo R|kotlin/TODO|()
|
||||
}
|
||||
public final fun test(): R|kotlin/Unit| {
|
||||
lval a1: R|A| = R|/foo|<R|A|>(::R|/singleA|, ::<Unresolved reference: multiple>#)
|
||||
lval a2: R|B| = R|/foo|<R|B|>(::R|/singleB|, ::<Unresolved reference: multiple>#)
|
||||
lval a3: R|A| = R|/foo|<R|A|>(::<Unresolved reference: multiple>#, ::R|/singleA|)
|
||||
lval a4: R|B| = R|/foo|<R|B|>(::<Unresolved reference: multiple>#, ::R|/singleB|)
|
||||
lval a1: R|A| = R|/foo|<R|A|>(::R|/singleA|, ::R|/multiple|)
|
||||
lval a2: R|B| = R|/foo|<R|B|>(::R|/singleB|, ::R|/multiple|)
|
||||
lval a3: R|A| = R|/foo|<R|A|>(::R|/multiple|, ::R|/singleA|)
|
||||
lval a4: R|B| = R|/foo|<R|B|>(::R|/multiple|, ::R|/singleB|)
|
||||
lval a5: R|A| = R|/foo|<R|A|>(::R|/singleA|, ::R|/singleA|)
|
||||
lval a6: R|it(A & B)| = R|/foo|<R|it(A & B)|>(::R|/singleA|, ::R|/singleB|)
|
||||
R|/foo|<R|kotlin/Unit|>(::<Unresolved reference: multiple>#, ::<Unresolved reference: multiple>#)
|
||||
|
||||
+2
-2
@@ -13,8 +13,8 @@ FILE: postponedResolveOfManyCallableReference.kt
|
||||
public final fun <T> bar2(f: R|kotlin/Function1<T, kotlin/Unit>|, e: R|T|): R|kotlin/Unit| {
|
||||
}
|
||||
public final fun test(a: R|A|, b: R|B|): R|kotlin/Unit| {
|
||||
lval expectedType1: R|A| = R|/bar1|<R|A|>(::<Unresolved reference: foo>#)
|
||||
lval expectedType2: R|B| = R|/bar1|<R|B|>(::<Unresolved reference: foo>#)
|
||||
lval expectedType1: R|A| = R|/bar1|<R|A|>(::R|/foo|)
|
||||
lval expectedType2: R|B| = R|/bar1|<R|B|>(::R|/foo|)
|
||||
R|/bar2|<R|A|>(::R|/foo|, R|<local>/a|)
|
||||
R|/bar2|<R|B|>(::R|/foo|, R|<local>/b|)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user