Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.FirDeclarationsResolveTransformer.kt Maven / Gradle / Ivy
/*
* Copyright 2010-2020 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.body.resolve
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.Visibilities.Internal
import org.jetbrains.kotlin.descriptors.Visibilities.Private
import org.jetbrains.kotlin.descriptors.Visibilities.Protected
import org.jetbrains.kotlin.descriptors.Visibilities.Public
import org.jetbrains.kotlin.descriptors.Visibility
import org.jetbrains.kotlin.fir.*
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.builder.buildValueParameter
import org.jetbrains.kotlin.fir.declarations.impl.FirDefaultPropertyAccessor
import org.jetbrains.kotlin.fir.declarations.synthetic.FirSyntheticProperty
import org.jetbrains.kotlin.fir.diagnostics.ConeSimpleDiagnostic
import org.jetbrains.kotlin.fir.diagnostics.DiagnosticKind
import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.expressions.builder.buildReturnExpression
import org.jetbrains.kotlin.fir.expressions.builder.buildUnitExpression
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
import org.jetbrains.kotlin.fir.resolve.*
import org.jetbrains.kotlin.fir.resolve.calls.FirNamedReferenceWithCandidate
import org.jetbrains.kotlin.fir.resolve.calls.ImplicitExtensionReceiverValue
import org.jetbrains.kotlin.fir.resolve.calls.InaccessibleImplicitReceiverValue
import org.jetbrains.kotlin.fir.resolve.dfa.FirControlFlowGraphReferenceImpl
import org.jetbrains.kotlin.fir.resolve.inference.FirDelegatedPropertyInferenceSession
import org.jetbrains.kotlin.fir.resolve.inference.extractLambdaInfoFromFunctionalType
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
import org.jetbrains.kotlin.fir.resolve.transformers.*
import org.jetbrains.kotlin.fir.scopes.impl.FirLocalScope
import org.jetbrains.kotlin.fir.scopes.impl.FirMemberTypeParameterScope
import org.jetbrains.kotlin.fir.scopes.impl.withReplacedConeType
import org.jetbrains.kotlin.fir.symbols.constructStarProjectedType
import org.jetbrains.kotlin.fir.symbols.impl.ConeClassLookupTagWithFixedSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirVariableSymbol
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.fir.types.builder.buildErrorTypeRef
import org.jetbrains.kotlin.fir.types.builder.buildImplicitTypeRef
import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef
import org.jetbrains.kotlin.fir.visitors.*
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.types.TypeApproximatorConfiguration
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
open class FirDeclarationsResolveTransformer(transformer: FirBodyResolveTransformer) : FirPartialBodyResolveTransformer(transformer) {
private var containingClass: FirRegularClass? = null
private inline fun withFirArrayOfCallTransformer(block: () -> T): T {
transformer.expressionsTransformer.enableArrayOfCallTransformation = true
return try {
block()
} finally {
transformer.expressionsTransformer.enableArrayOfCallTransformation = false
}
}
private fun transformDeclarationContent(
declaration: FirDeclaration, data: ResolutionMode
): CompositeTransformResult {
transformer.onBeforeDeclarationContentResolve(declaration)
return context.withContainer(declaration) {
declaration.replaceResolvePhase(transformerPhase)
transformer.transformDeclarationContent(declaration, data)
}
}
override fun transformDeclarationStatus(
declarationStatus: FirDeclarationStatus,
data: ResolutionMode
): CompositeTransformResult {
return ((data as? ResolutionMode.WithStatus)?.status ?: declarationStatus).compose()
}
private fun prepareSignatureForBodyResolve(callableMember: FirCallableMemberDeclaration<*>) {
callableMember.transformReturnTypeRef(transformer, ResolutionMode.ContextIndependent)
callableMember.transformReceiverTypeRef(transformer, ResolutionMode.ContextIndependent)
if (callableMember is FirFunction<*>) {
callableMember.valueParameters.forEach {
it.transformReturnTypeRef(transformer, ResolutionMode.ContextIndependent)
it.transformVarargTypeToArrayType()
}
}
}
protected fun createTypeParameterScope(declaration: FirMemberDeclaration): FirMemberTypeParameterScope? {
if (declaration.typeParameters.isEmpty()) return null
for (typeParameter in declaration.typeParameters) {
(typeParameter as? FirTypeParameter)?.replaceResolvePhase(FirResolvePhase.STATUS)
typeParameter.transformChildren(transformer, ResolutionMode.ContextIndependent)
}
return FirMemberTypeParameterScope(declaration)
}
protected inline fun withTypeParametersOf(declaration: FirMemberDeclaration, crossinline l: () -> T): T {
val scope = createTypeParameterScope(declaration) ?: return l()
return context.withTowerDataCleanup {
context.addNonLocalTowerDataElement(scope.asTowerDataElement(isLocal = false))
l()
}
}
override fun transformProperty(property: FirProperty, data: ResolutionMode): CompositeTransformResult {
if (property is FirSyntheticProperty) {
val delegate = property.getter.delegate
if (delegate.origin == FirDeclarationOrigin.IntersectionOverride) {
val unwrapped = delegate.symbol.overriddenSymbol!!.fir
transformSimpleFunction(unwrapped, data)
delegate.replaceReturnTypeRef(unwrapped.returnTypeRef)
} else {
transformSimpleFunction(delegate, data)
}
return property.compose()
}
return withTypeParametersOf(property) {
if (property.isLocal) {
prepareSignatureForBodyResolve(property)
property.transformStatus(this, property.resolveStatus(property.status).mode())
property.getter?.let { it.transformStatus(this, it.resolveStatus(it.status).mode()) }
property.setter?.let { it.transformStatus(this, it.resolveStatus(it.status).mode()) }
return@withTypeParametersOf transformLocalVariable(property)
}
val returnTypeRef = property.returnTypeRef
if (returnTypeRef !is FirImplicitTypeRef && implicitTypeOnly) return@withTypeParametersOf property.compose()
if (property.resolvePhase == transformerPhase) return@withTypeParametersOf property.compose()
if (property.resolvePhase == FirResolvePhase.IMPLICIT_TYPES_BODY_RESOLVE && transformerPhase == FirResolvePhase.BODY_RESOLVE) {
property.replaceResolvePhase(transformerPhase)
return@withTypeParametersOf property.compose()
}
dataFlowAnalyzer.enterProperty(property)
withFullBodyResolve {
withLocalScopeCleanup {
context.withContainer(property) {
if (property.delegate != null) {
addLocalScope(context.getPrimaryConstructorParametersScope())
transformPropertyWithDelegate(property)
} else {
withLocalScopeCleanup {
addLocalScope(context.getPrimaryConstructorParametersScope())
property.transformChildrenWithoutAccessors(returnTypeRef)
property.transformInitializer(integerLiteralTypeApproximator, property.returnTypeRef.coneTypeSafe())
}
if (property.initializer != null) {
storeVariableReturnType(property)
}
withLocalScopeCleanup {
if (property.receiverTypeRef == null) {
addLocalScope(FirLocalScope().storeBackingField(property))
}
property.transformAccessors()
}
}
}
property.replaceResolvePhase(transformerPhase)
dataFlowAnalyzer.exitProperty(property)?.let {
property.replaceControlFlowGraphReference(FirControlFlowGraphReferenceImpl(it))
}
property.compose()
}
}
}
}
private fun FirFunctionCall.replacePropertyReferenceTypeInDelegateAccessors(property: FirProperty) {
// var someProperty: SomeType
// get() = delegate.getValue(thisRef, kProperty: KProperty0/1/2<..., SomeType>)
// set() = delegate.getValue(thisRef, kProperty: KProperty0/1/2<..., SomeType>, value)
val propertyReferenceAccess = argumentMapping?.keys?.toList()?.getOrNull(1) as? FirCallableReferenceAccess ?: return
val typeRef = propertyReferenceAccess.typeRef
if (typeRef is FirResolvedTypeRef && property.returnTypeRef is FirResolvedTypeRef) {
val typeArguments = (typeRef.type as ConeClassLikeType).typeArguments
val extensionType = property.receiverTypeRef?.coneType
val dispatchType = containingClass?.let { containingClass ->
containingClass.symbol.constructStarProjectedType(containingClass.typeParameters.size)
}
propertyReferenceAccess.replaceTypeRef(
buildResolvedTypeRef {
source = typeRef.source
annotations.addAll(typeRef.annotations)
type = (typeRef.type as ConeClassLikeType).lookupTag.constructClassType(
typeArguments.mapIndexed { index, argument ->
when (index) {
typeArguments.lastIndex -> property.returnTypeRef.coneType
0 -> extensionType ?: dispatchType
else -> dispatchType
} ?: argument
}.toTypedArray(),
isNullable = false
)
}
)
}
}
private fun replacePropertyReferenceTypeInDelegateAccessors(property: FirProperty) {
(property.getter?.body?.statements?.singleOrNull() as? FirReturnExpression)?.let { returnExpression ->
(returnExpression.result as? FirFunctionCall)?.replacePropertyReferenceTypeInDelegateAccessors(property)
}
(property.setter?.body?.statements?.singleOrNull() as? FirFunctionCall)?.replacePropertyReferenceTypeInDelegateAccessors(property)
(property.delegate as? FirFunctionCall)?.replacePropertyReferenceTypeInDelegateAccessors(property)
}
private fun transformPropertyWithDelegate(property: FirProperty) {
property.transformDelegate(transformer, ResolutionMode.ContextDependent)
val delegateExpression = property.delegate!!
val inferenceSession = FirDelegatedPropertyInferenceSession(
property,
delegateExpression,
resolutionContext,
callCompleter.createPostponedArgumentsAnalyzer(resolutionContext)
)
context.withInferenceSession(inferenceSession) {
property.transformAccessors()
val completedCalls = inferenceSession.completeCandidates()
val finalSubstitutor = inferenceSession.createFinalSubstitutor()
val callCompletionResultsWriter = components.callCompleter.createCompletionResultsWriter(
finalSubstitutor,
mode = FirCallCompletionResultsWriterTransformer.Mode.DelegatedPropertyCompletion
)
completedCalls.forEach {
it.transformSingle(callCompletionResultsWriter, null)
}
val declarationCompletionResultsWriter = FirDeclarationCompletionResultsWriter(finalSubstitutor)
property.transformSingle(declarationCompletionResultsWriter, null)
}
if (property.delegateFieldSymbol != null) {
replacePropertyReferenceTypeInDelegateAccessors(property)
}
property.transformTypeParameters(transformer, ResolutionMode.ContextIndependent)
.transformOtherChildren(transformer, ResolutionMode.ContextIndependent)
}
override fun transformWrappedDelegateExpression(
wrappedDelegateExpression: FirWrappedDelegateExpression,
data: ResolutionMode,
): CompositeTransformResult {
dataFlowAnalyzer.enterDelegateExpression()
try {
val delegateProvider = wrappedDelegateExpression.delegateProvider.transformSingle(transformer, ResolutionMode.ContextDependent)
when (val calleeReference = (delegateProvider as FirResolvable).calleeReference) {
is FirResolvedNamedReference -> return delegateProvider.compose()
is FirNamedReferenceWithCandidate -> {
val candidate = calleeReference.candidate
if (!candidate.system.hasContradiction) {
return delegateProvider.compose()
}
}
}
(delegateProvider as? FirFunctionCall)?.let { dataFlowAnalyzer.dropSubgraphFromCall(it) }
return wrappedDelegateExpression.expression.transform(transformer, ResolutionMode.ContextDependent)
} finally {
dataFlowAnalyzer.exitDelegateExpression()
}
}
private fun transformLocalVariable(variable: FirProperty): CompositeTransformResult {
assert(variable.isLocal)
if (variable.delegate != null) {
transformPropertyWithDelegate(variable)
} else {
val resolutionMode = withExpectedType(variable.returnTypeRef)
variable.transformInitializer(transformer, resolutionMode)
.transformDelegate(transformer, resolutionMode)
.transformTypeParameters(transformer, resolutionMode)
.transformOtherChildren(transformer, resolutionMode)
.transformInitializer(integerLiteralTypeApproximator, null)
if (variable.initializer != null) {
storeVariableReturnType(variable)
}
variable.transformAccessors()
}
context.storeVariable(variable)
variable.replaceResolvePhase(transformerPhase)
dataFlowAnalyzer.exitLocalVariableDeclaration(variable)
return variable.compose()
}
private fun FirProperty.transformChildrenWithoutAccessors(returnTypeRef: FirTypeRef): FirProperty {
val data = withExpectedType(returnTypeRef)
return transformReturnTypeRef(transformer, data)
.transformInitializer(transformer, data)
.transformDelegate(transformer, data)
.transformTypeParameters(transformer, data)
.transformOtherChildren(transformer, data)
}
private fun > FirVariable.transformAccessors() {
var enhancedTypeRef = returnTypeRef
getter?.let {
transformAccessor(it, enhancedTypeRef, this)
}
if (returnTypeRef is FirImplicitTypeRef) {
storeVariableReturnType(this)
enhancedTypeRef = returnTypeRef
}
setter?.let {
if (it.valueParameters[0].returnTypeRef is FirImplicitTypeRef) {
it.valueParameters[0].transformReturnTypeRef(StoreType, enhancedTypeRef)
}
transformAccessor(it, enhancedTypeRef, this)
}
}
private fun transformAccessor(
accessor: FirPropertyAccessor,
enhancedTypeRef: FirTypeRef,
owner: FirVariable<*>
) {
if (accessor is FirDefaultPropertyAccessor || accessor.body == null) {
transformFunction(accessor, withExpectedType(enhancedTypeRef))
return
}
val returnTypeRef = accessor.returnTypeRef
val expectedReturnTypeRef = if (enhancedTypeRef is FirResolvedTypeRef && returnTypeRef !is FirResolvedTypeRef) {
enhancedTypeRef
} else {
returnTypeRef
}
val resolutionMode = if (expectedReturnTypeRef.coneTypeSafe() == session.builtinTypes.unitType.type) {
ResolutionMode.ContextIndependent
} else {
withExpectedType(expectedReturnTypeRef)
}
val receiverTypeRef = owner.receiverTypeRef
if (receiverTypeRef != null) {
withLabelAndReceiverType(owner.name, owner, receiverTypeRef.coneType) {
transformFunctionWithGivenSignature(accessor, resolutionMode)
}
} else {
transformFunctionWithGivenSignature(accessor, resolutionMode)
}
}
private fun FirDeclaration.resolveStatus(status: FirDeclarationStatus, containingClass: FirClass<*>? = null): FirDeclarationStatus {
val containingDeclaration = context.containerIfAny
return resolveStatus(
status, containingClass as? FirRegularClass, isLocal = containingDeclaration != null && containingClass == null
)
}
override fun transformRegularClass(regularClass: FirRegularClass, data: ResolutionMode): CompositeTransformResult {
context.storeClassIfNotNested(regularClass)
if (regularClass.isLocal && regularClass !in context.targetedLocalClasses) {
return regularClass.runAllPhasesForLocalClass(transformer, components, data).compose()
}
return context.withTowerDataCleanup {
if (!regularClass.isInner && context.containerIfAny is FirRegularClass) {
context.replaceTowerDataContext(
context.getTowerDataContextForStaticNestedClassesUnsafe()
)
}
doTransformRegularClass(regularClass, data)
}
}
private fun doTransformRegularClass(
regularClass: FirRegularClass,
data: ResolutionMode
): CompositeTransformResult.Single {
val notAnalyzed = regularClass.resolvePhase < transformerPhase
if (notAnalyzed) {
dataFlowAnalyzer.enterClass()
}
val oldContainingClass = containingClass
containingClass = regularClass
val type = regularClass.defaultType()
val result = withScopesForClass(regularClass.name, regularClass, type) {
transformDeclarationContent(regularClass, data).single as FirRegularClass
}
if (notAnalyzed) {
if (!implicitTypeOnly) {
val controlFlowGraph = dataFlowAnalyzer.exitRegularClass(result)
result.replaceControlFlowGraphReference(FirControlFlowGraphReferenceImpl(controlFlowGraph))
} else {
dataFlowAnalyzer.exitClass()
}
}
containingClass = oldContainingClass
return (@Suppress("UNCHECKED_CAST")
result.compose())
}
override fun transformAnonymousObject(
anonymousObject: FirAnonymousObject,
data: ResolutionMode
): CompositeTransformResult {
if (anonymousObject !in context.targetedLocalClasses) {
return anonymousObject.runAllPhasesForLocalClass(transformer, components, data).compose()
}
dataFlowAnalyzer.enterClass()
val type = anonymousObject.defaultType()
if (anonymousObject.typeRef !is FirResolvedTypeRef) {
anonymousObject.resultType = buildResolvedTypeRef {
source = anonymousObject.source
this.type = type
}
}
val labelName =
if (anonymousObject.classKind == ClassKind.ENUM_ENTRY) {
anonymousObject.getPrimaryConstructorIfAny()?.symbol?.callableId?.className?.shortName()
} else null
var result = withScopesForClass(labelName, anonymousObject, type) {
transformDeclarationContent(anonymousObject, data).single as FirAnonymousObject
}
if (!implicitTypeOnly && result.controlFlowGraphReference == null) {
val graph = dataFlowAnalyzer.exitAnonymousObject(result)
result.replaceControlFlowGraphReference(FirControlFlowGraphReferenceImpl(graph))
} else {
dataFlowAnalyzer.exitClass()
}
return result.compose()
}
private fun transformAnonymousFunctionWithLambdaResolution(
anonymousFunction: FirAnonymousFunction, lambdaResolution: ResolutionMode.LambdaResolution
): FirAnonymousFunction {
val receiverTypeRef = anonymousFunction.receiverTypeRef
fun transform(): FirAnonymousFunction {
val expectedReturnType =
lambdaResolution.expectedReturnTypeRef ?: anonymousFunction.returnTypeRef.takeUnless { it is FirImplicitTypeRef }
val result = transformFunction(anonymousFunction, withExpectedType(expectedReturnType)).single as FirAnonymousFunction
val body = result.body
return if (result.returnTypeRef is FirImplicitTypeRef && body != null) {
result.transformReturnTypeRef(transformer, withExpectedType(body.resultType))
result
} else {
result
}
}
val label = anonymousFunction.label
return if (label != null || receiverTypeRef is FirResolvedTypeRef) {
withLabelAndReceiverType(label?.name?.let { Name.identifier(it) }, anonymousFunction, receiverTypeRef?.coneTypeSafe()) {
transform()
}
} else {
transform()
}
}
override fun transformSimpleFunction(
simpleFunction: FirSimpleFunction,
data: ResolutionMode
): CompositeTransformResult {
if (simpleFunction.resolvePhase == transformerPhase) return simpleFunction.compose()
if (simpleFunction.resolvePhase == FirResolvePhase.IMPLICIT_TYPES_BODY_RESOLVE && transformerPhase == FirResolvePhase.BODY_RESOLVE) {
simpleFunction.replaceResolvePhase(transformerPhase)
return simpleFunction.compose()
}
val returnTypeRef = simpleFunction.returnTypeRef
if ((returnTypeRef !is FirImplicitTypeRef) && implicitTypeOnly) {
return simpleFunction.compose()
}
if (context.containerIfAny !is FirClass<*>) {
context.storeFunction(simpleFunction)
}
return withTypeParametersOf(simpleFunction) {
val containingDeclaration = context.containerIfAny
if (containingDeclaration != null && containingDeclaration !is FirClass<*>) {
// For class members everything should be already prepared
prepareSignatureForBodyResolve(simpleFunction)
simpleFunction.transformStatus(this, simpleFunction.resolveStatus(simpleFunction.status).mode())
}
withFullBodyResolve {
val receiverTypeRef = simpleFunction.receiverTypeRef
if (receiverTypeRef != null) {
withLabelAndReceiverType(simpleFunction.name, simpleFunction, receiverTypeRef.coneType) {
transformFunctionWithGivenSignature(simpleFunction, ResolutionMode.ContextIndependent)
}
} else {
transformFunctionWithGivenSignature(simpleFunction, ResolutionMode.ContextIndependent)
}
}
}
}
private fun > transformFunctionWithGivenSignature(
function: F,
resolutionMode: ResolutionMode,
): CompositeTransformResult {
@Suppress("UNCHECKED_CAST")
val result = transformFunction(function, resolutionMode).single as F
val body = result.body
if (result.returnTypeRef is FirImplicitTypeRef) {
val simpleFunction = function as? FirSimpleFunction
if (body != null) {
result.transformReturnTypeRef(
transformer,
withExpectedType(
body.resultType.approximateTypeIfNeeded(simpleFunction?.visibility, simpleFunction?.isInline == true)
)
)
} else {
result.transformReturnTypeRef(
transformer,
withExpectedType(buildErrorTypeRef { diagnostic = ConeSimpleDiagnostic("empty body", DiagnosticKind.Other) })
)
}
}
return result.compose()
}
override fun > transformFunction(
function: FirFunction,
data: ResolutionMode
): CompositeTransformResult {
return withNewLocalScope {
val functionIsNotAnalyzed = transformerPhase != function.resolvePhase
if (functionIsNotAnalyzed) {
dataFlowAnalyzer.enterFunction(function)
}
@Suppress("UNCHECKED_CAST")
transformDeclarationContent(function, data).also {
if (functionIsNotAnalyzed) {
val result = it.single as FirFunction<*>
val controlFlowGraphReference = dataFlowAnalyzer.exitFunction(result)
result.replaceControlFlowGraphReference(controlFlowGraphReference)
}
} as CompositeTransformResult
}
}
override fun transformConstructor(constructor: FirConstructor, data: ResolutionMode): CompositeTransformResult {
if (implicitTypeOnly) return constructor.compose()
if (constructor.isPrimary && containingClass?.classKind == ClassKind.ANNOTATION_CLASS) {
return withFirArrayOfCallTransformer {
@Suppress("UNCHECKED_CAST")
doTransformConstructor(constructor, data)
}
}
@Suppress("UNCHECKED_CAST")
return doTransformConstructor(constructor, data)
}
private fun doTransformConstructor(constructor: FirConstructor, data: ResolutionMode): CompositeTransformResult {
return context.withContainer(constructor) {
constructor.replaceResolvePhase(transformerPhase)
dataFlowAnalyzer.enterFunction(constructor)
constructor.transformTypeParameters(transformer, data)
.transformAnnotations(transformer, data)
.transformReceiverTypeRef(transformer, data)
.transformReturnTypeRef(transformer, data)
val containers = context.containers
val owningClass = containers[containers.lastIndex - 1].safeAs()
/*
* Default values of constructor can't access members of constructing class
*/
context.withTowerDataContext(context.getTowerDataContextForConstructorResolution()) {
if (owningClass != null && !constructor.isPrimary) {
context.addReceiver(
null,
InaccessibleImplicitReceiverValue(
owningClass.symbol,
owningClass.defaultType(),
session,
scopeSession
)
)
}
withNewLocalScope {
constructor.transformValueParameters(transformer, data)
}
}
val scopeWithValueParameters = if (constructor.isPrimary) {
context.getPrimaryConstructorParametersScope()
} else {
constructor.scopeWithParameters()
}
/*
* Delegated constructor call is called before constructor body, so we need to
* analyze it before body, so body can access smartcasts from that call
*/
context.withTowerDataCleanup {
addLocalScope(scopeWithValueParameters)
constructor.transformDelegatedConstructor(transformer, data)
}
if (constructor.body != null) {
if (constructor.isPrimary) {
/*
* Primary constructor may have body only if class delegates implementation to some property
* In it's body we don't have this receiver for building class, so we need to use
* special towerDataContext
*/
context.withTowerDataContext(context.getTowerDataContextForConstructorResolution()) {
addLocalScope(scopeWithValueParameters)
constructor.transformBody(transformer, data)
}
} else {
withLocalScopeCleanup {
addLocalScope(scopeWithValueParameters)
constructor.transformBody(transformer, data)
}
}
}
val controlFlowGraphReference = dataFlowAnalyzer.exitFunction(constructor)
constructor.replaceControlFlowGraphReference(controlFlowGraphReference)
constructor.compose()
}
}
override fun transformAnonymousInitializer(
anonymousInitializer: FirAnonymousInitializer,
data: ResolutionMode
): CompositeTransformResult {
if (implicitTypeOnly) return anonymousInitializer.compose()
return withLocalScopeCleanup {
dataFlowAnalyzer.enterInitBlock(anonymousInitializer)
addLocalScope(context.getPrimaryConstructorParametersScope())
addNewLocalScope()
val result =
transformDeclarationContent(anonymousInitializer, ResolutionMode.ContextIndependent).single as FirAnonymousInitializer
val graph = dataFlowAnalyzer.exitInitBlock(result)
result.replaceControlFlowGraphReference(FirControlFlowGraphReferenceImpl(graph))
result.compose()
}
}
override fun transformValueParameter(valueParameter: FirValueParameter, data: ResolutionMode): CompositeTransformResult {
context.storeVariable(valueParameter)
if (valueParameter.returnTypeRef is FirImplicitTypeRef) {
valueParameter.replaceResolvePhase(transformerPhase)
return valueParameter.compose()
}
dataFlowAnalyzer.enterValueParameter(valueParameter)
val transformedValueParameter =
valueParameter.transformInitializer(integerLiteralTypeApproximator, valueParameter.returnTypeRef.coneType)
val result = transformDeclarationContent(
transformedValueParameter,
withExpectedType(transformedValueParameter.returnTypeRef)
).single as FirValueParameter
dataFlowAnalyzer.exitValueParameter(result)?.let { graph ->
result.replaceControlFlowGraphReference(FirControlFlowGraphReferenceImpl(graph))
}
return result.compose()
}
override fun transformAnonymousFunction(
anonymousFunction: FirAnonymousFunction,
data: ResolutionMode
): CompositeTransformResult {
// Either ContextDependent, ContextIndependent or WithExpectedType could be here
if (data !is ResolutionMode.LambdaResolution) {
anonymousFunction.transformReturnTypeRef(transformer, ResolutionMode.ContextIndependent)
anonymousFunction.transformReceiverTypeRef(transformer, ResolutionMode.ContextIndependent)
anonymousFunction.valueParameters.forEach { it.transformReturnTypeRef(transformer, ResolutionMode.ContextIndependent) }
context.saveContextForAnonymousFunction(anonymousFunction)
}
return when (data) {
ResolutionMode.ContextDependent -> {
dataFlowAnalyzer.visitPostponedAnonymousFunction(anonymousFunction)
anonymousFunction.addReturn().compose()
}
is ResolutionMode.LambdaResolution -> {
transformAnonymousFunctionWithLambdaResolution(anonymousFunction, data).addReturn().compose()
}
is ResolutionMode.WithExpectedType, is ResolutionMode.ContextIndependent -> {
val expectedTypeRef = (data as? ResolutionMode.WithExpectedType)?.expectedTypeRef ?: buildImplicitTypeRef()
val resolvedLambdaAtom = (expectedTypeRef as? FirResolvedTypeRef)?.let {
extractLambdaInfoFromFunctionalType(
it.type, it, anonymousFunction, returnTypeVariable = null, components, candidate = null
)
}
var af = anonymousFunction
val valueParameters =
if (resolvedLambdaAtom == null) af.valueParameters
else {
val singleParameterType = resolvedLambdaAtom.parameters.singleOrNull()
val itParam = when {
af.valueParameters.isEmpty() && singleParameterType != null -> {
val name = Name.identifier("it")
buildValueParameter {
session = [email protected]
origin = FirDeclarationOrigin.Source
returnTypeRef = buildResolvedTypeRef { type = singleParameterType }
this.name = name
symbol = FirVariableSymbol(name)
isCrossinline = false
isNoinline = false
isVararg = false
}
}
else -> null
}
if (itParam != null) {
listOf(itParam)
} else {
af.valueParameters.mapIndexed { index, param ->
if (param.returnTypeRef is FirResolvedTypeRef) {
param
} else {
param.transformReturnTypeRef(
StoreType,
param.returnTypeRef.resolvedTypeFromPrototype(
resolvedLambdaAtom.parameters[index]
)
)
param
}
}
}
}
val returnTypeRefFromResolvedAtom = resolvedLambdaAtom?.returnType?.let { af.returnTypeRef.resolvedTypeFromPrototype(it) }
af = af.copy(
receiverTypeRef = af.receiverTypeRef?.takeIf { it !is FirImplicitTypeRef }
?: resolvedLambdaAtom?.receiver?.let { af.receiverTypeRef?.resolvedTypeFromPrototype(it) },
valueParameters = valueParameters,
returnTypeRef = (af.returnTypeRef as? FirResolvedTypeRef)
?: returnTypeRefFromResolvedAtom
?: af.returnTypeRef
)
af = af.transformValueParameters(ImplicitToErrorTypeTransformer, null)
val bodyExpectedType = returnTypeRefFromResolvedAtom ?: expectedTypeRef
val labelName = af.label?.name?.let { Name.identifier(it) }
withLabelAndReceiverType(labelName, af, af.receiverTypeRef?.coneType) {
af = transformFunction(af, withExpectedType(bodyExpectedType)).single as FirAnonymousFunction
}
// To separate function and separate commit
val writer = FirCallCompletionResultsWriterTransformer(
session,
ConeSubstitutor.Empty,
components.returnTypeCalculator,
inferenceComponents.approximator,
integerOperatorsTypeUpdater,
integerLiteralTypeApproximator
)
af.transformSingle(writer, expectedTypeRef.coneTypeSafe()?.toExpectedType())
val returnTypes = dataFlowAnalyzer.returnExpressionsOfAnonymousFunction(af)
.mapNotNull { (it as? FirExpression)?.resultType?.coneType }
af.replaceReturnTypeRef(
af.returnTypeRef.resolvedTypeFromPrototype(
inferenceComponents.ctx.commonSuperTypeOrNull(returnTypes) ?: session.builtinTypes.unitType.type
)
)
af.replaceTypeRef(af.constructFunctionalTypeRef())
af.addReturn().compose()
}
is ResolutionMode.WithStatus -> {
throw AssertionError("Should not be here in WithStatus mode")
}
}
}
private fun FirAnonymousFunction.addReturn(): FirAnonymousFunction {
// If this lambda's resolved, expected return type is Unit, we don't need an explicit return statement.
// During conversion (to backend IR), the last expression will be coerced to Unit if needed.
// As per KT-41005, we should not force coercion to Unit for nullable return type, though.
if (returnTypeRef.isUnit && body?.typeRef?.isMarkedNullable == false) {
return this
}
val lastStatement = body?.statements?.lastOrNull()
val returnType = (body?.typeRef as? FirResolvedTypeRef) ?: return this
val returnNothing = returnType.isNothing || returnType.isUnit
if (lastStatement is FirExpression && !returnNothing) {
body?.transformChildren(
object : FirDefaultTransformer() {
override fun transformElement(element: E, data: FirExpression): CompositeTransformResult {
if (element == lastStatement) {
val returnExpression = buildReturnExpression {
source = element.source?.fakeElement(FirFakeSourceElementKind.ImplicitReturn)
result = lastStatement
target = FirFunctionTarget(null, isLambda = [email protected] ).also {
it.bind(this@addReturn)
}
}
@Suppress("UNCHECKED_CAST")
return (returnExpression as E).compose()
}
return element.compose()
}
override fun transformReturnExpression(
returnExpression: FirReturnExpression,
data: FirExpression
): CompositeTransformResult {
return returnExpression.compose()
}
},
buildUnitExpression()
)
}
return this
}
private inline fun withScopesForClass(
labelName: Name?,
owner: FirClass<*>,
type: ConeKotlinType,
block: () -> T
): T = context.withTowerDataCleanup {
val towerElementsForClass = components.collectTowerDataElementsForClass(owner, type)
val staticsAndCompanion =
context.towerDataContext
.addNonLocalTowerDataElements(towerElementsForClass.superClassesStaticsAndCompanionReceivers)
.run {
if (towerElementsForClass.companionReceiver != null)
addReceiver(null, towerElementsForClass.companionReceiver)
else
this
}
.addNonLocalScopeIfNotNull(towerElementsForClass.companionStaticScope)
.addNonLocalScopeIfNotNull(towerElementsForClass.staticScope)
val typeParameterScope = (owner as? FirRegularClass)?.let(this::createTypeParameterScope)
val forMembersResolution =
staticsAndCompanion
.addReceiver(labelName, towerElementsForClass.thisReceiver)
.addNonLocalScopeIfNotNull(typeParameterScope)
val scopeForConstructorHeader =
staticsAndCompanion.addNonLocalScopeIfNotNull(typeParameterScope)
val newTowerDataContextForStaticNestedClasses =
if ((owner as? FirRegularClass)?.classKind?.isSingleton == true)
forMembersResolution
else
staticsAndCompanion
val constructor = (owner as? FirRegularClass)?.declarations?.firstOrNull { it is FirConstructor } as? FirConstructor
val primaryConstructorParametersScope =
if (constructor?.isPrimary == true) {
constructor.scopeWithParameters()
} else null
components.context.replaceTowerDataContext(forMembersResolution)
val newContexts =
FirTowerDataContextsForClassParts(
newTowerDataContextForStaticNestedClasses,
scopeForConstructorHeader,
primaryConstructorParametersScope
)
context.withNewTowerDataForClassParts(newContexts) {
block()
}
}
private fun FirConstructor.scopeWithParameters(): FirLocalScope {
return valueParameters.fold(FirLocalScope()) { acc, param -> acc.storeVariable(param) }
}
protected inline fun withLabelAndReceiverType(
labelName: Name?,
owner: FirCallableDeclaration<*>,
type: ConeKotlinType?,
block: () -> T
): T = context.withTowerDataCleanup {
if (type != null) {
val receiver = ImplicitExtensionReceiverValue(
owner.symbol,
type,
components.session,
components.scopeSession
)
context.addReceiver(labelName, receiver)
}
block()
}
private fun storeVariableReturnType(variable: FirVariable<*>) {
val initializer = variable.initializer
if (variable.returnTypeRef is FirImplicitTypeRef) {
when {
initializer != null -> {
val expectedType = when (val resultType = initializer.resultType) {
is FirImplicitTypeRef -> buildErrorTypeRef {
diagnostic = ConeSimpleDiagnostic("No result type for initializer", DiagnosticKind.InferenceError)
}
else -> {
buildResolvedTypeRef {
type = resultType.coneType
annotations.addAll(resultType.annotations)
resultType.source?.fakeElement(FirFakeSourceElementKind.PropertyFromParameter)?.let {
source = it
}
}
}
}
variable.transformReturnTypeRef(
transformer,
withExpectedType(expectedType.approximateTypeIfNeeded((variable as? FirProperty)?.visibility))
)
}
variable.getter != null && variable.getter !is FirDefaultPropertyAccessor -> {
val expectedType = when (val resultType = variable.getter?.returnTypeRef) {
is FirImplicitTypeRef -> buildErrorTypeRef {
diagnostic = ConeSimpleDiagnostic("No result type for getter", DiagnosticKind.InferenceError)
}
else -> {
resultType?.let {
buildResolvedTypeRef {
type = resultType.coneType
annotations.addAll(resultType.annotations)
resultType.source?.fakeElement(FirFakeSourceElementKind.PropertyFromParameter)?.let {
source = it
}
}
}
}
}
variable.transformReturnTypeRef(
transformer,
withExpectedType(expectedType?.approximateTypeIfNeeded((variable as? FirProperty)?.visibility))
)
}
else -> {
variable.transformReturnTypeRef(
transformer,
withExpectedType(
buildErrorTypeRef {
diagnostic = ConeSimpleDiagnostic(
"Cannot infer variable type without initializer / getter / delegate",
DiagnosticKind.InferenceError,
)
},
)
)
}
}
if (variable.getter?.returnTypeRef is FirImplicitTypeRef) {
variable.getter?.transformReturnTypeRef(transformer, withExpectedType(variable.returnTypeRef))
}
}
}
private fun FirTypeRef.approximateTypeIfNeeded(
containingCallableVisibility: Visibility?,
isInlineFunction: Boolean = false
): FirTypeRef {
val approximatedType = if (this is FirResolvedTypeRef &&
(containingCallableVisibility == Public || containingCallableVisibility == Protected)
) {
when (this.type) {
is ConeIntegerLiteralType,
is ConeCapturedType,
is ConeDefinitelyNotNullType,
is ConeIntersectionType -> {
this.withReplacedConeType(
inferenceComponents.approximator.approximateToSuperType(
this.type, TypeApproximatorConfiguration.PublicDeclaration
) as ConeKotlinType
)
}
else -> {
this
}
}
} else {
this
}
return approximatedType.hideLocalTypeIfNeeded(containingCallableVisibility, isInlineFunction)
}
/*
* Suppose a function without an explicit return type just returns an anonymous object:
*
* fun foo(...) = object : ObjectSuperType {
* override fun ...
* }
*
* Without unwrapping, the return type ended up with that anonymous object (), while the resolved super type, which
* acts like an implementing interface, is a better fit. In fact, exposing an anonymous object types is prohibited for certain cases,
* e.g., KT-33917. We can also apply this to any local types.
*/
private fun FirTypeRef.hideLocalTypeIfNeeded(
containingCallableVisibility: Visibility?,
isInlineFunction: Boolean = false
): FirTypeRef {
if (containingCallableVisibility == null) {
return this
}
// Approximate types for non-private (all but package private or private) members.
// Also private inline functions, as per KT-33917.
if (containingCallableVisibility == Public ||
containingCallableVisibility == Protected ||
containingCallableVisibility == Internal ||
(containingCallableVisibility == Private && isInlineFunction)
) {
val firClass =
(((this as? FirResolvedTypeRef)
?.type as? ConeClassLikeType)
?.lookupTag as? ConeClassLookupTagWithFixedSymbol)
?.symbol?.fir
if (firClass?.classId?.isLocal != true) {
return this
}
if (firClass.superTypeRefs.size > 1) {
return buildErrorTypeRef {
diagnostic = ConeSimpleDiagnostic("Cannot hide local type ${firClass.render()}")
}
}
val superType = firClass.superTypeRefs.single()
if (superType is FirResolvedTypeRef && !superType.isAny) {
return superType
}
}
return this
}
private object ImplicitToErrorTypeTransformer : FirTransformer() {
override fun transformElement(element: E, data: Nothing?): CompositeTransformResult {
return element.compose()
}
override fun transformValueParameter(valueParameter: FirValueParameter, data: Nothing?): CompositeTransformResult {
if (valueParameter.returnTypeRef is FirImplicitTypeRef) {
valueParameter.transformReturnTypeRef(
StoreType,
valueParameter.returnTypeRef.resolvedTypeFromPrototype(
ConeKotlinErrorType(ConeSimpleDiagnostic("No type for parameter", DiagnosticKind.NoTypeForTypeParameter))
)
)
}
return valueParameter.compose()
}
}
}