FIR: Support postponed callable references resolution

^KT-32725 In Progress
This commit is contained in:
Denis Zharkov
2019-10-17 18:46:24 +03:00
parent cb50ea2707
commit 937ea3d8a0
7 changed files with 84 additions and 16 deletions
@@ -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
}
}
@@ -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)
}
@@ -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)
@@ -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)
@@ -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|)
}
}
@@ -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>#)
@@ -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|)
}