[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
|
||||
|
||||
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.render
|
||||
import org.jetbrains.kotlin.fir.service
|
||||
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccess
|
||||
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.impl.FirCallableSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeAliasSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
import org.jetbrains.kotlin.fir.types.impl.ConeAbbreviatedTypeImpl
|
||||
import org.jetbrains.kotlin.fir.types.impl.ConeClassTypeImpl
|
||||
import org.jetbrains.kotlin.fir.types.impl.ConeTypeParameterTypeImpl
|
||||
import org.jetbrains.kotlin.fir.types.impl.FirResolvedTypeRefImpl
|
||||
import org.jetbrains.kotlin.fir.types.impl.*
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
|
||||
@@ -167,3 +171,94 @@ fun FirFunction.constructFunctionalTypeRef(session: FirSession): FirResolvedType
|
||||
|
||||
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
|
||||
|
||||
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.declarations.*
|
||||
import org.jetbrains.kotlin.fir.declarations.impl.FirDefaultPropertyAccessor
|
||||
import org.jetbrains.kotlin.fir.declarations.impl.FirValueParameterImpl
|
||||
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.resolve.*
|
||||
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.addImportingScopes
|
||||
import org.jetbrains.kotlin.fir.scopes.impl.FirLocalScope
|
||||
import org.jetbrains.kotlin.fir.scopes.impl.FirTopLevelDeclaredMemberScope
|
||||
import org.jetbrains.kotlin.fir.scopes.impl.withReplacedConeType
|
||||
import org.jetbrains.kotlin.fir.symbols.*
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.*
|
||||
import org.jetbrains.kotlin.fir.symbols.ConeSymbol
|
||||
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.impl.*
|
||||
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.Name
|
||||
import org.jetbrains.kotlin.resolve.calls.NewCommonSuperTypeCalculator
|
||||
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.resolve.calls.results.TypeSpecificityComparator
|
||||
import org.jetbrains.kotlin.types.model.*
|
||||
import org.jetbrains.kotlin.types.model.KotlinTypeMarker
|
||||
import org.jetbrains.kotlin.types.model.SimpleTypeMarker
|
||||
import org.jetbrains.kotlin.types.model.TypeConstructorMarker
|
||||
import org.jetbrains.kotlin.types.model.TypeSystemInferenceExtensionContextDelegate
|
||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||
|
||||
open class FirBodyResolveTransformer(
|
||||
val session: FirSession, val implicitTypeOnly: Boolean,
|
||||
final override val session: FirSession,
|
||||
val implicitTypeOnly: Boolean,
|
||||
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 fun <E : FirElement> transformElement(element: E, data: Any?): CompositeTransformResult<E> {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return (element.transformChildren(this, data) as E).compose()
|
||||
}
|
||||
override val symbolProvider = session.service<FirSymbolProvider>()
|
||||
val scopes = mutableListOf<FirScope>()
|
||||
|
||||
private var packageFqName = FqName.ROOT
|
||||
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> {
|
||||
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> {
|
||||
if (implicitTypeOnly) return constructor.compose()
|
||||
@@ -102,19 +117,6 @@ open class FirBodyResolveTransformer(
|
||||
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> {
|
||||
return withScopeCleanup(scopes) {
|
||||
val oldConstructorScope = primaryConstructorParametersScope
|
||||
@@ -177,217 +179,6 @@ open class FirBodyResolveTransformer(
|
||||
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(
|
||||
qualifiedAccessExpression: FirQualifiedAccessExpression,
|
||||
data: Any?
|
||||
@@ -395,7 +186,6 @@ open class FirBodyResolveTransformer(
|
||||
|
||||
when (val callee = qualifiedAccessExpression.calleeReference) {
|
||||
is FirThisReference -> {
|
||||
|
||||
val labelName = callee.labelName
|
||||
val types = if (labelName == null) labels.values() else labels[Name.identifier(labelName)]
|
||||
val type = types.lastOrNull() ?: ConeKotlinErrorType("Unresolved this@$labelName")
|
||||
@@ -426,11 +216,12 @@ open class FirBodyResolveTransformer(
|
||||
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),
|
||||
// so candidate existence must be checked before calling completion
|
||||
return if (transformedCallee is FirQualifiedAccessExpression && transformedCallee.candidate() != null) {
|
||||
completeTypeInference(transformedCallee, data as? FirTypeRef).compose()
|
||||
callCompleter.completeCall(transformedCallee, data as? FirTypeRef).compose()
|
||||
} else {
|
||||
transformedCallee.compose()
|
||||
}
|
||||
@@ -440,9 +231,10 @@ open class FirBodyResolveTransformer(
|
||||
variableAssignment: FirVariableAssignment,
|
||||
data: Any?
|
||||
): CompositeTransformResult<FirStatement> {
|
||||
val resolvedAssignment = transformCallee(variableAssignment)
|
||||
// val resolvedAssignment = transformCallee(variableAssignment)
|
||||
val resolvedAssignment = callResolver.resolveVariableAccessAndSelectCandidate(variableAssignment, file)
|
||||
return if (resolvedAssignment is FirVariableAssignment) {
|
||||
val completeAssignment = completeTypeInference(resolvedAssignment, noExpectedType)
|
||||
val completeAssignment = callCompleter.completeCall(resolvedAssignment, noExpectedType)
|
||||
val expectedType = typeFromCallee(completeAssignment)
|
||||
completeAssignment.transformRValue(this, expectedType).compose()
|
||||
} 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?)
|
||||
|
||||
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> {
|
||||
@Suppress("NAME_SHADOWING")
|
||||
val tryExpression = tryExpression.transformChildren(this, data) as FirTryExpression
|
||||
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
|
||||
if (expression != null) {
|
||||
(expression.resultType as? FirResolvedTypeRef) ?: FirErrorTypeRefImpl(session, null, "No type for when branch result")
|
||||
@@ -764,13 +371,13 @@ open class FirBodyResolveTransformer(
|
||||
val completeInference =
|
||||
try {
|
||||
val initialExplicitReceiver = functionCall.explicitReceiver
|
||||
val resultExpression = resolveCallAndSelectCandidate(functionCall, expectedTypeRef)
|
||||
val resultExpression = callResolver.resolveCallAndSelectCandidate(functionCall, expectedTypeRef, file)
|
||||
val resultExplicitReceiver = resultExpression.explicitReceiver
|
||||
if (initialExplicitReceiver !== resultExplicitReceiver && resultExplicitReceiver is FirQualifiedAccess) {
|
||||
// name.invoke() case
|
||||
completeTypeInference(resultExplicitReceiver, null)
|
||||
callCompleter.completeCall(resultExplicitReceiver, null)
|
||||
}
|
||||
completeTypeInference(resultExpression, expectedTypeRef)
|
||||
callCompleter.completeCall(resultExpression, expectedTypeRef)
|
||||
} catch (e: Throwable) {
|
||||
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> {
|
||||
// if (namedReference is FirErrorNamedReference || namedReference is FirResolvedCallableReference) 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> {
|
||||
@Suppress("NAME_SHADOWING")
|
||||
val block = block.transformChildren(this, data) as FirBlock
|
||||
val statement = block.statements.lastOrNull()
|
||||
|
||||
@@ -850,6 +413,7 @@ open class FirBodyResolveTransformer(
|
||||
return block.compose()
|
||||
}
|
||||
|
||||
@Deprecated("should be removed after try/when completion")
|
||||
private fun commonSuperType(types: List<FirTypeRef>): FirTypeRef? {
|
||||
val commonSuperType = with(NewCommonSuperTypeCalculator) {
|
||||
with(inferenceComponents.ctx) {
|
||||
@@ -862,7 +426,7 @@ open class FirBodyResolveTransformer(
|
||||
override fun transformWhenExpression(whenExpression: FirWhenExpression, data: Any?): CompositeTransformResult<FirStatement> {
|
||||
whenExpression.transformChildren(this, data)
|
||||
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
|
||||
if (expression != null) {
|
||||
(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)
|
||||
}
|
||||
|
||||
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> {
|
||||
return withContainer(declaration) {
|
||||
super.transformDeclaration(declaration, data)
|
||||
@@ -1121,12 +671,6 @@ open class FirBodyResolveTransformer(
|
||||
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> {
|
||||
val transformedGetClassCall = super.transformGetClassCall(getClassCall, data).single as FirGetClassCall
|
||||
val kClassSymbol = ClassId.fromString("kotlin/reflect/KClass")(session.service())
|
||||
@@ -1159,9 +703,52 @@ open class FirBodyResolveTransformer(
|
||||
)
|
||||
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 {
|
||||
override fun findCommonIntegerLiteralTypesSuperType(explicitSupertypes: List<SimpleTypeMarker>): SimpleTypeMarker? {
|
||||
//TODO wtf
|
||||
@@ -1178,65 +765,7 @@ private fun inferenceComponents(session: FirSession, jump: ReturnTypeCalculatorW
|
||||
override fun KotlinTypeMarker.removeExactAnnotation(): KotlinTypeMarker {
|
||||
return this
|
||||
}
|
||||
}, session, jump, 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
|
||||
}
|
||||
}
|
||||
}, session, returnTypeCalculator, 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
|
||||
}
|
||||
|
||||
|
||||
interface ReturnTypeCalculator {
|
||||
fun tryCalculateReturnType(declaration: FirTypedDeclaration): FirResolvedTypeRef
|
||||
}
|
||||
|
||||
|
||||
internal inline var FirExpression.resultType: FirTypeRef
|
||||
get() = typeRef
|
||||
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.types.Variance
|
||||
|
||||
class FirCallCompleterTransformer(
|
||||
class FirCallCompletionResultsWriterTransformer(
|
||||
val session: FirSession,
|
||||
private val finalSubstitutor: ConeSubstitutor,
|
||||
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