[FIR] Refactor FirResolveBodyTransformer
Extract from it components responsible for call completion, call resolution and resolution of FQN
This commit is contained in:
committed by
Mikhail Glukhikh
parent
43e7f54fae
commit
a226e40e34
@@ -0,0 +1,250 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.fir
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.FirFile
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.FirMemberDeclaration
|
||||||
|
import org.jetbrains.kotlin.fir.expressions.FirExpression
|
||||||
|
import org.jetbrains.kotlin.fir.expressions.FirFunctionCall
|
||||||
|
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccess
|
||||||
|
import org.jetbrains.kotlin.fir.expressions.FirStatement
|
||||||
|
import org.jetbrains.kotlin.fir.expressions.impl.FirResolvedQualifierImpl
|
||||||
|
import org.jetbrains.kotlin.fir.references.FirBackingFieldReferenceImpl
|
||||||
|
import org.jetbrains.kotlin.fir.references.FirErrorNamedReference
|
||||||
|
import org.jetbrains.kotlin.fir.references.FirResolvedCallableReferenceImpl
|
||||||
|
import org.jetbrains.kotlin.fir.references.FirSimpleNamedReference
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.BodyResolveComponents
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.calls.*
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.transformers.FirBodyResolveTransformer
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.transformers.StoreNameReference
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.transformers.firUnsafe
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.transformers.resultType
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.typeForQualifier
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.typeFromCallee
|
||||||
|
import org.jetbrains.kotlin.fir.scopes.FirScope
|
||||||
|
import org.jetbrains.kotlin.fir.symbols.ConeCallableSymbol
|
||||||
|
import org.jetbrains.kotlin.fir.symbols.ConeClassLikeSymbol
|
||||||
|
import org.jetbrains.kotlin.fir.symbols.ConeSymbol
|
||||||
|
import org.jetbrains.kotlin.fir.symbols.impl.FirBackingFieldSymbol
|
||||||
|
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
|
||||||
|
import org.jetbrains.kotlin.fir.symbols.impl.FirVariableSymbol
|
||||||
|
import org.jetbrains.kotlin.fir.types.ConeKotlinErrorType
|
||||||
|
import org.jetbrains.kotlin.fir.types.FirTypeRef
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.results.TypeSpecificityComparator
|
||||||
|
|
||||||
|
class FirCallResolver(
|
||||||
|
private val transformer: FirBodyResolveTransformer,
|
||||||
|
private val inferenceComponents: InferenceComponents,
|
||||||
|
private val scopes: List<FirScope>,
|
||||||
|
private val localScopes: List<FirScope>,
|
||||||
|
private val implicitReceiverStack: List<ImplicitReceiverValue>,
|
||||||
|
private val qualifiedResolver: FirQualifiedNameResolver
|
||||||
|
) : BodyResolveComponents by transformer {
|
||||||
|
|
||||||
|
fun resolveCallAndSelectCandidate(functionCall: FirFunctionCall, expectedTypeRef: FirTypeRef?, file: FirFile): FirFunctionCall {
|
||||||
|
qualifiedResolver.reset()
|
||||||
|
@Suppress("NAME_SHADOWING")
|
||||||
|
val functionCall = (functionCall.transformExplicitReceiver(transformer, noExpectedType) as FirFunctionCall)
|
||||||
|
.transformArguments(transformer, null) as FirFunctionCall
|
||||||
|
|
||||||
|
val name = functionCall.calleeReference.name
|
||||||
|
|
||||||
|
val explicitReceiver = functionCall.explicitReceiver
|
||||||
|
val arguments = functionCall.arguments
|
||||||
|
val typeArguments = functionCall.typeArguments
|
||||||
|
|
||||||
|
val info = CallInfo(
|
||||||
|
CallKind.Function,
|
||||||
|
explicitReceiver,
|
||||||
|
arguments,
|
||||||
|
functionCall.safe,
|
||||||
|
typeArguments,
|
||||||
|
session,
|
||||||
|
file,
|
||||||
|
transformer.container
|
||||||
|
) { it.resultType }
|
||||||
|
val resolver = CallResolver(returnTypeCalculator, inferenceComponents)
|
||||||
|
resolver.callInfo = info
|
||||||
|
resolver.scopes = (scopes + localScopes).asReversed()
|
||||||
|
|
||||||
|
val consumer = createFunctionConsumer(session, name, info, inferenceComponents, resolver.collector, resolver)
|
||||||
|
val result = resolver.runTowerResolver(consumer, implicitReceiverStack.asReversed())
|
||||||
|
val bestCandidates = result.bestCandidates()
|
||||||
|
val reducedCandidates = if (result.currentApplicability < CandidateApplicability.SYNTHETIC_RESOLVED) {
|
||||||
|
bestCandidates.toSet()
|
||||||
|
} else {
|
||||||
|
ConeOverloadConflictResolver(TypeSpecificityComparator.NONE, inferenceComponents)
|
||||||
|
.chooseMaximallySpecificCandidates(bestCandidates, discriminateGenerics = false)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
fun isInvoke()
|
||||||
|
|
||||||
|
val resultExpression =
|
||||||
|
|
||||||
|
when {
|
||||||
|
successCandidates.singleOrNull() as? ConeCallableSymbol -> {
|
||||||
|
FirFunctionCallImpl(functionCall.session, functionCall.psi, safe = functionCall.safe).apply {
|
||||||
|
calleeReference =
|
||||||
|
functionCall.calleeReference.transformSingle(this@FirBodyResolveTransformer, result.successCandidates())
|
||||||
|
explicitReceiver =
|
||||||
|
FirQualifiedAccessExpressionImpl(
|
||||||
|
functionCall.session,
|
||||||
|
functionCall.calleeReference.psi,
|
||||||
|
functionCall.safe
|
||||||
|
).apply {
|
||||||
|
calleeReference = createResolvedNamedReference(
|
||||||
|
functionCall.calleeReference,
|
||||||
|
result.variableChecker.successCandidates() as List<ConeCallableSymbol>
|
||||||
|
)
|
||||||
|
explicitReceiver = functionCall.explicitReceiver
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
is ApplicabilityChecker -> {
|
||||||
|
functionCall.transformCalleeReference(this, result.successCandidates())
|
||||||
|
}
|
||||||
|
else -> functionCall
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
val nameReference = createResolvedNamedReference(
|
||||||
|
functionCall.calleeReference,
|
||||||
|
reducedCandidates,
|
||||||
|
result.currentApplicability
|
||||||
|
)
|
||||||
|
|
||||||
|
val resultExpression = functionCall.transformCalleeReference(StoreNameReference, nameReference) as FirFunctionCall
|
||||||
|
val candidate = resultExpression.candidate()
|
||||||
|
|
||||||
|
// We need desugaring
|
||||||
|
val resultFunctionCall = if (candidate != null && candidate.callInfo != info) {
|
||||||
|
functionCall.copy(
|
||||||
|
explicitReceiver = candidate.callInfo.explicitReceiver,
|
||||||
|
arguments = candidate.callInfo.arguments,
|
||||||
|
safe = candidate.callInfo.isSafeCall
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
resultExpression
|
||||||
|
}
|
||||||
|
val typeRef = typeFromCallee(resultFunctionCall)
|
||||||
|
if (typeRef.type is ConeKotlinErrorType) {
|
||||||
|
resultFunctionCall.resultType = typeRef
|
||||||
|
}
|
||||||
|
return resultFunctionCall
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <T : FirQualifiedAccess> resolveVariableAccessAndSelectCandidate(qualifiedAccess: T, file: FirFile): FirStatement {
|
||||||
|
val callee = qualifiedAccess.calleeReference as? FirSimpleNamedReference ?: return qualifiedAccess
|
||||||
|
|
||||||
|
qualifiedResolver.initProcessingQualifiedAccess(qualifiedAccess, callee)
|
||||||
|
|
||||||
|
@Suppress("NAME_SHADOWING")
|
||||||
|
val qualifiedAccess = qualifiedAccess.transformExplicitReceiver(transformer, noExpectedType)
|
||||||
|
qualifiedResolver.replacedQualifier(qualifiedAccess)?.let { return it }
|
||||||
|
|
||||||
|
val info = CallInfo(
|
||||||
|
CallKind.VariableAccess,
|
||||||
|
qualifiedAccess.explicitReceiver,
|
||||||
|
emptyList(),
|
||||||
|
qualifiedAccess.safe,
|
||||||
|
emptyList(),
|
||||||
|
session,
|
||||||
|
file,
|
||||||
|
transformer.container
|
||||||
|
) { it.resultType }
|
||||||
|
val resolver = CallResolver(returnTypeCalculator, inferenceComponents)
|
||||||
|
resolver.callInfo = info
|
||||||
|
resolver.scopes = (scopes + localScopes).asReversed()
|
||||||
|
|
||||||
|
val consumer = createVariableAndObjectConsumer(
|
||||||
|
session,
|
||||||
|
callee.name,
|
||||||
|
info, inferenceComponents,
|
||||||
|
resolver.collector
|
||||||
|
)
|
||||||
|
val result = resolver.runTowerResolver(consumer, implicitReceiverStack.asReversed())
|
||||||
|
|
||||||
|
val candidates = result.bestCandidates()
|
||||||
|
val nameReference = createResolvedNamedReference(
|
||||||
|
callee,
|
||||||
|
candidates,
|
||||||
|
result.currentApplicability
|
||||||
|
)
|
||||||
|
|
||||||
|
if (qualifiedAccess.explicitReceiver == null &&
|
||||||
|
(candidates.size <= 1 && result.currentApplicability < CandidateApplicability.SYNTHETIC_RESOLVED)
|
||||||
|
) {
|
||||||
|
qualifiedResolver.tryResolveAsQualifier()?.let { return it }
|
||||||
|
}
|
||||||
|
|
||||||
|
val referencedSymbol = when (nameReference) {
|
||||||
|
is FirResolvedCallableReference -> nameReference.coneSymbol
|
||||||
|
is FirNamedReferenceWithCandidate -> nameReference.candidateSymbol
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
if (referencedSymbol is ConeClassLikeSymbol) {
|
||||||
|
return FirResolvedQualifierImpl(session, nameReference.psi, referencedSymbol.classId).apply {
|
||||||
|
resultType = typeForQualifier(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (qualifiedAccess.explicitReceiver == null) {
|
||||||
|
qualifiedResolver.reset()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
val resultExpression = qualifiedAccess.transformCalleeReference(StoreNameReference, nameReference) as T
|
||||||
|
if (resultExpression is FirExpression) transformer.storeTypeFromCallee(resultExpression)
|
||||||
|
return resultExpression
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createResolvedNamedReference(
|
||||||
|
namedReference: FirNamedReference,
|
||||||
|
candidates: Collection<Candidate>,
|
||||||
|
applicability: CandidateApplicability
|
||||||
|
): FirNamedReference {
|
||||||
|
val name = namedReference.name
|
||||||
|
val firSession = namedReference.session
|
||||||
|
val psi = namedReference.psi
|
||||||
|
return when {
|
||||||
|
candidates.isEmpty() -> FirErrorNamedReference(
|
||||||
|
firSession, psi, "Unresolved name: $name"
|
||||||
|
)
|
||||||
|
applicability < CandidateApplicability.SYNTHETIC_RESOLVED -> {
|
||||||
|
FirErrorNamedReference(
|
||||||
|
firSession, psi,
|
||||||
|
"Inapplicable($applicability): ${candidates.map { describeSymbol(it.symbol) }}",
|
||||||
|
namedReference.name
|
||||||
|
)
|
||||||
|
}
|
||||||
|
candidates.size == 1 -> {
|
||||||
|
val candidate = candidates.single()
|
||||||
|
val coneSymbol = candidate.symbol
|
||||||
|
when {
|
||||||
|
coneSymbol is FirBackingFieldSymbol -> FirBackingFieldReferenceImpl(firSession, psi, coneSymbol)
|
||||||
|
coneSymbol is FirVariableSymbol &&
|
||||||
|
(coneSymbol !is FirPropertySymbol || coneSymbol.firUnsafe<FirMemberDeclaration>().typeParameters.isEmpty()) ->
|
||||||
|
FirResolvedCallableReferenceImpl(firSession, psi, name, coneSymbol)
|
||||||
|
else -> FirNamedReferenceWithCandidate(firSession, psi, name, candidate)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else -> FirErrorNamedReference(
|
||||||
|
firSession, psi, "Ambiguity: $name, ${candidates.map { describeSymbol(it.symbol) }}",
|
||||||
|
namedReference.name
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private fun describeSymbol(symbol: ConeSymbol): String {
|
||||||
|
return when (symbol) {
|
||||||
|
is ConeClassLikeSymbol -> symbol.classId.asString()
|
||||||
|
is ConeCallableSymbol -> symbol.callableId.toString()
|
||||||
|
else -> "$symbol"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.fir
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccess
|
||||||
|
import org.jetbrains.kotlin.fir.expressions.FirStatement
|
||||||
|
import org.jetbrains.kotlin.fir.expressions.impl.FirResolvedQualifierImpl
|
||||||
|
import org.jetbrains.kotlin.fir.references.FirSimpleNamedReference
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.BodyResolveComponents
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.FirSymbolProvider
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.transformers.PackageOrClass
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.transformers.resolveToPackageOrClass
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.transformers.resultType
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.typeForQualifier
|
||||||
|
import org.jetbrains.kotlin.name.FqName
|
||||||
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
|
||||||
|
class FirQualifiedNameResolver(components: BodyResolveComponents) : BodyResolveComponents by components {
|
||||||
|
private var qualifierStack = mutableListOf<Name>()
|
||||||
|
private var qualifierPartsToDrop = 0
|
||||||
|
|
||||||
|
fun reset() {
|
||||||
|
qualifierStack.clear()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun initProcessingQualifiedAccess(qualifiedAccess: FirQualifiedAccess, callee: FirSimpleNamedReference) {
|
||||||
|
if (qualifiedAccess.safe || callee.name.isSpecial) {
|
||||||
|
qualifierStack.clear()
|
||||||
|
} else {
|
||||||
|
qualifierStack.add(callee.name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun replacedQualifier(qualifiedAccess: FirQualifiedAccess): FirStatement? =
|
||||||
|
if (qualifierPartsToDrop > 0) {
|
||||||
|
qualifierPartsToDrop--
|
||||||
|
qualifiedAccess.explicitReceiver ?: qualifiedAccess
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
|
||||||
|
fun tryResolveAsQualifier(): FirStatement? {
|
||||||
|
val symbolProvider = session.service<FirSymbolProvider>()
|
||||||
|
var qualifierParts = qualifierStack.asReversed().map { it.asString() }
|
||||||
|
var resolved: PackageOrClass?
|
||||||
|
do {
|
||||||
|
resolved = resolveToPackageOrClass(
|
||||||
|
symbolProvider,
|
||||||
|
FqName.fromSegments(qualifierParts)
|
||||||
|
)
|
||||||
|
if (resolved == null)
|
||||||
|
qualifierParts = qualifierParts.dropLast(1)
|
||||||
|
} while (resolved == null && qualifierParts.isNotEmpty())
|
||||||
|
|
||||||
|
if (resolved != null) {
|
||||||
|
qualifierPartsToDrop = qualifierParts.size - 1
|
||||||
|
return FirResolvedQualifierImpl(
|
||||||
|
session,
|
||||||
|
null /* TODO */,
|
||||||
|
resolved.packageFqName,
|
||||||
|
resolved.relativeClassFqName
|
||||||
|
)
|
||||||
|
.apply { resultType = typeForQualifier(this) }
|
||||||
|
}
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -5,18 +5,22 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.fir.resolve
|
package org.jetbrains.kotlin.fir.resolve
|
||||||
|
|
||||||
import org.jetbrains.kotlin.fir.FirSession
|
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||||
|
import org.jetbrains.kotlin.fir.*
|
||||||
import org.jetbrains.kotlin.fir.declarations.*
|
import org.jetbrains.kotlin.fir.declarations.*
|
||||||
import org.jetbrains.kotlin.fir.render
|
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccess
|
||||||
import org.jetbrains.kotlin.fir.service
|
import org.jetbrains.kotlin.fir.expressions.FirResolvedQualifier
|
||||||
|
import org.jetbrains.kotlin.fir.references.FirErrorNamedReference
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.calls.FirNamedReferenceWithCandidate
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.transformers.resultType
|
||||||
|
import org.jetbrains.kotlin.fir.scopes.impl.withReplacedConeType
|
||||||
import org.jetbrains.kotlin.fir.symbols.*
|
import org.jetbrains.kotlin.fir.symbols.*
|
||||||
|
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
|
||||||
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeAliasSymbol
|
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeAliasSymbol
|
||||||
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol
|
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol
|
||||||
import org.jetbrains.kotlin.fir.types.*
|
import org.jetbrains.kotlin.fir.types.*
|
||||||
import org.jetbrains.kotlin.fir.types.impl.ConeAbbreviatedTypeImpl
|
import org.jetbrains.kotlin.fir.types.impl.*
|
||||||
import org.jetbrains.kotlin.fir.types.impl.ConeClassTypeImpl
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.fir.types.impl.ConeTypeParameterTypeImpl
|
|
||||||
import org.jetbrains.kotlin.fir.types.impl.FirResolvedTypeRefImpl
|
|
||||||
import org.jetbrains.kotlin.types.Variance
|
import org.jetbrains.kotlin.types.Variance
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||||
|
|
||||||
@@ -167,3 +171,94 @@ fun FirFunction.constructFunctionalTypeRef(session: FirSession): FirResolvedType
|
|||||||
|
|
||||||
return FirResolvedTypeRefImpl(session, psi, functionalType)
|
return FirResolvedTypeRefImpl(session, psi, functionalType)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun BodyResolveComponents.typeForQualifier(resolvedQualifier: FirResolvedQualifier): FirTypeRef {
|
||||||
|
val classId = resolvedQualifier.classId
|
||||||
|
val resultType = resolvedQualifier.resultType
|
||||||
|
if (classId != null) {
|
||||||
|
val classSymbol = symbolProvider.getClassLikeSymbolByFqName(classId)!!
|
||||||
|
val declaration = classSymbol.fir
|
||||||
|
if (declaration is FirClass) {
|
||||||
|
if (declaration.classKind == ClassKind.OBJECT) {
|
||||||
|
return resultType.resolvedTypeFromPrototype(
|
||||||
|
classSymbol.constructType(emptyArray(), false)
|
||||||
|
)
|
||||||
|
} else if (declaration.classKind == ClassKind.ENUM_ENTRY) {
|
||||||
|
val enumClassSymbol = symbolProvider.getClassLikeSymbolByFqName(classSymbol.classId.outerClassId!!)!!
|
||||||
|
return resultType.resolvedTypeFromPrototype(
|
||||||
|
enumClassSymbol.constructType(emptyArray(), false)
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
if (declaration is FirRegularClass) {
|
||||||
|
val companionObject = declaration.companionObject
|
||||||
|
if (companionObject != null) {
|
||||||
|
return resultType.resolvedTypeFromPrototype(
|
||||||
|
companionObject.symbol.constructType(emptyArray(), false)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// TODO: Handle no value type here
|
||||||
|
return resultType.resolvedTypeFromPrototype(
|
||||||
|
StandardClassIds.Unit(symbolProvider).constructType(emptyArray(), isNullable = false)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fun <T : FirQualifiedAccess> BodyResolveComponents.typeFromCallee(access: T): FirResolvedTypeRef {
|
||||||
|
val makeNullable: Boolean by lazy {
|
||||||
|
access.safe && access.explicitReceiver!!.resultType.coneTypeUnsafe<ConeKotlinType>().isNullable
|
||||||
|
}
|
||||||
|
|
||||||
|
return when (val newCallee = access.calleeReference) {
|
||||||
|
is FirErrorNamedReference ->
|
||||||
|
FirErrorTypeRefImpl(session, access.psi, newCallee.errorReason)
|
||||||
|
is FirNamedReferenceWithCandidate -> {
|
||||||
|
typeFromSymbol(newCallee.candidateSymbol, makeNullable)
|
||||||
|
}
|
||||||
|
is FirResolvedCallableReference -> {
|
||||||
|
typeFromSymbol(newCallee.coneSymbol, makeNullable)
|
||||||
|
}
|
||||||
|
is FirThisReference -> {
|
||||||
|
val labelName = newCallee.labelName
|
||||||
|
val types = if (labelName == null) labels.values() else labels[Name.identifier(labelName)]
|
||||||
|
val type = types.lastOrNull() ?: ConeKotlinErrorType("Unresolved this@$labelName")
|
||||||
|
FirResolvedTypeRefImpl(session, null, type, emptyList())
|
||||||
|
}
|
||||||
|
else -> error("Failed to extract type from: $newCallee")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun BodyResolveComponents.typeFromSymbol(symbol: ConeSymbol, makeNullable: Boolean): FirResolvedTypeRef {
|
||||||
|
return when (symbol) {
|
||||||
|
is FirCallableSymbol<*> -> {
|
||||||
|
val returnType = returnTypeCalculator.tryCalculateReturnType(symbol.fir)
|
||||||
|
if (makeNullable) {
|
||||||
|
returnType.withReplacedConeType(
|
||||||
|
session,
|
||||||
|
returnType.coneTypeUnsafe<ConeKotlinType>().withNullability(ConeNullability.NULLABLE)
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
returnType
|
||||||
|
}
|
||||||
|
}
|
||||||
|
is ConeClassifierSymbol -> {
|
||||||
|
val fir = (symbol as? FirBasedSymbol<*>)?.fir
|
||||||
|
// TODO: unhack
|
||||||
|
if (fir is FirEnumEntry) {
|
||||||
|
(fir.superTypeRefs.firstOrNull() as? FirResolvedTypeRef) ?: FirErrorTypeRefImpl(
|
||||||
|
session,
|
||||||
|
null,
|
||||||
|
"no enum item supertype"
|
||||||
|
)
|
||||||
|
} else
|
||||||
|
FirResolvedTypeRefImpl(
|
||||||
|
session, null, symbol.constructType(emptyArray(), isNullable = false),
|
||||||
|
annotations = emptyList()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
else -> error("WTF ! $symbol")
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.fir.resolve
|
||||||
|
|
||||||
|
import com.google.common.collect.SetMultimap
|
||||||
|
import org.jetbrains.kotlin.fir.FirSession
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.transformers.ReturnTypeCalculator
|
||||||
|
import org.jetbrains.kotlin.fir.types.ConeKotlinType
|
||||||
|
import org.jetbrains.kotlin.fir.types.FirTypeRef
|
||||||
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
|
||||||
|
interface SessionHolder {
|
||||||
|
val session: FirSession
|
||||||
|
}
|
||||||
|
|
||||||
|
interface BodyResolveComponents : SessionHolder {
|
||||||
|
val returnTypeCalculator: ReturnTypeCalculator
|
||||||
|
val labels: SetMultimap<Name, ConeKotlinType>
|
||||||
|
val noExpectedType: FirTypeRef
|
||||||
|
val symbolProvider: FirSymbolProvider
|
||||||
|
}
|
||||||
+123
@@ -0,0 +1,123 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.fir.resolve.inference
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.fir.copy
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.FirAnonymousFunction
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.impl.FirValueParameterImpl
|
||||||
|
import org.jetbrains.kotlin.fir.expressions.FirExpression
|
||||||
|
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccess
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.BodyResolveComponents
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.calls.*
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.transformers.*
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.transformers.MapArguments
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.typeFromCallee
|
||||||
|
import org.jetbrains.kotlin.fir.resolvedTypeFromPrototype
|
||||||
|
import org.jetbrains.kotlin.fir.transformSingle
|
||||||
|
import org.jetbrains.kotlin.fir.types.ConeKotlinErrorType
|
||||||
|
import org.jetbrains.kotlin.fir.types.ConeKotlinType
|
||||||
|
import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef
|
||||||
|
import org.jetbrains.kotlin.fir.types.FirTypeRef
|
||||||
|
import org.jetbrains.kotlin.fir.types.impl.FirResolvedTypeRefImpl
|
||||||
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.components.InferenceSession
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.inference.buildAbstractResultingSubstitutor
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.inference.components.KotlinConstraintSystemCompleter
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.inference.model.SimpleConstraintSystemConstraintPosition
|
||||||
|
import org.jetbrains.kotlin.types.model.StubTypeMarker
|
||||||
|
import org.jetbrains.kotlin.types.model.TypeVariableMarker
|
||||||
|
|
||||||
|
class FirCallCompleter(
|
||||||
|
private val transformer: FirBodyResolveTransformer,
|
||||||
|
private val inferenceComponents: InferenceComponents
|
||||||
|
) : BodyResolveComponents by transformer {
|
||||||
|
fun <T : FirQualifiedAccess> completeCall(call: T, expectedTypeRef: FirTypeRef?): T {
|
||||||
|
val typeRef = typeFromCallee(call)
|
||||||
|
if (typeRef.type is ConeKotlinErrorType) {
|
||||||
|
if (call is FirExpression) {
|
||||||
|
call.resultType = typeRef
|
||||||
|
}
|
||||||
|
return call
|
||||||
|
}
|
||||||
|
val candidate = call.candidate() ?: return call
|
||||||
|
val initialSubstitutor = candidate.substitutor
|
||||||
|
|
||||||
|
val initialType = initialSubstitutor.substituteOrSelf(typeRef.type)
|
||||||
|
|
||||||
|
if (expectedTypeRef is FirResolvedTypeRef) {
|
||||||
|
candidate.system.addSubtypeConstraint(initialType, expectedTypeRef.type, SimpleConstraintSystemConstraintPosition)
|
||||||
|
}
|
||||||
|
|
||||||
|
val completionMode = candidate.computeCompletionMode(inferenceComponents, expectedTypeRef, initialType)
|
||||||
|
val completer = ConstraintSystemCompleter(inferenceComponents)
|
||||||
|
val replacements = mutableMapOf<FirExpression, FirExpression>()
|
||||||
|
|
||||||
|
val analyzer = PostponedArgumentsAnalyzer(LambdaAnalyzerImpl(replacements), { it.resultType }, inferenceComponents)
|
||||||
|
|
||||||
|
completer.complete(candidate.system.asConstraintSystemCompleterContext(), completionMode, listOf(call), initialType) {
|
||||||
|
analyzer.analyze(candidate.system.asPostponedArgumentsAnalyzerContext(), it)
|
||||||
|
}
|
||||||
|
|
||||||
|
call.transformChildren(MapArguments, replacements.toMap())
|
||||||
|
|
||||||
|
if (completionMode == KotlinConstraintSystemCompleter.ConstraintSystemCompletionMode.FULL) {
|
||||||
|
val finalSubstitutor =
|
||||||
|
candidate.system.asReadOnlyStorage().buildAbstractResultingSubstitutor(inferenceComponents.ctx) as ConeSubstitutor
|
||||||
|
return call.transformSingle(
|
||||||
|
FirCallCompletionResultsWriterTransformer(session, finalSubstitutor, returnTypeCalculator),
|
||||||
|
null
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return call
|
||||||
|
}
|
||||||
|
|
||||||
|
private inner class LambdaAnalyzerImpl(
|
||||||
|
val replacements: MutableMap<FirExpression, FirExpression>
|
||||||
|
) : LambdaAnalyzer {
|
||||||
|
override fun analyzeAndGetLambdaReturnArguments(
|
||||||
|
lambdaArgument: FirAnonymousFunction,
|
||||||
|
isSuspend: Boolean,
|
||||||
|
receiverType: ConeKotlinType?,
|
||||||
|
parameters: List<ConeKotlinType>,
|
||||||
|
expectedReturnType: ConeKotlinType?,
|
||||||
|
rawReturnType: ConeKotlinType,
|
||||||
|
stubsForPostponedVariables: Map<TypeVariableMarker, StubTypeMarker>
|
||||||
|
): Pair<List<FirExpression>, InferenceSession> {
|
||||||
|
|
||||||
|
val itParam = when {
|
||||||
|
lambdaArgument.valueParameters.isEmpty() && parameters.size == 1 ->
|
||||||
|
FirValueParameterImpl(
|
||||||
|
session,
|
||||||
|
null,
|
||||||
|
Name.identifier("it"),
|
||||||
|
FirResolvedTypeRefImpl(session, null, parameters.single(), emptyList()),
|
||||||
|
defaultValue = null,
|
||||||
|
isCrossinline = false,
|
||||||
|
isNoinline = false,
|
||||||
|
isVararg = false
|
||||||
|
)
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
|
||||||
|
val expectedReturnTypeRef = expectedReturnType?.let { lambdaArgument.returnTypeRef.resolvedTypeFromPrototype(it) }
|
||||||
|
|
||||||
|
val newLambdaExpression = lambdaArgument.copy(
|
||||||
|
receiverTypeRef = receiverType?.let { lambdaArgument.receiverTypeRef!!.resolvedTypeFromPrototype(it) },
|
||||||
|
valueParameters = lambdaArgument.valueParameters.mapIndexed { index, parameter ->
|
||||||
|
parameter.transformReturnTypeRef(StoreType, parameter.returnTypeRef.resolvedTypeFromPrototype(parameters[index]))
|
||||||
|
parameter
|
||||||
|
} + listOfNotNull(itParam),
|
||||||
|
returnTypeRef = expectedReturnTypeRef ?: noExpectedType
|
||||||
|
)
|
||||||
|
|
||||||
|
replacements[lambdaArgument] =
|
||||||
|
newLambdaExpression.transformSingle(transformer, FirBodyResolveTransformer.LambdaResolution(expectedReturnTypeRef))
|
||||||
|
|
||||||
|
return listOfNotNull(newLambdaExpression.body?.statements?.lastOrNull() as? FirExpression) to InferenceSession.default
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+103
-575
@@ -6,27 +6,25 @@
|
|||||||
package org.jetbrains.kotlin.fir.resolve.transformers
|
package org.jetbrains.kotlin.fir.resolve.transformers
|
||||||
|
|
||||||
import com.google.common.collect.LinkedHashMultimap
|
import com.google.common.collect.LinkedHashMultimap
|
||||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
import com.google.common.collect.SetMultimap
|
||||||
import org.jetbrains.kotlin.fir.*
|
import org.jetbrains.kotlin.fir.*
|
||||||
import org.jetbrains.kotlin.fir.declarations.*
|
import org.jetbrains.kotlin.fir.declarations.*
|
||||||
import org.jetbrains.kotlin.fir.declarations.impl.FirDefaultPropertyAccessor
|
import org.jetbrains.kotlin.fir.declarations.impl.FirDefaultPropertyAccessor
|
||||||
import org.jetbrains.kotlin.fir.declarations.impl.FirValueParameterImpl
|
import org.jetbrains.kotlin.fir.declarations.impl.FirValueParameterImpl
|
||||||
import org.jetbrains.kotlin.fir.expressions.*
|
import org.jetbrains.kotlin.fir.expressions.*
|
||||||
import org.jetbrains.kotlin.fir.expressions.impl.FirResolvedQualifierImpl
|
|
||||||
import org.jetbrains.kotlin.fir.references.FirBackingFieldReferenceImpl
|
|
||||||
import org.jetbrains.kotlin.fir.references.FirErrorNamedReference
|
|
||||||
import org.jetbrains.kotlin.fir.references.FirResolvedCallableReferenceImpl
|
|
||||||
import org.jetbrains.kotlin.fir.references.FirSimpleNamedReference
|
import org.jetbrains.kotlin.fir.references.FirSimpleNamedReference
|
||||||
import org.jetbrains.kotlin.fir.resolve.*
|
import org.jetbrains.kotlin.fir.resolve.*
|
||||||
import org.jetbrains.kotlin.fir.resolve.calls.*
|
import org.jetbrains.kotlin.fir.resolve.calls.*
|
||||||
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
|
import org.jetbrains.kotlin.fir.resolve.inference.FirCallCompleter
|
||||||
import org.jetbrains.kotlin.fir.scopes.FirScope
|
import org.jetbrains.kotlin.fir.scopes.FirScope
|
||||||
import org.jetbrains.kotlin.fir.scopes.addImportingScopes
|
import org.jetbrains.kotlin.fir.scopes.addImportingScopes
|
||||||
import org.jetbrains.kotlin.fir.scopes.impl.FirLocalScope
|
import org.jetbrains.kotlin.fir.scopes.impl.FirLocalScope
|
||||||
import org.jetbrains.kotlin.fir.scopes.impl.FirTopLevelDeclaredMemberScope
|
import org.jetbrains.kotlin.fir.scopes.impl.FirTopLevelDeclaredMemberScope
|
||||||
import org.jetbrains.kotlin.fir.scopes.impl.withReplacedConeType
|
import org.jetbrains.kotlin.fir.scopes.impl.withReplacedConeType
|
||||||
import org.jetbrains.kotlin.fir.symbols.*
|
import org.jetbrains.kotlin.fir.symbols.ConeSymbol
|
||||||
import org.jetbrains.kotlin.fir.symbols.impl.*
|
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
|
||||||
|
import org.jetbrains.kotlin.fir.symbols.StandardClassIds
|
||||||
|
import org.jetbrains.kotlin.fir.symbols.invoke
|
||||||
import org.jetbrains.kotlin.fir.types.*
|
import org.jetbrains.kotlin.fir.types.*
|
||||||
import org.jetbrains.kotlin.fir.types.impl.*
|
import org.jetbrains.kotlin.fir.types.impl.*
|
||||||
import org.jetbrains.kotlin.fir.visitors.CompositeTransformResult
|
import org.jetbrains.kotlin.fir.visitors.CompositeTransformResult
|
||||||
@@ -37,29 +35,43 @@ import org.jetbrains.kotlin.name.ClassId
|
|||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.resolve.calls.NewCommonSuperTypeCalculator
|
import org.jetbrains.kotlin.resolve.calls.NewCommonSuperTypeCalculator
|
||||||
import org.jetbrains.kotlin.resolve.calls.components.InferenceSession
|
import org.jetbrains.kotlin.types.model.KotlinTypeMarker
|
||||||
import org.jetbrains.kotlin.resolve.calls.inference.buildAbstractResultingSubstitutor
|
import org.jetbrains.kotlin.types.model.SimpleTypeMarker
|
||||||
import org.jetbrains.kotlin.resolve.calls.inference.components.KotlinConstraintSystemCompleter
|
import org.jetbrains.kotlin.types.model.TypeConstructorMarker
|
||||||
import org.jetbrains.kotlin.resolve.calls.inference.model.SimpleConstraintSystemConstraintPosition
|
import org.jetbrains.kotlin.types.model.TypeSystemInferenceExtensionContextDelegate
|
||||||
import org.jetbrains.kotlin.resolve.calls.results.TypeSpecificityComparator
|
|
||||||
import org.jetbrains.kotlin.types.model.*
|
|
||||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||||
|
|
||||||
open class FirBodyResolveTransformer(
|
open class FirBodyResolveTransformer(
|
||||||
val session: FirSession, val implicitTypeOnly: Boolean,
|
final override val session: FirSession,
|
||||||
|
val implicitTypeOnly: Boolean,
|
||||||
val scopeSession: ScopeSession = ScopeSession()
|
val scopeSession: ScopeSession = ScopeSession()
|
||||||
) : FirTransformer<Any?>() {
|
) : FirTransformer<Any?>(), BodyResolveComponents {
|
||||||
|
final override val returnTypeCalculator: ReturnTypeCalculator = ReturnTypeCalculatorWithJump(session, scopeSession)
|
||||||
|
override val labels: SetMultimap<Name, ConeKotlinType> = LinkedHashMultimap.create()
|
||||||
|
override val noExpectedType = FirImplicitTypeRefImpl(session, null)
|
||||||
|
|
||||||
val symbolProvider = session.service<FirSymbolProvider>()
|
override val symbolProvider = session.service<FirSymbolProvider>()
|
||||||
|
val scopes = mutableListOf<FirScope>()
|
||||||
override fun <E : FirElement> transformElement(element: E, data: Any?): CompositeTransformResult<E> {
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
|
||||||
return (element.transformChildren(this, data) as E).compose()
|
|
||||||
}
|
|
||||||
|
|
||||||
private var packageFqName = FqName.ROOT
|
private var packageFqName = FqName.ROOT
|
||||||
private lateinit var file: FirFile
|
private lateinit var file: FirFile
|
||||||
private var container: FirDeclaration? = null
|
|
||||||
|
private var _container: FirDeclaration? = null
|
||||||
|
internal var container: FirDeclaration
|
||||||
|
get() = _container!!
|
||||||
|
set(value) {
|
||||||
|
_container = value
|
||||||
|
}
|
||||||
|
|
||||||
|
private val localScopes = mutableListOf<FirLocalScope>()
|
||||||
|
private val implicitReceiverStack = mutableListOf<ImplicitReceiverValue>()
|
||||||
|
private val inferenceComponents = inferenceComponents(session, returnTypeCalculator, scopeSession)
|
||||||
|
|
||||||
|
private var primaryConstructorParametersScope: FirLocalScope? = null
|
||||||
|
|
||||||
|
private val callCompleter: FirCallCompleter = FirCallCompleter(this, inferenceComponents)
|
||||||
|
private val qualifiedResolver: FirQualifiedNameResolver = FirQualifiedNameResolver(this)
|
||||||
|
private val callResolver: FirCallResolver = FirCallResolver(this, inferenceComponents, scopes, localScopes, implicitReceiverStack, qualifiedResolver)
|
||||||
|
|
||||||
override fun transformFile(file: FirFile, data: Any?): CompositeTransformResult<FirFile> {
|
override fun transformFile(file: FirFile, data: Any?): CompositeTransformResult<FirFile> {
|
||||||
packageFqName = file.packageFqName
|
packageFqName = file.packageFqName
|
||||||
@@ -71,7 +83,10 @@ open class FirBodyResolveTransformer(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private var primaryConstructorParametersScope: FirLocalScope? = null
|
override fun <E : FirElement> transformElement(element: E, data: Any?): CompositeTransformResult<E> {
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
return (element.transformChildren(this, data) as E).compose()
|
||||||
|
}
|
||||||
|
|
||||||
override fun transformConstructor(constructor: FirConstructor, data: Any?): CompositeTransformResult<FirDeclaration> {
|
override fun transformConstructor(constructor: FirConstructor, data: Any?): CompositeTransformResult<FirDeclaration> {
|
||||||
if (implicitTypeOnly) return constructor.compose()
|
if (implicitTypeOnly) return constructor.compose()
|
||||||
@@ -102,19 +117,6 @@ open class FirBodyResolveTransformer(
|
|||||||
return super.transformValueParameter(valueParameter, valueParameter.returnTypeRef)
|
return super.transformValueParameter(valueParameter, valueParameter.returnTypeRef)
|
||||||
}
|
}
|
||||||
|
|
||||||
private inline fun <T> withLabelAndReceiverType(labelName: Name, owner: FirElement, type: ConeKotlinType, block: () -> T): T {
|
|
||||||
labels.put(labelName, type)
|
|
||||||
when (owner) {
|
|
||||||
is FirRegularClass -> implicitReceiverStack += ImplicitDispatchReceiverValue(owner.symbol, type)
|
|
||||||
is FirFunction -> implicitReceiverStack += ImplicitExtensionReceiverValue(type)
|
|
||||||
else -> throw IllegalArgumentException("Incorrect label & receiver owner: ${owner.javaClass}")
|
|
||||||
}
|
|
||||||
val result = block()
|
|
||||||
implicitReceiverStack.removeAt(implicitReceiverStack.size - 1)
|
|
||||||
labels.remove(labelName, type)
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun transformRegularClass(regularClass: FirRegularClass, data: Any?): CompositeTransformResult<FirDeclaration> {
|
override fun transformRegularClass(regularClass: FirRegularClass, data: Any?): CompositeTransformResult<FirDeclaration> {
|
||||||
return withScopeCleanup(scopes) {
|
return withScopeCleanup(scopes) {
|
||||||
val oldConstructorScope = primaryConstructorParametersScope
|
val oldConstructorScope = primaryConstructorParametersScope
|
||||||
@@ -177,217 +179,6 @@ open class FirBodyResolveTransformer(
|
|||||||
return resolved.compose()
|
return resolved.compose()
|
||||||
}
|
}
|
||||||
|
|
||||||
protected inline fun <T> withScopeCleanup(scopes: MutableList<*>, crossinline l: () -> T): T {
|
|
||||||
val sizeBefore = scopes.size
|
|
||||||
val result = l()
|
|
||||||
val size = scopes.size
|
|
||||||
assert(size >= sizeBefore)
|
|
||||||
repeat(size - sizeBefore) {
|
|
||||||
scopes.let { it.removeAt(it.size - 1) }
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
val scopes = mutableListOf<FirScope>()
|
|
||||||
private val localScopes = mutableListOf<FirLocalScope>()
|
|
||||||
|
|
||||||
private val labels = LinkedHashMultimap.create<Name, ConeKotlinType>()
|
|
||||||
|
|
||||||
private val implicitReceiverStack = mutableListOf<ImplicitReceiverValue>()
|
|
||||||
|
|
||||||
private val jump = ReturnTypeCalculatorWithJump(session, scopeSession)
|
|
||||||
|
|
||||||
private fun <T> storeTypeFromCallee(access: T) where T : FirQualifiedAccess, T : FirExpression {
|
|
||||||
access.resultType = typeFromCallee(access)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun typeFromSymbol(symbol: ConeSymbol, makeNullable: Boolean): FirResolvedTypeRef {
|
|
||||||
return when (symbol) {
|
|
||||||
is FirCallableSymbol<*> -> {
|
|
||||||
val returnType = jump.tryCalculateReturnType(symbol.fir)
|
|
||||||
if (makeNullable) {
|
|
||||||
returnType.withReplacedConeType(
|
|
||||||
session,
|
|
||||||
returnType.coneTypeUnsafe<ConeKotlinType>().withNullability(ConeNullability.NULLABLE)
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
returnType
|
|
||||||
}
|
|
||||||
}
|
|
||||||
is ConeClassifierSymbol -> {
|
|
||||||
val fir = (symbol as? FirBasedSymbol<*>)?.fir
|
|
||||||
// TODO: unhack
|
|
||||||
if (fir is FirEnumEntry) {
|
|
||||||
(fir.superTypeRefs.firstOrNull() as? FirResolvedTypeRef) ?: FirErrorTypeRefImpl(
|
|
||||||
session,
|
|
||||||
null,
|
|
||||||
"no enum item supertype"
|
|
||||||
)
|
|
||||||
} else
|
|
||||||
FirResolvedTypeRefImpl(
|
|
||||||
session, null, symbol.constructType(emptyArray(), isNullable = false),
|
|
||||||
annotations = emptyList()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
else -> error("WTF ! $symbol")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun <T> typeFromCallee(access: T): FirResolvedTypeRef where T : FirQualifiedAccess {
|
|
||||||
val makeNullable: Boolean by lazy {
|
|
||||||
access.safe && access.explicitReceiver!!.resultType.coneTypeUnsafe<ConeKotlinType>().isNullable
|
|
||||||
}
|
|
||||||
|
|
||||||
return when (val newCallee = access.calleeReference) {
|
|
||||||
is FirErrorNamedReference ->
|
|
||||||
FirErrorTypeRefImpl(session, access.psi, newCallee.errorReason)
|
|
||||||
is FirNamedReferenceWithCandidate -> {
|
|
||||||
typeFromSymbol(newCallee.candidateSymbol, makeNullable)
|
|
||||||
}
|
|
||||||
is FirResolvedCallableReference -> {
|
|
||||||
typeFromSymbol(newCallee.coneSymbol, makeNullable)
|
|
||||||
}
|
|
||||||
is FirThisReference -> {
|
|
||||||
val labelName = newCallee.labelName
|
|
||||||
val types = if (labelName == null) labels.values() else labels[Name.identifier(labelName)]
|
|
||||||
val type = types.lastOrNull() ?: ConeKotlinErrorType("Unresolved this@$labelName")
|
|
||||||
FirResolvedTypeRefImpl(session, null, type, emptyList())
|
|
||||||
}
|
|
||||||
else -> error("Failed to extract type from: $newCallee")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private var qualifierStack = mutableListOf<Name>()
|
|
||||||
private var qualifierPartsToDrop = 0
|
|
||||||
|
|
||||||
private fun tryResolveAsQualifier(): FirStatement? {
|
|
||||||
|
|
||||||
val symbolProvider = session.service<FirSymbolProvider>()
|
|
||||||
var qualifierParts = qualifierStack.asReversed().map { it.asString() }
|
|
||||||
var resolved: PackageOrClass?
|
|
||||||
do {
|
|
||||||
resolved = resolveToPackageOrClass(
|
|
||||||
symbolProvider,
|
|
||||||
FqName.fromSegments(qualifierParts)
|
|
||||||
)
|
|
||||||
if (resolved == null)
|
|
||||||
qualifierParts = qualifierParts.dropLast(1)
|
|
||||||
} while (resolved == null && qualifierParts.isNotEmpty())
|
|
||||||
|
|
||||||
if (resolved != null) {
|
|
||||||
qualifierPartsToDrop = qualifierParts.size - 1
|
|
||||||
return FirResolvedQualifierImpl(session, null /* TODO */, resolved.packageFqName, resolved.relativeClassFqName)
|
|
||||||
.apply { resultType = typeForQualifier(this) }
|
|
||||||
}
|
|
||||||
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun typeForQualifier(resolvedQualifier: FirResolvedQualifier): FirTypeRef {
|
|
||||||
val classId = resolvedQualifier.classId
|
|
||||||
val resultType = resolvedQualifier.resultType
|
|
||||||
if (classId != null) {
|
|
||||||
val classSymbol = symbolProvider.getClassLikeSymbolByFqName(classId)!!
|
|
||||||
val declaration = classSymbol.fir
|
|
||||||
if (declaration is FirClass) {
|
|
||||||
if (declaration.classKind == ClassKind.OBJECT) {
|
|
||||||
return resultType.resolvedTypeFromPrototype(
|
|
||||||
classSymbol.constructType(emptyArray(), false)
|
|
||||||
)
|
|
||||||
} else if (declaration.classKind == ClassKind.ENUM_ENTRY) {
|
|
||||||
val enumClassSymbol = symbolProvider.getClassLikeSymbolByFqName(classSymbol.classId.outerClassId!!)!!
|
|
||||||
return resultType.resolvedTypeFromPrototype(
|
|
||||||
enumClassSymbol.constructType(emptyArray(), false)
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
if (declaration is FirRegularClass) {
|
|
||||||
val companionObject = declaration.companionObject
|
|
||||||
if (companionObject != null) {
|
|
||||||
return resultType.resolvedTypeFromPrototype(
|
|
||||||
companionObject.symbol.constructType(emptyArray(), false)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// TODO: Handle no value type here
|
|
||||||
return resultType.resolvedTypeFromPrototype(
|
|
||||||
StandardClassIds.Unit(symbolProvider).constructType(emptyArray(), isNullable = false)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun <T : FirQualifiedAccess> transformCallee(qualifiedAccess: T): FirStatement {
|
|
||||||
val callee = qualifiedAccess.calleeReference as? FirSimpleNamedReference ?: return qualifiedAccess
|
|
||||||
if (qualifiedAccess.safe || callee.name.isSpecial) {
|
|
||||||
qualifierStack.clear()
|
|
||||||
} else {
|
|
||||||
qualifierStack.add(callee.name)
|
|
||||||
}
|
|
||||||
|
|
||||||
val qualifiedAccess = qualifiedAccess.transformExplicitReceiver(this, noExpectedType)
|
|
||||||
if (qualifierPartsToDrop > 0) {
|
|
||||||
qualifierPartsToDrop--
|
|
||||||
return qualifiedAccess.explicitReceiver ?: qualifiedAccess
|
|
||||||
}
|
|
||||||
|
|
||||||
val info = CallInfo(
|
|
||||||
CallKind.VariableAccess,
|
|
||||||
qualifiedAccess.explicitReceiver,
|
|
||||||
emptyList(),
|
|
||||||
qualifiedAccess.safe,
|
|
||||||
emptyList(),
|
|
||||||
session,
|
|
||||||
file,
|
|
||||||
container!!
|
|
||||||
) { it.resultType }
|
|
||||||
val resolver = CallResolver(jump, inferenceComponents)
|
|
||||||
resolver.callInfo = info
|
|
||||||
resolver.scopes = (scopes + localScopes).asReversed()
|
|
||||||
|
|
||||||
val consumer = createVariableAndObjectConsumer(
|
|
||||||
session,
|
|
||||||
callee.name,
|
|
||||||
info, inferenceComponents,
|
|
||||||
resolver.collector
|
|
||||||
)
|
|
||||||
val result = resolver.runTowerResolver(consumer, implicitReceiverStack.asReversed())
|
|
||||||
|
|
||||||
val candidates = result.bestCandidates()
|
|
||||||
val nameReference = createResolvedNamedReference(
|
|
||||||
callee,
|
|
||||||
candidates,
|
|
||||||
result.currentApplicability
|
|
||||||
)
|
|
||||||
|
|
||||||
if (qualifiedAccess.explicitReceiver == null &&
|
|
||||||
(candidates.size <= 1 && result.currentApplicability < CandidateApplicability.SYNTHETIC_RESOLVED)
|
|
||||||
) {
|
|
||||||
tryResolveAsQualifier()?.let { return it }
|
|
||||||
}
|
|
||||||
|
|
||||||
val referencedSymbol = when (nameReference) {
|
|
||||||
is FirResolvedCallableReference -> nameReference.coneSymbol
|
|
||||||
is FirNamedReferenceWithCandidate -> nameReference.candidateSymbol
|
|
||||||
else -> null
|
|
||||||
}
|
|
||||||
if (referencedSymbol is ConeClassLikeSymbol) {
|
|
||||||
return FirResolvedQualifierImpl(session, nameReference.psi, referencedSymbol.classId).apply {
|
|
||||||
resultType = typeForQualifier(this)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (qualifiedAccess.explicitReceiver == null) {
|
|
||||||
qualifierStack.clear()
|
|
||||||
}
|
|
||||||
|
|
||||||
val resultExpression =
|
|
||||||
qualifiedAccess.transformCalleeReference(StoreNameReference, nameReference) as T
|
|
||||||
if (resultExpression is FirExpression) storeTypeFromCallee(resultExpression)
|
|
||||||
return resultExpression
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun transformQualifiedAccessExpression(
|
override fun transformQualifiedAccessExpression(
|
||||||
qualifiedAccessExpression: FirQualifiedAccessExpression,
|
qualifiedAccessExpression: FirQualifiedAccessExpression,
|
||||||
data: Any?
|
data: Any?
|
||||||
@@ -395,7 +186,6 @@ open class FirBodyResolveTransformer(
|
|||||||
|
|
||||||
when (val callee = qualifiedAccessExpression.calleeReference) {
|
when (val callee = qualifiedAccessExpression.calleeReference) {
|
||||||
is FirThisReference -> {
|
is FirThisReference -> {
|
||||||
|
|
||||||
val labelName = callee.labelName
|
val labelName = callee.labelName
|
||||||
val types = if (labelName == null) labels.values() else labels[Name.identifier(labelName)]
|
val types = if (labelName == null) labels.values() else labels[Name.identifier(labelName)]
|
||||||
val type = types.lastOrNull() ?: ConeKotlinErrorType("Unresolved this@$labelName")
|
val type = types.lastOrNull() ?: ConeKotlinErrorType("Unresolved this@$labelName")
|
||||||
@@ -426,11 +216,12 @@ open class FirBodyResolveTransformer(
|
|||||||
return qualifiedAccessExpression.compose()
|
return qualifiedAccessExpression.compose()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val transformedCallee = transformCallee(qualifiedAccessExpression)
|
|
||||||
|
val transformedCallee = callResolver.resolveVariableAccessAndSelectCandidate(qualifiedAccessExpression, file)
|
||||||
// NB: here we can get raw expression because of dropped qualifiers (see transform callee),
|
// NB: here we can get raw expression because of dropped qualifiers (see transform callee),
|
||||||
// so candidate existence must be checked before calling completion
|
// so candidate existence must be checked before calling completion
|
||||||
return if (transformedCallee is FirQualifiedAccessExpression && transformedCallee.candidate() != null) {
|
return if (transformedCallee is FirQualifiedAccessExpression && transformedCallee.candidate() != null) {
|
||||||
completeTypeInference(transformedCallee, data as? FirTypeRef).compose()
|
callCompleter.completeCall(transformedCallee, data as? FirTypeRef).compose()
|
||||||
} else {
|
} else {
|
||||||
transformedCallee.compose()
|
transformedCallee.compose()
|
||||||
}
|
}
|
||||||
@@ -440,9 +231,10 @@ open class FirBodyResolveTransformer(
|
|||||||
variableAssignment: FirVariableAssignment,
|
variableAssignment: FirVariableAssignment,
|
||||||
data: Any?
|
data: Any?
|
||||||
): CompositeTransformResult<FirStatement> {
|
): CompositeTransformResult<FirStatement> {
|
||||||
val resolvedAssignment = transformCallee(variableAssignment)
|
// val resolvedAssignment = transformCallee(variableAssignment)
|
||||||
|
val resolvedAssignment = callResolver.resolveVariableAccessAndSelectCandidate(variableAssignment, file)
|
||||||
return if (resolvedAssignment is FirVariableAssignment) {
|
return if (resolvedAssignment is FirVariableAssignment) {
|
||||||
val completeAssignment = completeTypeInference(resolvedAssignment, noExpectedType)
|
val completeAssignment = callCompleter.completeCall(resolvedAssignment, noExpectedType)
|
||||||
val expectedType = typeFromCallee(completeAssignment)
|
val expectedType = typeFromCallee(completeAssignment)
|
||||||
completeAssignment.transformRValue(this, expectedType).compose()
|
completeAssignment.transformRValue(this, expectedType).compose()
|
||||||
} else {
|
} else {
|
||||||
@@ -551,198 +343,13 @@ open class FirBodyResolveTransformer(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private val noExpectedType = FirImplicitTypeRefImpl(session, null)
|
|
||||||
private val inferenceComponents = inferenceComponents(session, jump, scopeSession)
|
|
||||||
|
|
||||||
private fun resolveCallAndSelectCandidate(functionCall: FirFunctionCall, expectedTypeRef: FirTypeRef?): FirFunctionCall {
|
|
||||||
|
|
||||||
qualifierStack.clear()
|
|
||||||
|
|
||||||
val functionCall =
|
|
||||||
(functionCall.transformExplicitReceiver(this, noExpectedType) as FirFunctionCall)
|
|
||||||
.transformArguments(this, null) as FirFunctionCall
|
|
||||||
|
|
||||||
val name = functionCall.calleeReference.name
|
|
||||||
|
|
||||||
val explicitReceiver = functionCall.explicitReceiver
|
|
||||||
val arguments = functionCall.arguments
|
|
||||||
val typeArguments = functionCall.typeArguments
|
|
||||||
|
|
||||||
val info = CallInfo(
|
|
||||||
CallKind.Function,
|
|
||||||
explicitReceiver,
|
|
||||||
arguments,
|
|
||||||
functionCall.safe,
|
|
||||||
typeArguments,
|
|
||||||
session,
|
|
||||||
file,
|
|
||||||
container!!
|
|
||||||
) { it.resultType }
|
|
||||||
val resolver = CallResolver(jump, inferenceComponents)
|
|
||||||
resolver.callInfo = info
|
|
||||||
resolver.scopes = (scopes + localScopes).asReversed()
|
|
||||||
|
|
||||||
val consumer = createFunctionConsumer(session, name, info, inferenceComponents, resolver.collector, resolver)
|
|
||||||
val result = resolver.runTowerResolver(consumer, implicitReceiverStack.asReversed())
|
|
||||||
val bestCandidates = result.bestCandidates()
|
|
||||||
val reducedCandidates = if (result.currentApplicability < CandidateApplicability.SYNTHETIC_RESOLVED) {
|
|
||||||
bestCandidates.toSet()
|
|
||||||
} else {
|
|
||||||
ConeOverloadConflictResolver(TypeSpecificityComparator.NONE, inferenceComponents)
|
|
||||||
.chooseMaximallySpecificCandidates(bestCandidates, discriminateGenerics = false)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// fun isInvoke()
|
|
||||||
//
|
|
||||||
// val resultExpression =
|
|
||||||
//
|
|
||||||
// when {
|
|
||||||
// successCandidates.singleOrNull() as? ConeCallableSymbol -> {
|
|
||||||
// FirFunctionCallImpl(functionCall.session, functionCall.psi, safe = functionCall.safe).apply {
|
|
||||||
// calleeReference =
|
|
||||||
// functionCall.calleeReference.transformSingle(this@FirBodyResolveTransformer, result.successCandidates())
|
|
||||||
// explicitReceiver =
|
|
||||||
// FirQualifiedAccessExpressionImpl(
|
|
||||||
// functionCall.session,
|
|
||||||
// functionCall.calleeReference.psi,
|
|
||||||
// functionCall.safe
|
|
||||||
// ).apply {
|
|
||||||
// calleeReference = createResolvedNamedReference(
|
|
||||||
// functionCall.calleeReference,
|
|
||||||
// result.variableChecker.successCandidates() as List<ConeCallableSymbol>
|
|
||||||
// )
|
|
||||||
// explicitReceiver = functionCall.explicitReceiver
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// is ApplicabilityChecker -> {
|
|
||||||
// functionCall.transformCalleeReference(this, result.successCandidates())
|
|
||||||
// }
|
|
||||||
// else -> functionCall
|
|
||||||
// }
|
|
||||||
val nameReference = createResolvedNamedReference(
|
|
||||||
functionCall.calleeReference,
|
|
||||||
reducedCandidates,
|
|
||||||
result.currentApplicability
|
|
||||||
)
|
|
||||||
|
|
||||||
val resultExpression = functionCall.transformCalleeReference(StoreNameReference, nameReference) as FirFunctionCall
|
|
||||||
val candidate = resultExpression.candidate()
|
|
||||||
|
|
||||||
// We need desugaring
|
|
||||||
val resultFunctionCall = if (candidate != null && candidate.callInfo != info) {
|
|
||||||
functionCall.copy(
|
|
||||||
explicitReceiver = candidate.callInfo.explicitReceiver,
|
|
||||||
arguments = candidate.callInfo.arguments,
|
|
||||||
safe = candidate.callInfo.isSafeCall
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
resultExpression
|
|
||||||
}
|
|
||||||
val typeRef = typeFromCallee(resultFunctionCall)
|
|
||||||
if (typeRef.type is ConeKotlinErrorType) {
|
|
||||||
resultFunctionCall.resultType = typeRef
|
|
||||||
}
|
|
||||||
return resultFunctionCall
|
|
||||||
}
|
|
||||||
|
|
||||||
data class LambdaResolution(val expectedReturnTypeRef: FirResolvedTypeRef?)
|
data class LambdaResolution(val expectedReturnTypeRef: FirResolvedTypeRef?)
|
||||||
|
|
||||||
private fun <T : FirQualifiedAccess> completeTypeInference(qualifiedAccess: T, expectedTypeRef: FirTypeRef?): T {
|
|
||||||
val typeRef = typeFromCallee(qualifiedAccess)
|
|
||||||
if (typeRef.type is ConeKotlinErrorType) {
|
|
||||||
if (qualifiedAccess is FirExpression) {
|
|
||||||
qualifiedAccess.resultType = typeRef
|
|
||||||
}
|
|
||||||
return qualifiedAccess
|
|
||||||
}
|
|
||||||
val candidate = qualifiedAccess.candidate() ?: return qualifiedAccess
|
|
||||||
val initialSubstitutor = candidate.substitutor
|
|
||||||
|
|
||||||
val initialType = initialSubstitutor.substituteOrSelf(typeRef.type)
|
|
||||||
|
|
||||||
if (expectedTypeRef is FirResolvedTypeRef) {
|
|
||||||
candidate.system.addSubtypeConstraint(initialType, expectedTypeRef.type, SimpleConstraintSystemConstraintPosition)
|
|
||||||
}
|
|
||||||
|
|
||||||
val completionMode = candidate.computeCompletionMode(inferenceComponents, expectedTypeRef, initialType)
|
|
||||||
val completer = ConstraintSystemCompleter(inferenceComponents)
|
|
||||||
val replacements = mutableMapOf<FirExpression, FirExpression>()
|
|
||||||
|
|
||||||
val analyzer = PostponedArgumentsAnalyzer(object : LambdaAnalyzer {
|
|
||||||
override fun analyzeAndGetLambdaReturnArguments(
|
|
||||||
lambdaArgument: FirAnonymousFunction,
|
|
||||||
isSuspend: Boolean,
|
|
||||||
receiverType: ConeKotlinType?,
|
|
||||||
parameters: List<ConeKotlinType>,
|
|
||||||
expectedReturnType: ConeKotlinType?,
|
|
||||||
rawReturnType: ConeKotlinType,
|
|
||||||
stubsForPostponedVariables: Map<TypeVariableMarker, StubTypeMarker>
|
|
||||||
): Pair<List<FirExpression>, InferenceSession> {
|
|
||||||
|
|
||||||
val itParam = when {
|
|
||||||
lambdaArgument.valueParameters.isEmpty() && parameters.size == 1 ->
|
|
||||||
FirValueParameterImpl(
|
|
||||||
session,
|
|
||||||
null,
|
|
||||||
Name.identifier("it"),
|
|
||||||
FirResolvedTypeRefImpl(session, null, parameters.single(), emptyList()),
|
|
||||||
defaultValue = null,
|
|
||||||
isCrossinline = false,
|
|
||||||
isNoinline = false,
|
|
||||||
isVararg = false
|
|
||||||
)
|
|
||||||
else -> null
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
val expectedReturnTypeRef = expectedReturnType?.let { lambdaArgument.returnTypeRef.resolvedTypeFromPrototype(it) }
|
|
||||||
|
|
||||||
val newLambdaExpression = lambdaArgument.copy(
|
|
||||||
receiverTypeRef = receiverType?.let { lambdaArgument.receiverTypeRef!!.resolvedTypeFromPrototype(it) },
|
|
||||||
valueParameters = lambdaArgument.valueParameters.mapIndexed { index, parameter ->
|
|
||||||
parameter.transformReturnTypeRef(StoreType, parameter.returnTypeRef.resolvedTypeFromPrototype(parameters[index]))
|
|
||||||
parameter
|
|
||||||
} + listOfNotNull(itParam),
|
|
||||||
returnTypeRef = expectedReturnTypeRef ?: noExpectedType
|
|
||||||
)
|
|
||||||
|
|
||||||
replacements[lambdaArgument] =
|
|
||||||
newLambdaExpression.transformSingle(this@FirBodyResolveTransformer, LambdaResolution(expectedReturnTypeRef))
|
|
||||||
|
|
||||||
|
|
||||||
return listOfNotNull(newLambdaExpression.body?.statements?.lastOrNull() as? FirExpression) to InferenceSession.default
|
|
||||||
}
|
|
||||||
|
|
||||||
}, { it.resultType }, inferenceComponents)
|
|
||||||
|
|
||||||
completer.complete(candidate.system.asConstraintSystemCompleterContext(), completionMode, listOf(qualifiedAccess), initialType) {
|
|
||||||
analyzer.analyze(
|
|
||||||
candidate.system.asPostponedArgumentsAnalyzerContext(),
|
|
||||||
it
|
|
||||||
// diagnosticsHolder
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
qualifiedAccess.transformChildren(MapArguments, replacements.toMap())
|
|
||||||
|
|
||||||
|
|
||||||
if (completionMode == KotlinConstraintSystemCompleter.ConstraintSystemCompletionMode.FULL) {
|
|
||||||
val finalSubstitutor =
|
|
||||||
candidate.system.asReadOnlyStorage().buildAbstractResultingSubstitutor(inferenceComponents.ctx) as ConeSubstitutor
|
|
||||||
return qualifiedAccess.transformSingle(
|
|
||||||
FirCallCompleterTransformer(session, finalSubstitutor, jump),
|
|
||||||
null
|
|
||||||
)
|
|
||||||
}
|
|
||||||
return qualifiedAccess
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun transformTryExpression(tryExpression: FirTryExpression, data: Any?): CompositeTransformResult<FirStatement> {
|
override fun transformTryExpression(tryExpression: FirTryExpression, data: Any?): CompositeTransformResult<FirStatement> {
|
||||||
|
@Suppress("NAME_SHADOWING")
|
||||||
val tryExpression = tryExpression.transformChildren(this, data) as FirTryExpression
|
val tryExpression = tryExpression.transformChildren(this, data) as FirTryExpression
|
||||||
if (tryExpression.resultType !is FirResolvedTypeRef) {
|
if (tryExpression.resultType !is FirResolvedTypeRef) {
|
||||||
val type = commonSuperType((listOf(tryExpression.tryBlock) + tryExpression.catches.map { it.block }).mapNotNull {
|
val type = commonSuperType((listOf(tryExpression.tryBlock) + tryExpression.catches.map { it.block }).map {
|
||||||
val expression = it.statements.lastOrNull() as? FirExpression
|
val expression = it.statements.lastOrNull() as? FirExpression
|
||||||
if (expression != null) {
|
if (expression != null) {
|
||||||
(expression.resultType as? FirResolvedTypeRef) ?: FirErrorTypeRefImpl(session, null, "No type for when branch result")
|
(expression.resultType as? FirResolvedTypeRef) ?: FirErrorTypeRefImpl(session, null, "No type for when branch result")
|
||||||
@@ -764,13 +371,13 @@ open class FirBodyResolveTransformer(
|
|||||||
val completeInference =
|
val completeInference =
|
||||||
try {
|
try {
|
||||||
val initialExplicitReceiver = functionCall.explicitReceiver
|
val initialExplicitReceiver = functionCall.explicitReceiver
|
||||||
val resultExpression = resolveCallAndSelectCandidate(functionCall, expectedTypeRef)
|
val resultExpression = callResolver.resolveCallAndSelectCandidate(functionCall, expectedTypeRef, file)
|
||||||
val resultExplicitReceiver = resultExpression.explicitReceiver
|
val resultExplicitReceiver = resultExpression.explicitReceiver
|
||||||
if (initialExplicitReceiver !== resultExplicitReceiver && resultExplicitReceiver is FirQualifiedAccess) {
|
if (initialExplicitReceiver !== resultExplicitReceiver && resultExplicitReceiver is FirQualifiedAccess) {
|
||||||
// name.invoke() case
|
// name.invoke() case
|
||||||
completeTypeInference(resultExplicitReceiver, null)
|
callCompleter.completeCall(resultExplicitReceiver, null)
|
||||||
}
|
}
|
||||||
completeTypeInference(resultExpression, expectedTypeRef)
|
callCompleter.completeCall(resultExpression, expectedTypeRef)
|
||||||
} catch (e: Throwable) {
|
} catch (e: Throwable) {
|
||||||
throw RuntimeException("While resolving call ${functionCall.render()}", e)
|
throw RuntimeException("While resolving call ${functionCall.render()}", e)
|
||||||
}
|
}
|
||||||
@@ -780,51 +387,6 @@ open class FirBodyResolveTransformer(
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun describeSymbol(symbol: ConeSymbol): String {
|
|
||||||
return when (symbol) {
|
|
||||||
is ConeClassLikeSymbol -> symbol.classId.asString()
|
|
||||||
is ConeCallableSymbol -> symbol.callableId.toString()
|
|
||||||
else -> "$symbol"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun createResolvedNamedReference(
|
|
||||||
namedReference: FirNamedReference,
|
|
||||||
candidates: Collection<Candidate>,
|
|
||||||
applicability: CandidateApplicability
|
|
||||||
): FirNamedReference {
|
|
||||||
val name = namedReference.name
|
|
||||||
val firSession = namedReference.session
|
|
||||||
val psi = namedReference.psi
|
|
||||||
return when {
|
|
||||||
candidates.isEmpty() -> FirErrorNamedReference(
|
|
||||||
firSession, psi, "Unresolved name: $name"
|
|
||||||
)
|
|
||||||
applicability < CandidateApplicability.SYNTHETIC_RESOLVED -> {
|
|
||||||
FirErrorNamedReference(
|
|
||||||
firSession, psi,
|
|
||||||
"Inapplicable($applicability): ${candidates.map { describeSymbol(it.symbol) }}",
|
|
||||||
namedReference.name
|
|
||||||
)
|
|
||||||
}
|
|
||||||
candidates.size == 1 -> {
|
|
||||||
val candidate = candidates.single()
|
|
||||||
val coneSymbol = candidate.symbol
|
|
||||||
when {
|
|
||||||
coneSymbol is FirBackingFieldSymbol -> FirBackingFieldReferenceImpl(firSession, psi, coneSymbol)
|
|
||||||
coneSymbol is FirVariableSymbol &&
|
|
||||||
(coneSymbol !is FirPropertySymbol || coneSymbol.firUnsafe<FirMemberDeclaration>().typeParameters.isEmpty()) ->
|
|
||||||
FirResolvedCallableReferenceImpl(firSession, psi, name, coneSymbol)
|
|
||||||
else -> FirNamedReferenceWithCandidate(firSession, psi, name, candidate)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else -> FirErrorNamedReference(
|
|
||||||
firSession, psi, "Ambiguity: $name, ${candidates.map { describeSymbol(it.symbol) }}",
|
|
||||||
namedReference.name
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// override fun transformNamedReference(namedReference: FirNamedReference, data: Any?): CompositeTransformResult<FirNamedReference> {
|
// override fun transformNamedReference(namedReference: FirNamedReference, data: Any?): CompositeTransformResult<FirNamedReference> {
|
||||||
// if (namedReference is FirErrorNamedReference || namedReference is FirResolvedCallableReference) return namedReference.compose()
|
// if (namedReference is FirErrorNamedReference || namedReference is FirResolvedCallableReference) return namedReference.compose()
|
||||||
// val referents = data as? List<ConeCallableSymbol> ?: return namedReference.compose()
|
// val referents = data as? List<ConeCallableSymbol> ?: return namedReference.compose()
|
||||||
@@ -833,6 +395,7 @@ open class FirBodyResolveTransformer(
|
|||||||
|
|
||||||
|
|
||||||
override fun transformBlock(block: FirBlock, data: Any?): CompositeTransformResult<FirStatement> {
|
override fun transformBlock(block: FirBlock, data: Any?): CompositeTransformResult<FirStatement> {
|
||||||
|
@Suppress("NAME_SHADOWING")
|
||||||
val block = block.transformChildren(this, data) as FirBlock
|
val block = block.transformChildren(this, data) as FirBlock
|
||||||
val statement = block.statements.lastOrNull()
|
val statement = block.statements.lastOrNull()
|
||||||
|
|
||||||
@@ -850,6 +413,7 @@ open class FirBodyResolveTransformer(
|
|||||||
return block.compose()
|
return block.compose()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated("should be removed after try/when completion")
|
||||||
private fun commonSuperType(types: List<FirTypeRef>): FirTypeRef? {
|
private fun commonSuperType(types: List<FirTypeRef>): FirTypeRef? {
|
||||||
val commonSuperType = with(NewCommonSuperTypeCalculator) {
|
val commonSuperType = with(NewCommonSuperTypeCalculator) {
|
||||||
with(inferenceComponents.ctx) {
|
with(inferenceComponents.ctx) {
|
||||||
@@ -862,7 +426,7 @@ open class FirBodyResolveTransformer(
|
|||||||
override fun transformWhenExpression(whenExpression: FirWhenExpression, data: Any?): CompositeTransformResult<FirStatement> {
|
override fun transformWhenExpression(whenExpression: FirWhenExpression, data: Any?): CompositeTransformResult<FirStatement> {
|
||||||
whenExpression.transformChildren(this, data)
|
whenExpression.transformChildren(this, data)
|
||||||
if (whenExpression.resultType !is FirResolvedTypeRef) {
|
if (whenExpression.resultType !is FirResolvedTypeRef) {
|
||||||
val type = commonSuperType(whenExpression.branches.mapNotNull {
|
val type = commonSuperType(whenExpression.branches.map {
|
||||||
val expression = it.result.statements.lastOrNull() as? FirExpression
|
val expression = it.result.statements.lastOrNull() as? FirExpression
|
||||||
if (expression != null) {
|
if (expression != null) {
|
||||||
(expression.resultType as? FirResolvedTypeRef) ?: FirErrorTypeRefImpl(session, null, "No type for when branch result")
|
(expression.resultType as? FirResolvedTypeRef) ?: FirErrorTypeRefImpl(session, null, "No type for when branch result")
|
||||||
@@ -918,20 +482,6 @@ open class FirBodyResolveTransformer(
|
|||||||
return super.transformConstExpression(constExpression, data)
|
return super.transformConstExpression(constExpression, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
private inline var FirExpression.resultType: FirTypeRef
|
|
||||||
get() = typeRef
|
|
||||||
set(type) {
|
|
||||||
replaceTypeRef(type)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun <T> withContainer(declaration: FirDeclaration, f: () -> T): T {
|
|
||||||
val prevContainer = container
|
|
||||||
container = declaration
|
|
||||||
val result = f()
|
|
||||||
container = prevContainer
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun transformDeclaration(declaration: FirDeclaration, data: Any?): CompositeTransformResult<FirDeclaration> {
|
override fun transformDeclaration(declaration: FirDeclaration, data: Any?): CompositeTransformResult<FirDeclaration> {
|
||||||
return withContainer(declaration) {
|
return withContainer(declaration) {
|
||||||
super.transformDeclaration(declaration, data)
|
super.transformDeclaration(declaration, data)
|
||||||
@@ -1121,12 +671,6 @@ open class FirBodyResolveTransformer(
|
|||||||
return (expression.transformChildren(this, data) as FirStatement).compose()
|
return (expression.transformChildren(this, data) as FirStatement).compose()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <D> FirElement.visitNoTransform(transformer: FirTransformer<D>, data: D) {
|
|
||||||
val result = this.transform<FirElement, D>(transformer, data)
|
|
||||||
require(result.single === this) { "become ${result.single}: `${result.single.render()}`, was ${this}: `${this.render()}`" }
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
override fun transformGetClassCall(getClassCall: FirGetClassCall, data: Any?): CompositeTransformResult<FirStatement> {
|
override fun transformGetClassCall(getClassCall: FirGetClassCall, data: Any?): CompositeTransformResult<FirStatement> {
|
||||||
val transformedGetClassCall = super.transformGetClassCall(getClassCall, data).single as FirGetClassCall
|
val transformedGetClassCall = super.transformGetClassCall(getClassCall, data).single as FirGetClassCall
|
||||||
val kClassSymbol = ClassId.fromString("kotlin/reflect/KClass")(session.service())
|
val kClassSymbol = ClassId.fromString("kotlin/reflect/KClass")(session.service())
|
||||||
@@ -1159,9 +703,52 @@ open class FirBodyResolveTransformer(
|
|||||||
)
|
)
|
||||||
return transformedGetClassCall.compose()
|
return transformedGetClassCall.compose()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ----------------------- Util functions -----------------------
|
||||||
|
|
||||||
|
private inline fun <T> withLabelAndReceiverType(labelName: Name, owner: FirElement, type: ConeKotlinType, block: () -> T): T {
|
||||||
|
labels.put(labelName, type)
|
||||||
|
when (owner) {
|
||||||
|
is FirRegularClass -> implicitReceiverStack += ImplicitDispatchReceiverValue(owner.symbol, type)
|
||||||
|
is FirFunction -> implicitReceiverStack += ImplicitExtensionReceiverValue(type)
|
||||||
|
else -> throw IllegalArgumentException("Incorrect label & receiver owner: ${owner.javaClass}")
|
||||||
|
}
|
||||||
|
val result = block()
|
||||||
|
implicitReceiverStack.removeAt(implicitReceiverStack.size - 1)
|
||||||
|
labels.remove(labelName, type)
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
protected inline fun <T> withScopeCleanup(scopes: MutableList<*>, crossinline l: () -> T): T {
|
||||||
|
val sizeBefore = scopes.size
|
||||||
|
val result = l()
|
||||||
|
val size = scopes.size
|
||||||
|
assert(size >= sizeBefore)
|
||||||
|
repeat(size - sizeBefore) {
|
||||||
|
scopes.let { it.removeAt(it.size - 1) }
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun <T> storeTypeFromCallee(access: T) where T : FirQualifiedAccess, T : FirExpression {
|
||||||
|
access.resultType = callCompleter.typeFromCallee(access)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun <T> withContainer(declaration: FirDeclaration, f: () -> T): T {
|
||||||
|
val prevContainer = _container
|
||||||
|
_container = declaration
|
||||||
|
val result = f()
|
||||||
|
_container = prevContainer
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <D> FirElement.visitNoTransform(transformer: FirTransformer<D>, data: D) {
|
||||||
|
val result = this.transform<FirElement, D>(transformer, data)
|
||||||
|
require(result.single === this) { "become ${result.single}: `${result.single.render()}`, was ${this}: `${this.render()}`" }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun inferenceComponents(session: FirSession, jump: ReturnTypeCalculatorWithJump, scopeSession: ScopeSession) =
|
private fun inferenceComponents(session: FirSession, returnTypeCalculator: ReturnTypeCalculator, scopeSession: ScopeSession) =
|
||||||
InferenceComponents(object : ConeInferenceContext, TypeSystemInferenceExtensionContextDelegate {
|
InferenceComponents(object : ConeInferenceContext, TypeSystemInferenceExtensionContextDelegate {
|
||||||
override fun findCommonIntegerLiteralTypesSuperType(explicitSupertypes: List<SimpleTypeMarker>): SimpleTypeMarker? {
|
override fun findCommonIntegerLiteralTypesSuperType(explicitSupertypes: List<SimpleTypeMarker>): SimpleTypeMarker? {
|
||||||
//TODO wtf
|
//TODO wtf
|
||||||
@@ -1178,65 +765,7 @@ private fun inferenceComponents(session: FirSession, jump: ReturnTypeCalculatorW
|
|||||||
override fun KotlinTypeMarker.removeExactAnnotation(): KotlinTypeMarker {
|
override fun KotlinTypeMarker.removeExactAnnotation(): KotlinTypeMarker {
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
}, session, jump, scopeSession)
|
}, session, returnTypeCalculator, scopeSession)
|
||||||
|
|
||||||
|
|
||||||
class ReturnTypeCalculatorWithJump(val session: FirSession, val scopeSession: ScopeSession) : ReturnTypeCalculator {
|
|
||||||
|
|
||||||
private fun cycleErrorType(declaration: FirTypedDeclaration): FirResolvedTypeRef? {
|
|
||||||
if (declaration.returnTypeRef is FirComputingImplicitTypeRef) {
|
|
||||||
declaration.transformReturnTypeRef(TransformImplicitType, FirErrorTypeRefImpl(session, null, "cycle"))
|
|
||||||
return declaration.returnTypeRef as FirResolvedTypeRef
|
|
||||||
}
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun tryCalculateReturnType(declaration: FirTypedDeclaration): FirResolvedTypeRef {
|
|
||||||
|
|
||||||
if (declaration is FirValueParameter && declaration.returnTypeRef is FirImplicitTypeRef) {
|
|
||||||
// TODO?
|
|
||||||
declaration.transformReturnTypeRef(TransformImplicitType, FirErrorTypeRefImpl(session, null, "Unsupported: implicit VP type"))
|
|
||||||
}
|
|
||||||
val returnTypeRef = declaration.returnTypeRef
|
|
||||||
if (returnTypeRef is FirResolvedTypeRef) return returnTypeRef
|
|
||||||
cycleErrorType(declaration)?.let { return it }
|
|
||||||
require(declaration is FirCallableMemberDeclaration<*>) { "${declaration::class}: ${declaration.render()}" }
|
|
||||||
|
|
||||||
|
|
||||||
val symbol = declaration.symbol as ConeCallableSymbol
|
|
||||||
val id = symbol.callableId
|
|
||||||
|
|
||||||
val provider = session.service<FirProvider>()
|
|
||||||
|
|
||||||
val file = provider.getFirCallableContainerFile(symbol)
|
|
||||||
|
|
||||||
val outerClasses = generateSequence(id.classId) { classId ->
|
|
||||||
classId.outerClassId
|
|
||||||
}.mapTo(mutableListOf()) { provider.getFirClassifierByFqName(it) }
|
|
||||||
|
|
||||||
if (file == null || outerClasses.any { it == null }) return FirErrorTypeRefImpl(
|
|
||||||
session,
|
|
||||||
null,
|
|
||||||
"I don't know what todo"
|
|
||||||
)
|
|
||||||
|
|
||||||
declaration.transformReturnTypeRef(TransformImplicitType, FirComputingImplicitTypeRef)
|
|
||||||
|
|
||||||
val transformer = FirDesignatedBodyResolveTransformer(
|
|
||||||
(listOf(file) + outerClasses.filterNotNull().asReversed() + listOf(declaration)).iterator(),
|
|
||||||
file.fileSession,
|
|
||||||
scopeSession
|
|
||||||
)
|
|
||||||
|
|
||||||
file.transform<FirElement, Any?>(transformer, null)
|
|
||||||
|
|
||||||
|
|
||||||
val newReturnTypeRef = declaration.returnTypeRef
|
|
||||||
cycleErrorType(declaration)?.let { return it }
|
|
||||||
require(newReturnTypeRef is FirResolvedTypeRef) { declaration.render() }
|
|
||||||
return newReturnTypeRef
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class FirDesignatedBodyResolveTransformer(val designation: Iterator<FirElement>, session: FirSession, scopeSession: ScopeSession) :
|
class FirDesignatedBodyResolveTransformer(val designation: Iterator<FirElement>, session: FirSession, scopeSession: ScopeSession) :
|
||||||
@@ -1294,9 +823,8 @@ inline fun <reified T : FirElement> ConeSymbol.firSafeNullable(): T? {
|
|||||||
return fir as? T
|
return fir as? T
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal inline var FirExpression.resultType: FirTypeRef
|
||||||
interface ReturnTypeCalculator {
|
get() = typeRef
|
||||||
fun tryCalculateReturnType(declaration: FirTypedDeclaration): FirResolvedTypeRef
|
set(type) {
|
||||||
}
|
replaceTypeRef(type)
|
||||||
|
}
|
||||||
|
|
||||||
+1
-1
@@ -28,7 +28,7 @@ import org.jetbrains.kotlin.fir.visitors.FirTransformer
|
|||||||
import org.jetbrains.kotlin.fir.visitors.compose
|
import org.jetbrains.kotlin.fir.visitors.compose
|
||||||
import org.jetbrains.kotlin.types.Variance
|
import org.jetbrains.kotlin.types.Variance
|
||||||
|
|
||||||
class FirCallCompleterTransformer(
|
class FirCallCompletionResultsWriterTransformer(
|
||||||
val session: FirSession,
|
val session: FirSession,
|
||||||
private val finalSubstitutor: ConeSubstitutor,
|
private val finalSubstitutor: ConeSubstitutor,
|
||||||
private val typeCalculator: ReturnTypeCalculator
|
private val typeCalculator: ReturnTypeCalculator
|
||||||
+96
@@ -0,0 +1,96 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.fir.resolve.transformers
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.fir.FirElement
|
||||||
|
import org.jetbrains.kotlin.fir.FirSession
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.FirCallableMemberDeclaration
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.FirTypedDeclaration
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.FirValueParameter
|
||||||
|
import org.jetbrains.kotlin.fir.render
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.FirProvider
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.ScopeSession
|
||||||
|
import org.jetbrains.kotlin.fir.service
|
||||||
|
import org.jetbrains.kotlin.fir.symbols.ConeCallableSymbol
|
||||||
|
import org.jetbrains.kotlin.fir.types.FirImplicitTypeRef
|
||||||
|
import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef
|
||||||
|
import org.jetbrains.kotlin.fir.types.impl.FirComputingImplicitTypeRef
|
||||||
|
import org.jetbrains.kotlin.fir.types.impl.FirErrorTypeRefImpl
|
||||||
|
|
||||||
|
interface ReturnTypeCalculator {
|
||||||
|
fun tryCalculateReturnType(declaration: FirTypedDeclaration): FirResolvedTypeRef
|
||||||
|
}
|
||||||
|
|
||||||
|
class ReturnTypeCalculatorWithJump(val session: FirSession, val scopeSession: ScopeSession) :
|
||||||
|
ReturnTypeCalculator {
|
||||||
|
|
||||||
|
private fun cycleErrorType(declaration: FirTypedDeclaration): FirResolvedTypeRef? {
|
||||||
|
if (declaration.returnTypeRef is FirComputingImplicitTypeRef) {
|
||||||
|
declaration.transformReturnTypeRef(
|
||||||
|
TransformImplicitType,
|
||||||
|
FirErrorTypeRefImpl(session, null, "cycle")
|
||||||
|
)
|
||||||
|
return declaration.returnTypeRef as FirResolvedTypeRef
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun tryCalculateReturnType(declaration: FirTypedDeclaration): FirResolvedTypeRef {
|
||||||
|
|
||||||
|
if (declaration is FirValueParameter && declaration.returnTypeRef is FirImplicitTypeRef) {
|
||||||
|
// TODO?
|
||||||
|
declaration.transformReturnTypeRef(
|
||||||
|
TransformImplicitType,
|
||||||
|
FirErrorTypeRefImpl(
|
||||||
|
session,
|
||||||
|
null,
|
||||||
|
"Unsupported: implicit VP type"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
val returnTypeRef = declaration.returnTypeRef
|
||||||
|
if (returnTypeRef is FirResolvedTypeRef) return returnTypeRef
|
||||||
|
cycleErrorType(declaration)?.let { return it }
|
||||||
|
require(declaration is FirCallableMemberDeclaration<*>) { "${declaration::class}: ${declaration.render()}" }
|
||||||
|
|
||||||
|
|
||||||
|
val symbol = declaration.symbol as ConeCallableSymbol
|
||||||
|
val id = symbol.callableId
|
||||||
|
|
||||||
|
val provider = session.service<FirProvider>()
|
||||||
|
|
||||||
|
val file = provider.getFirCallableContainerFile(symbol)
|
||||||
|
|
||||||
|
val outerClasses = generateSequence(id.classId) { classId ->
|
||||||
|
classId.outerClassId
|
||||||
|
}.mapTo(mutableListOf()) { provider.getFirClassifierByFqName(it) }
|
||||||
|
|
||||||
|
if (file == null || outerClasses.any { it == null }) return FirErrorTypeRefImpl(
|
||||||
|
session,
|
||||||
|
null,
|
||||||
|
"I don't know what todo"
|
||||||
|
)
|
||||||
|
|
||||||
|
declaration.transformReturnTypeRef(
|
||||||
|
TransformImplicitType,
|
||||||
|
FirComputingImplicitTypeRef
|
||||||
|
)
|
||||||
|
|
||||||
|
val transformer = FirDesignatedBodyResolveTransformer(
|
||||||
|
(listOf(file) + outerClasses.filterNotNull().asReversed() + listOf(declaration)).iterator(),
|
||||||
|
file.fileSession,
|
||||||
|
scopeSession
|
||||||
|
)
|
||||||
|
|
||||||
|
file.transform<FirElement, Any?>(transformer, null)
|
||||||
|
|
||||||
|
|
||||||
|
val newReturnTypeRef = declaration.returnTypeRef
|
||||||
|
cycleErrorType(declaration)?.let { return it }
|
||||||
|
require(newReturnTypeRef is FirResolvedTypeRef) { declaration.render() }
|
||||||
|
return newReturnTypeRef
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user