[FIR] Refactor FirResolveBodyTransformer

Extract from it components responsible for call completion,
  call resolution and resolution of FQN
This commit is contained in:
Dmitriy Novozhilov
2019-07-24 16:08:46 +03:00
committed by Mikhail Glukhikh
parent 43e7f54fae
commit a226e40e34
8 changed files with 771 additions and 583 deletions
@@ -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
}
@@ -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
}
}
}
@@ -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)
}
@@ -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
@@ -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
}
}