[FIR] Use tower to resolve delegated constructors, set dispatch receiver
This commit is contained in:
@@ -6,6 +6,7 @@
|
||||
package org.jetbrains.kotlin.fir
|
||||
|
||||
import org.jetbrains.kotlin.fir.declarations.FirMemberDeclaration
|
||||
import org.jetbrains.kotlin.fir.declarations.isInner
|
||||
import org.jetbrains.kotlin.fir.expressions.*
|
||||
import org.jetbrains.kotlin.fir.expressions.builder.buildExpressionStub
|
||||
import org.jetbrains.kotlin.fir.expressions.builder.buildResolvedReifiedParameterReference
|
||||
@@ -20,7 +21,6 @@ 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.calls.tower.FirTowerResolver
|
||||
import org.jetbrains.kotlin.fir.resolve.calls.tower.TowerGroup
|
||||
import org.jetbrains.kotlin.fir.resolve.calls.tower.TowerResolveManager
|
||||
import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeAmbiguityError
|
||||
import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeInapplicableCandidateError
|
||||
@@ -32,14 +32,12 @@ 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.scopes.unsubstitutedScope
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.*
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilder
|
||||
import org.jetbrains.kotlin.resolve.calls.results.TypeSpecificityComparator
|
||||
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind
|
||||
|
||||
class FirCallResolver(
|
||||
private val components: BodyResolveComponents,
|
||||
@@ -269,14 +267,13 @@ class FirCallResolver(
|
||||
|
||||
fun resolveDelegatingConstructorCall(
|
||||
delegatedConstructorCall: FirDelegatedConstructorCall,
|
||||
symbol: FirClassSymbol<*>,
|
||||
constructorClassSymbol: FirClassSymbol<*>,
|
||||
typeArguments: List<FirTypeProjection>,
|
||||
): FirDelegatedConstructorCall? {
|
||||
val scope = symbol.fir.unsubstitutedScope(session, scopeSession)
|
||||
val className = symbol.classId.shortClassName
|
||||
val name = Name.special("<init>")
|
||||
val callInfo = CallInfo(
|
||||
CallKind.DelegatingConstructorCall,
|
||||
className,
|
||||
name,
|
||||
explicitReceiver = null,
|
||||
delegatedConstructorCall.argumentList,
|
||||
isSafeCall = false,
|
||||
@@ -286,22 +283,19 @@ class FirCallResolver(
|
||||
file,
|
||||
implicitReceiverStack,
|
||||
)
|
||||
val candidateFactory = CandidateFactory(this, callInfo)
|
||||
val candidates = mutableListOf<Candidate>()
|
||||
towerResolver.reset()
|
||||
val result = towerResolver.runResolverForDelegatingConstructor(
|
||||
implicitReceiverStack.receiversAsReversed(),
|
||||
callInfo,
|
||||
constructorClassSymbol,
|
||||
)
|
||||
|
||||
scope.processDeclaredConstructors {
|
||||
val candidate = candidateFactory.createCandidate(it, ExplicitReceiverKind.NO_EXPLICIT_RECEIVER)
|
||||
candidate.typeArgumentMapping = TypeArgumentMapping.Mapped(typeArguments)
|
||||
candidates += candidate
|
||||
}
|
||||
return callResolver.selectDelegatingConstructorCall(delegatedConstructorCall, className, candidates)
|
||||
return callResolver.selectDelegatingConstructorCall(delegatedConstructorCall, name, result)
|
||||
}
|
||||
|
||||
private fun selectDelegatingConstructorCall(
|
||||
call: FirDelegatedConstructorCall, name: Name, candidates: Collection<Candidate>,
|
||||
call: FirDelegatedConstructorCall, name: Name, result: CandidateCollector,
|
||||
): FirDelegatedConstructorCall {
|
||||
val result = CandidateCollector(this, resolutionStageRunner)
|
||||
candidates.forEach { result.consumeCandidate(TowerGroup.Start, it) }
|
||||
val bestCandidates = result.bestCandidates()
|
||||
val reducedCandidates = if (result.currentApplicability < CandidateApplicability.SYNTHETIC_RESOLVED) {
|
||||
bestCandidates.toSet()
|
||||
@@ -316,7 +310,15 @@ class FirCallResolver(
|
||||
result.currentApplicability,
|
||||
)
|
||||
|
||||
return call.transformCalleeReference(StoreNameReference, nameReference)
|
||||
return call.transformCalleeReference(StoreNameReference, nameReference).apply {
|
||||
val singleCandidate = reducedCandidates.singleOrNull()
|
||||
if (singleCandidate != null) {
|
||||
val symbol = singleCandidate.symbol
|
||||
if (symbol is FirConstructorSymbol && symbol.fir.isInner) {
|
||||
transformDispatchReceiver(StoreReceiver, singleCandidate.dispatchReceiverExpression())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun createCallableReferencesInfoForLHS(
|
||||
|
||||
@@ -40,6 +40,7 @@ enum class CallKind(vararg resolutionSequence: ResolutionStage) {
|
||||
CheckVisibility,
|
||||
MapArguments,
|
||||
CheckExplicitReceiverConsistency,
|
||||
MapTypeArguments,
|
||||
CreateFreshTypeVariableSubstitutorStage,
|
||||
CheckReceivers.Dispatch,
|
||||
CheckReceivers.Extension,
|
||||
|
||||
+21
-2
@@ -28,10 +28,11 @@ import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
private operator fun <T> Pair<T, *>?.component1() = this?.first
|
||||
private operator fun <T> Pair<*, T>?.component2() = this?.second
|
||||
|
||||
internal fun FirScope.processFunctionsAndConstructorsByName(
|
||||
internal fun FirScope.processConstructorsByName(
|
||||
name: Name,
|
||||
session: FirSession,
|
||||
bodyResolveComponents: BodyResolveComponents,
|
||||
noSyntheticConstructors: Boolean,
|
||||
noInnerConstructors: Boolean = false,
|
||||
processor: (FirCallableSymbol<*>) -> Unit
|
||||
) {
|
||||
@@ -41,7 +42,6 @@ internal fun FirScope.processFunctionsAndConstructorsByName(
|
||||
val (matchedClassifierSymbol, substitutor) = classifierInfo
|
||||
val matchedClassSymbol = matchedClassifierSymbol as? FirClassLikeSymbol<*>
|
||||
|
||||
|
||||
processConstructors(
|
||||
matchedClassSymbol,
|
||||
substitutor,
|
||||
@@ -51,12 +51,31 @@ internal fun FirScope.processFunctionsAndConstructorsByName(
|
||||
noInnerConstructors
|
||||
)
|
||||
|
||||
if (noSyntheticConstructors) {
|
||||
return
|
||||
}
|
||||
|
||||
processSyntheticConstructors(
|
||||
matchedClassSymbol,
|
||||
processor,
|
||||
bodyResolveComponents
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
internal fun FirScope.processFunctionsAndConstructorsByName(
|
||||
name: Name,
|
||||
session: FirSession,
|
||||
bodyResolveComponents: BodyResolveComponents,
|
||||
noInnerConstructors: Boolean = false,
|
||||
processor: (FirCallableSymbol<*>) -> Unit
|
||||
) {
|
||||
processConstructorsByName(
|
||||
name, session, bodyResolveComponents,
|
||||
noSyntheticConstructors = false,
|
||||
noInnerConstructors = noInnerConstructors,
|
||||
processor = processor
|
||||
)
|
||||
|
||||
processFunctionsByName(name) {
|
||||
processor(it)
|
||||
|
||||
+1
-1
@@ -36,7 +36,7 @@ internal object MapTypeArguments : ResolutionStage() {
|
||||
|
||||
val owner = candidate.symbol.fir as FirTypeParameterRefsOwner
|
||||
|
||||
if (typeArguments.size == owner.typeParameters.size) {
|
||||
if (typeArguments.size == owner.typeParameters.size || callInfo.callKind == CallKind.DelegatingConstructorCall) {
|
||||
candidate.typeArgumentMapping = TypeArgumentMapping.Mapped(typeArguments)
|
||||
} else {
|
||||
sink.yieldApplicability(CandidateApplicability.INAPPLICABLE)
|
||||
|
||||
+16
@@ -7,6 +7,8 @@ package org.jetbrains.kotlin.fir.resolve.calls.tower
|
||||
|
||||
import org.jetbrains.kotlin.fir.resolve.BodyResolveComponents
|
||||
import org.jetbrains.kotlin.fir.resolve.calls.*
|
||||
import org.jetbrains.kotlin.fir.scopes.FirScope
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
|
||||
|
||||
class FirTowerResolver(
|
||||
private val components: BodyResolveComponents,
|
||||
@@ -30,6 +32,20 @@ class FirTowerResolver(
|
||||
return collector
|
||||
}
|
||||
|
||||
fun runResolverForDelegatingConstructor(
|
||||
implicitReceiverValues: List<ImplicitReceiverValue<*>>,
|
||||
info: CallInfo,
|
||||
constructorClassSymbol: FirClassSymbol<*>,
|
||||
): CandidateCollector {
|
||||
val candidateFactoriesAndCollectors = buildCandidateFactoriesAndCollectors(info, collector)
|
||||
|
||||
val towerResolverSession = FirTowerResolverSession(components, implicitReceiverValues, manager, candidateFactoriesAndCollectors)
|
||||
towerResolverSession.runResolutionForDelegatingConstructor(info, constructorClassSymbol)
|
||||
|
||||
manager.runTasks()
|
||||
return collector
|
||||
}
|
||||
|
||||
private fun buildCandidateFactoriesAndCollectors(
|
||||
info: CallInfo,
|
||||
collector: CandidateCollector
|
||||
|
||||
+25
@@ -26,7 +26,9 @@ import org.jetbrains.kotlin.fir.scopes.ProcessorAction
|
||||
import org.jetbrains.kotlin.fir.scopes.impl.FirCompositeScope
|
||||
import org.jetbrains.kotlin.fir.scopes.impl.FirLocalScope
|
||||
import org.jetbrains.kotlin.fir.scopes.impl.FirStaticScope
|
||||
import org.jetbrains.kotlin.fir.scopes.unsubstitutedScope
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
import org.jetbrains.kotlin.fir.types.impl.FirImplicitBuiltinTypeRef
|
||||
@@ -65,6 +67,10 @@ class FirTowerResolverSession internal constructor(
|
||||
else
|
||||
components.typeParametersScopes.asReversed() + components.fileImportsScope.asReversed()
|
||||
|
||||
fun runResolutionForDelegatingConstructor(info: CallInfo, constructorClassSymbol: FirClassSymbol<*>) {
|
||||
manager.enqueueResolverTask { runResolverForDelegatingConstructorCall(info, constructorClassSymbol) }
|
||||
}
|
||||
|
||||
fun runResolution(info: CallInfo) {
|
||||
when (val receiver = info.explicitReceiver) {
|
||||
is FirResolvedQualifier -> manager.enqueueResolverTask { runResolverForQualifierReceiver(info, receiver) }
|
||||
@@ -198,6 +204,25 @@ class FirTowerResolverSession internal constructor(
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun runResolverForDelegatingConstructorCall(info: CallInfo, constructorClassSymbol: FirClassSymbol<*>) {
|
||||
val scope = constructorClassSymbol.fir.unsubstitutedScope(session, components.scopeSession)
|
||||
// Search for non-inner constructors only
|
||||
processLevel(
|
||||
scope.toScopeTowerLevel(),
|
||||
info, TowerGroup.Implicit(0)
|
||||
)
|
||||
// Search for inner constructors only
|
||||
if (constructorClassSymbol is FirRegularClassSymbol) {
|
||||
// 1 because we search for inner constructor in outer class
|
||||
implicitReceiversUsableAsValues.getOrNull(1)?.let { (implicitReceiverValue) ->
|
||||
processLevel(
|
||||
implicitReceiverValue.toMemberScopeTowerLevel(),
|
||||
info.copy(name = constructorClassSymbol.fir.name), TowerGroup.Implicit(1)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun runResolverForNoReceiver(
|
||||
info: CallInfo
|
||||
) {
|
||||
|
||||
+9
@@ -122,6 +122,9 @@ internal class TowerLevelHandler {
|
||||
towerLevel.processFunctionsAndProperties(info.name, processor)
|
||||
}
|
||||
}
|
||||
CallKind.DelegatingConstructorCall -> {
|
||||
towerLevel.processConstructors(info.name, processor)
|
||||
}
|
||||
else -> {
|
||||
throw AssertionError("Unsupported call kind in tower resolver: ${info.callKind}")
|
||||
}
|
||||
@@ -150,6 +153,12 @@ internal class TowerLevelHandler {
|
||||
processProperties(name, processor)
|
||||
}
|
||||
|
||||
private fun TowerScopeLevel.processConstructors(
|
||||
name: Name, processor: TowerScopeLevel.TowerScopeLevelProcessor<AbstractFirBasedSymbol<*>>
|
||||
) {
|
||||
processElementsByNameAndStoreResult(TowerScopeLevel.Token.Constructors, name, processor)
|
||||
}
|
||||
|
||||
private fun TowerScopeLevel.processObjectsAsVariables(
|
||||
name: Name, processor: TowerScopeLevel.TowerScopeLevelProcessor<AbstractFirBasedSymbol<*>>
|
||||
) {
|
||||
|
||||
+33
-6
@@ -37,8 +37,8 @@ interface TowerScopeLevel {
|
||||
|
||||
sealed class Token<out T : AbstractFirBasedSymbol<*>> {
|
||||
object Properties : Token<FirVariableSymbol<*>>()
|
||||
|
||||
object Functions : Token<FirFunctionSymbol<*>>()
|
||||
object Constructors : Token<FirConstructorSymbol>()
|
||||
object Objects : Token<AbstractFirBasedSymbol<*>>()
|
||||
}
|
||||
|
||||
@@ -82,6 +82,7 @@ class MemberScopeTowerLevel(
|
||||
) : SessionBasedTowerLevel(session) {
|
||||
private fun <T : AbstractFirBasedSymbol<*>> processMembers(
|
||||
output: TowerScopeLevel.TowerScopeLevelProcessor<T>,
|
||||
forInnerConstructors: Boolean = false,
|
||||
processScopeMembers: FirScope.(processor: (T) -> Unit) -> Unit
|
||||
): ProcessorAction {
|
||||
var empty = true
|
||||
@@ -92,7 +93,11 @@ class MemberScopeTowerLevel(
|
||||
(implicitExtensionInvokeMode || candidate.hasConsistentExtensionReceiver(extensionReceiver))
|
||||
) {
|
||||
val fir = candidate.fir
|
||||
if ((fir as? FirCallableMemberDeclaration<*>)?.isStatic == true || (fir as? FirConstructor)?.isInner == false) {
|
||||
if (forInnerConstructors) {
|
||||
if (candidate !is FirConstructorSymbol || !candidate.fir.isInner) {
|
||||
return@processScopeMembers
|
||||
}
|
||||
} else if ((fir as? FirCallableMemberDeclaration<*>)?.isStatic == true || (fir as? FirConstructor)?.isInner == false) {
|
||||
return@processScopeMembers
|
||||
}
|
||||
val dispatchReceiverValue = NotNullableReceiverValue(dispatchReceiver)
|
||||
@@ -114,10 +119,12 @@ class MemberScopeTowerLevel(
|
||||
}
|
||||
}
|
||||
|
||||
val withSynthetic = FirSyntheticPropertiesScope(session, scope)
|
||||
withSynthetic.processScopeMembers { symbol ->
|
||||
empty = false
|
||||
output.consumeCandidate(symbol, NotNullableReceiverValue(dispatchReceiver), extensionReceiver as? ImplicitReceiverValue<*>)
|
||||
if (!forInnerConstructors) {
|
||||
val withSynthetic = FirSyntheticPropertiesScope(session, scope)
|
||||
withSynthetic.processScopeMembers { symbol ->
|
||||
empty = false
|
||||
output.consumeCandidate(symbol, NotNullableReceiverValue(dispatchReceiver), extensionReceiver as? ImplicitReceiverValue<*>)
|
||||
}
|
||||
}
|
||||
return if (empty) ProcessorAction.NONE else ProcessorAction.NEXT
|
||||
}
|
||||
@@ -157,6 +164,17 @@ class MemberScopeTowerLevel(
|
||||
consumer(it as T)
|
||||
}
|
||||
}
|
||||
TowerScopeLevel.Token.Constructors -> processMembers(processor, forInnerConstructors = true) { consumer ->
|
||||
this.processConstructorsByName(
|
||||
name, session, bodyResolveComponents,
|
||||
noSyntheticConstructors = true,
|
||||
noInnerConstructors = false,
|
||||
processor = {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
consumer(it as T)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -261,6 +279,15 @@ class ScopeTowerLevel(
|
||||
implicitExtensionReceiverValue = null
|
||||
)
|
||||
}
|
||||
TowerScopeLevel.Token.Constructors -> scope.processDeclaredConstructors { candidate ->
|
||||
// NB: here we cannot resolve inner constructors, because they should have dispatch receiver
|
||||
if (!candidate.fir.isInner) {
|
||||
processor.consumeCandidate(
|
||||
candidate as T, dispatchReceiverValue(scope, candidate),
|
||||
implicitExtensionReceiverValue = null
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
return if (empty) ProcessorAction.NONE else ProcessorAction.NEXT
|
||||
}
|
||||
|
||||
+7
-2
@@ -644,7 +644,8 @@ class FirExpressionsResolveTransformer(transformer: FirBodyResolveTransformer) :
|
||||
context.implicitReceiverStack.add(name, lastDispatchReceiver)
|
||||
}
|
||||
val typeArguments: List<FirTypeProjection>
|
||||
val symbol: FirClassSymbol<*> = when (val reference = delegatedConstructorCall.calleeReference) {
|
||||
val reference = delegatedConstructorCall.calleeReference
|
||||
val symbol: FirClassSymbol<*> = when (reference) {
|
||||
is FirThisReference -> {
|
||||
typeArguments = emptyList()
|
||||
if (reference.boundSymbol == null) {
|
||||
@@ -674,7 +675,11 @@ class FirExpressionsResolveTransformer(transformer: FirBodyResolveTransformer) :
|
||||
}
|
||||
val resolvedCall = callResolver.resolveDelegatingConstructorCall(delegatedConstructorCall, symbol, typeArguments)
|
||||
?: return delegatedConstructorCall.compose()
|
||||
|
||||
if (reference is FirThisReference && reference.boundSymbol == null) {
|
||||
resolvedCall.dispatchReceiver.typeRef.coneTypeSafe<ConeClassLikeType>()?.lookupTag?.toSymbol(session)?.let {
|
||||
reference.replaceBoundSymbol(it)
|
||||
}
|
||||
}
|
||||
|
||||
val completionResult = callCompleter.completeCall(resolvedCall, noExpectedType)
|
||||
result = completionResult.result
|
||||
|
||||
Reference in New Issue
Block a user