[FIR] Add ir support
This commit is contained in:
committed by
TeamCityServer
parent
8b918e12b2
commit
79ceaf03bf
+10
-3
@@ -699,6 +699,7 @@ class Fir2IrDeclarationStorage(
|
||||
|
||||
private val FirProperty.fieldVisibility: Visibility
|
||||
get() = when {
|
||||
hasExplicitBackingField -> backingField?.visibility ?: status.visibility
|
||||
isLateInit -> setter?.visibility ?: status.visibility
|
||||
isConst -> status.visibility
|
||||
hasJvmFieldAnnotation -> status.visibility
|
||||
@@ -798,7 +799,6 @@ class Fir2IrDeclarationStorage(
|
||||
parent = irParent
|
||||
}
|
||||
val type = property.returnTypeRef.toIrType()
|
||||
val initializer = property.initializer
|
||||
val delegate = property.delegate
|
||||
val getter = property.getter
|
||||
val setter = property.setter
|
||||
@@ -810,14 +810,21 @@ class Fir2IrDeclarationStorage(
|
||||
Name.identifier("${property.name}\$delegate"), true, delegate
|
||||
)
|
||||
} else {
|
||||
val initializer = property.backingField?.initializer ?: property.initializer
|
||||
// There are cases when we get here for properties
|
||||
// that have no backing field. For example, in the
|
||||
// funExpression.kt test there's an attempt
|
||||
// to access the `javaClass` property of the `foo0`'s
|
||||
// `block` argument
|
||||
val typeToUse = property.backingField?.returnTypeRef?.toIrType() ?: type
|
||||
createBackingField(
|
||||
property, IrDeclarationOrigin.PROPERTY_BACKING_FIELD,
|
||||
components.visibilityConverter.convertToDescriptorVisibility(property.fieldVisibility),
|
||||
property.name, property.isVal, initializer, type
|
||||
property.name, property.isVal, initializer, typeToUse
|
||||
).also { field ->
|
||||
if (initializer is FirConstExpression<*>) {
|
||||
// TODO: Normally we shouldn't have error type here
|
||||
val constType = initializer.typeRef.toIrType().takeIf { it !is IrErrorType } ?: type
|
||||
val constType = initializer.typeRef.toIrType().takeIf { it !is IrErrorType } ?: typeToUse
|
||||
field.initializer = factory.createExpressionBody(initializer.toIrConst(constType))
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -158,7 +158,7 @@ internal class ClassMemberGenerator(
|
||||
}
|
||||
|
||||
fun convertPropertyContent(irProperty: IrProperty, property: FirProperty, containingClass: FirClass?): IrProperty {
|
||||
val initializer = property.initializer
|
||||
val initializer = property.backingField?.initializer ?: property.initializer
|
||||
val delegate = property.delegate
|
||||
val propertyType = property.returnTypeRef.toIrType()
|
||||
irProperty.initializeBackingField(property, initializerExpression = initializer ?: delegate)
|
||||
|
||||
@@ -29,6 +29,8 @@ import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedContainerSource
|
||||
import org.jetbrains.kotlin.fir.backend.*
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.*
|
||||
import org.jetbrains.kotlin.fir.expressions.FirExpression
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpressionBody
|
||||
import org.jetbrains.kotlin.ir.symbols.IrPropertySymbol
|
||||
|
||||
class Fir2IrLazyProperty(
|
||||
@@ -88,6 +90,16 @@ class Fir2IrLazyProperty(
|
||||
with(typeConverter) { fir.returnTypeRef.toIrType() }
|
||||
}
|
||||
|
||||
private fun toIrInitializer(initializer: FirExpression?): IrExpressionBody? {
|
||||
return if (initializer is FirConstExpression<*>) {
|
||||
// TODO: Normally we shouldn't have error type here
|
||||
val constType = with(typeConverter) { initializer.typeRef.toIrType().takeIf { it !is IrErrorType } ?: type }
|
||||
factory.createExpressionBody(initializer.toIrConst(constType))
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ObsoleteDescriptorBasedAPI::class)
|
||||
override var backingField: IrField? by lazyVar(lock) {
|
||||
// TODO: this checks are very preliminary, FIR resolve should determine backing field presence itself
|
||||
@@ -96,6 +108,26 @@ class Fir2IrLazyProperty(
|
||||
!fir.isConst && (fir.modality == Modality.ABSTRACT || parent is IrClass && parent.isInterface) -> {
|
||||
null
|
||||
}
|
||||
fir.hasExplicitBackingField -> {
|
||||
with(declarationStorage) {
|
||||
val backingFieldType = with(typeConverter) {
|
||||
fir.backingField?.returnTypeRef?.toIrType()
|
||||
}
|
||||
val initializer = fir.backingField?.initializer ?: fir.initializer
|
||||
val visibility = fir.backingField?.visibility ?: fir.visibility
|
||||
createBackingField(
|
||||
fir,
|
||||
IrDeclarationOrigin.PROPERTY_BACKING_FIELD,
|
||||
components.visibilityConverter.convertToDescriptorVisibility(visibility),
|
||||
fir.name,
|
||||
fir.isVal,
|
||||
initializer,
|
||||
backingFieldType
|
||||
).also { field ->
|
||||
field.initializer = toIrInitializer(initializer)
|
||||
}
|
||||
}
|
||||
}
|
||||
fir.initializer != null || fir.getter is FirDefaultPropertyGetter || fir.isVar && fir.setter is FirDefaultPropertySetter -> {
|
||||
with(declarationStorage) {
|
||||
createBackingField(
|
||||
@@ -103,12 +135,7 @@ class Fir2IrLazyProperty(
|
||||
components.visibilityConverter.convertToDescriptorVisibility(fir.visibility), fir.name, fir.isVal, fir.initializer,
|
||||
type
|
||||
).also { field ->
|
||||
val initializer = fir.initializer
|
||||
if (initializer is FirConstExpression<*>) {
|
||||
// TODO: Normally we shouldn't have error type here
|
||||
val constType = with(typeConverter) { initializer.typeRef.toIrType().takeIf { it !is IrErrorType } ?: type }
|
||||
field.initializer = factory.createExpressionBody(initializer.toIrConst(constType))
|
||||
}
|
||||
field.initializer = toIrInitializer(fir.initializer)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.fir
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.fir.declarations.*
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.hasExplicitBackingField
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.isInner
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.isReferredViaField
|
||||
import org.jetbrains.kotlin.fir.diagnostics.ConeDiagnostic
|
||||
@@ -44,6 +45,7 @@ import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind
|
||||
import org.jetbrains.kotlin.resolve.calls.tower.CandidateApplicability
|
||||
import org.jetbrains.kotlin.resolve.calls.tower.isSuccess
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
|
||||
class FirCallResolver(
|
||||
private val components: FirAbstractBodyResolveTransformer.BodyResolveTransformerComponents,
|
||||
@@ -727,6 +729,11 @@ class FirCallResolver(
|
||||
resolvedSymbol = coneSymbol
|
||||
}
|
||||
}
|
||||
if (coneSymbol.safeAs<FirPropertySymbol>()?.hasExplicitBackingField == true) {
|
||||
return FirPropertyWithExplicitBackingFieldResolvedNamedReference(
|
||||
source, name, candidate.symbol, candidate.hasVisibleBackingField
|
||||
)
|
||||
}
|
||||
/*
|
||||
* This `if` is an optimization for local variables and properties without type parameters
|
||||
* Since they have no type variables, so we can don't run completion on them at all and create
|
||||
|
||||
@@ -18,11 +18,13 @@ import org.jetbrains.kotlin.fir.resolve.calls.FirSyntheticFunctionSymbol
|
||||
import org.jetbrains.kotlin.fir.resolve.calls.ReceiverValue
|
||||
import org.jetbrains.kotlin.fir.symbols.ConeClassLikeLookupTag
|
||||
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirBackingFieldSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.*
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.types.AbstractTypeChecker
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
|
||||
abstract class FirModuleVisibilityChecker : FirSessionComponent {
|
||||
abstract fun <T> isInFriendModule(declaration: T): Boolean where T : FirMemberDeclaration, T : FirDeclaration
|
||||
@@ -51,6 +53,23 @@ abstract class FirVisibilityChecker : FirSessionComponent {
|
||||
}
|
||||
}
|
||||
|
||||
private fun FirMemberDeclaration.getBackingFieldIfApplicable(): FirBackingField? {
|
||||
val field = this.safeAs<FirProperty>()?.getExplicitBackingField()
|
||||
?: return null
|
||||
|
||||
// This check prevents resolving protected and
|
||||
// public fields.
|
||||
if (
|
||||
field.visibility == Visibilities.PrivateToThis ||
|
||||
field.visibility == Visibilities.Private ||
|
||||
field.visibility == Visibilities.Internal
|
||||
) {
|
||||
return field
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
fun isVisible(
|
||||
declaration: FirMemberDeclaration,
|
||||
candidate: Candidate
|
||||
@@ -71,7 +90,20 @@ abstract class FirVisibilityChecker : FirSessionComponent {
|
||||
return true
|
||||
}
|
||||
|
||||
return isVisible(declaration, session, useSiteFile, containingDeclarations, candidate.dispatchReceiverValue)
|
||||
val visible = isVisible(declaration, session, useSiteFile, containingDeclarations, candidate.dispatchReceiverValue)
|
||||
val backingField = declaration.getBackingFieldIfApplicable()
|
||||
|
||||
if (visible && backingField != null) {
|
||||
candidate.hasVisibleBackingField = isVisible(
|
||||
backingField,
|
||||
session,
|
||||
useSiteFile,
|
||||
containingDeclarations,
|
||||
candidate.dispatchReceiverValue,
|
||||
)
|
||||
}
|
||||
|
||||
return visible
|
||||
}
|
||||
|
||||
fun isVisible(
|
||||
@@ -277,6 +309,7 @@ val FirSession.visibilityChecker: FirVisibilityChecker by FirSession.sessionComp
|
||||
|
||||
fun FirBasedSymbol<*>.getOwnerLookupTag(): ConeClassLikeLookupTag? {
|
||||
return when (this) {
|
||||
is FirBackingFieldSymbol -> fir.propertySymbol.getOwnerLookupTag()
|
||||
is FirClassLikeSymbol<*> -> {
|
||||
if (classId.isLocal) {
|
||||
(fir as? FirRegularClass)?.containingClassForLocal()
|
||||
|
||||
@@ -11,7 +11,9 @@ import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.fir.*
|
||||
import org.jetbrains.kotlin.fir.declarations.*
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.canNarrowDownGetterType
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.expandedConeType
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.isFinal
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.isInner
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.isLocal
|
||||
import org.jetbrains.kotlin.fir.diagnostics.ConeDiagnostic
|
||||
@@ -187,6 +189,30 @@ internal fun typeForQualifierByDeclaration(declaration: FirDeclaration, resultTy
|
||||
return null
|
||||
}
|
||||
|
||||
private fun FirPropertyWithExplicitBackingFieldResolvedNamedReference.getNarrowedDownSymbol(): FirBasedSymbol<*> {
|
||||
val propertyReceiver = resolvedSymbol.safeAs<FirPropertySymbol>()
|
||||
?: return resolvedSymbol
|
||||
|
||||
// This can happen in case of 2 properties referencing
|
||||
// each other recursively. See: Jet81.fir.kt
|
||||
if (
|
||||
propertyReceiver.fir.returnTypeRef is FirImplicitTypeRef ||
|
||||
propertyReceiver.fir.backingField?.returnTypeRef is FirImplicitTypeRef
|
||||
) {
|
||||
return resolvedSymbol
|
||||
}
|
||||
|
||||
if (
|
||||
propertyReceiver.isFinal &&
|
||||
hasVisibleBackingField &&
|
||||
propertyReceiver.canNarrowDownGetterType
|
||||
) {
|
||||
return propertyReceiver.fir.backingField?.symbol ?: resolvedSymbol
|
||||
}
|
||||
|
||||
return resolvedSymbol
|
||||
}
|
||||
|
||||
fun <T : FirResolvable> BodyResolveComponents.typeFromCallee(access: T): FirResolvedTypeRef {
|
||||
return when (val newCallee = access.calleeReference) {
|
||||
is FirErrorNamedReference ->
|
||||
@@ -198,16 +224,8 @@ fun <T : FirResolvable> BodyResolveComponents.typeFromCallee(access: T): FirReso
|
||||
typeFromSymbol(newCallee.candidateSymbol, false)
|
||||
}
|
||||
is FirPropertyWithExplicitBackingFieldResolvedNamedReference -> {
|
||||
val backingField = newCallee.resolvedSymbol
|
||||
.safeAs<FirPropertySymbol>()
|
||||
?.fir
|
||||
?.backingField
|
||||
|
||||
if (newCallee.hasVisibleBackingField && backingField != null) {
|
||||
typeFromSymbol(backingField.symbol, false)
|
||||
} else {
|
||||
typeFromSymbol(newCallee.resolvedSymbol, false)
|
||||
}
|
||||
val symbol = newCallee.getNarrowedDownSymbol()
|
||||
typeFromSymbol(symbol, false)
|
||||
}
|
||||
is FirResolvedNamedReference -> {
|
||||
typeFromSymbol(newCallee.resolvedSymbol, false)
|
||||
|
||||
@@ -145,6 +145,8 @@ class Candidate(
|
||||
fun extensionReceiverExpression(): FirExpression =
|
||||
extensionReceiverValue?.receiverExpression?.takeIf { it !is FirExpressionStub } ?: FirNoReceiverExpression
|
||||
|
||||
var hasVisibleBackingField = false
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (javaClass != other?.javaClass) return false
|
||||
|
||||
+18
@@ -8,8 +8,11 @@ package org.jetbrains.kotlin.fir.resolve.calls
|
||||
import org.jetbrains.kotlin.fir.FirImplementationDetail
|
||||
import org.jetbrains.kotlin.fir.FirSourceElement
|
||||
import org.jetbrains.kotlin.fir.diagnostics.ConeDiagnostic
|
||||
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
|
||||
import org.jetbrains.kotlin.fir.references.impl.FirSimpleNamedReference
|
||||
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
|
||||
import org.jetbrains.kotlin.fir.visitors.FirTransformer
|
||||
import org.jetbrains.kotlin.fir.visitors.FirVisitor
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
@OptIn(FirImplementationDetail::class)
|
||||
@@ -32,3 +35,18 @@ class FirErrorReferenceWithCandidate(
|
||||
) : FirNamedReferenceWithCandidate(source, name, candidate) {
|
||||
override val isError: Boolean get() = true
|
||||
}
|
||||
|
||||
class FirPropertyWithExplicitBackingFieldResolvedNamedReference(
|
||||
override val source: FirSourceElement?,
|
||||
override val name: Name,
|
||||
override val resolvedSymbol: FirBasedSymbol<*>,
|
||||
val hasVisibleBackingField: Boolean,
|
||||
) : FirResolvedNamedReference() {
|
||||
override val candidateSymbol: FirBasedSymbol<*>? get() = null
|
||||
|
||||
override fun <R, D> acceptChildren(visitor: FirVisitor<R, D>, data: D) {}
|
||||
|
||||
override fun <D> transformChildren(transformer: FirTransformer<D>, data: D): FirPropertyWithExplicitBackingFieldResolvedNamedReference {
|
||||
return this
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,11 +69,6 @@ open class ExpressionReceiverValue(
|
||||
}
|
||||
}
|
||||
|
||||
class NarrowedExpressionReceiverValue(
|
||||
explicitReceiver: FirExpression,
|
||||
override val type: ConeKotlinType,
|
||||
) : ExpressionReceiverValue(explicitReceiver)
|
||||
|
||||
sealed class ImplicitReceiverValue<S : FirBasedSymbol<*>>(
|
||||
val boundSymbol: S,
|
||||
type: ConeKotlinType,
|
||||
|
||||
+1
-66
@@ -5,34 +5,21 @@
|
||||
|
||||
package org.jetbrains.kotlin.fir.resolve.calls.tower
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||
import org.jetbrains.kotlin.fir.asReversedFrozen
|
||||
import org.jetbrains.kotlin.fir.containingClass
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.canNarrowDownGetterType
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.isFinal
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.visibility
|
||||
import org.jetbrains.kotlin.fir.expressions.FirExpression
|
||||
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression
|
||||
import org.jetbrains.kotlin.fir.expressions.FirResolvedQualifier
|
||||
import org.jetbrains.kotlin.fir.expressions.builder.buildExpressionStub
|
||||
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
|
||||
import org.jetbrains.kotlin.fir.resolve.BodyResolveComponents
|
||||
import org.jetbrains.kotlin.fir.resolve.DoubleColonLHS
|
||||
import org.jetbrains.kotlin.fir.resolve.FirTowerDataContext
|
||||
import org.jetbrains.kotlin.fir.resolve.calls.*
|
||||
import org.jetbrains.kotlin.fir.resolve.toSymbol
|
||||
import org.jetbrains.kotlin.fir.scopes.FirScope
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
|
||||
import org.jetbrains.kotlin.fir.types.ConeKotlinType
|
||||
import org.jetbrains.kotlin.fir.types.FirImplicitTypeRef
|
||||
import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef
|
||||
import org.jetbrains.kotlin.fir.types.coneType
|
||||
import org.jetbrains.kotlin.fir.types.impl.FirImplicitBuiltinTypeRef
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.HIDES_MEMBERS_NAME_LIST
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
|
||||
|
||||
internal class TowerDataElementsForName(
|
||||
name: Name,
|
||||
@@ -236,64 +223,12 @@ internal open class FirTowerResolveTask(
|
||||
)
|
||||
}
|
||||
|
||||
private fun FirPropertySymbol.hasAccessibleBackingField(info: CallInfo): Boolean {
|
||||
val receiverContainer = containingClass()?.toSymbol(info.session)
|
||||
|
||||
if (!this.isFinal) {
|
||||
return false
|
||||
}
|
||||
|
||||
return when (fir.backingField?.visibility) {
|
||||
Visibilities.Private -> {
|
||||
info.containingDeclarations.any {
|
||||
it.symbol == receiverContainer
|
||||
}
|
||||
}
|
||||
Visibilities.Internal -> {
|
||||
receiverContainer?.moduleData == info.containingFile.moduleData
|
||||
}
|
||||
else -> {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun FirExpression.getNarrowedDownReturnType(info: CallInfo): ConeKotlinType? {
|
||||
val propertyReceiver = this.safeAs<FirQualifiedAccessExpression>()
|
||||
?.calleeReference
|
||||
?.safeAs<FirResolvedNamedReference>()
|
||||
?.resolvedSymbol
|
||||
?.safeAs<FirPropertySymbol>()
|
||||
?: return null
|
||||
|
||||
// This can happen in case of 2 properties referencing
|
||||
// each other recursively. See: Jet81.fir.kt
|
||||
if (
|
||||
propertyReceiver.fir.returnTypeRef is FirImplicitTypeRef ||
|
||||
propertyReceiver.fir.backingField?.returnTypeRef is FirImplicitTypeRef
|
||||
) {
|
||||
return null
|
||||
}
|
||||
|
||||
if (propertyReceiver.hasAccessibleBackingField(info) && propertyReceiver.canNarrowDownGetterType) {
|
||||
return propertyReceiver.fir.backingField?.returnTypeRef?.coneType
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
suspend fun runResolverForExpressionReceiver(
|
||||
info: CallInfo,
|
||||
receiver: FirExpression,
|
||||
parentGroup: TowerGroup = TowerGroup.EmptyRoot
|
||||
) {
|
||||
val narrowedType = receiver.getNarrowedDownReturnType(info)
|
||||
|
||||
val explicitReceiverValue = if (narrowedType != null) {
|
||||
NarrowedExpressionReceiverValue(receiver, narrowedType)
|
||||
} else {
|
||||
ExpressionReceiverValue(receiver)
|
||||
}
|
||||
val explicitReceiverValue = ExpressionReceiverValue(receiver)
|
||||
|
||||
processExtensionsThatHideMembers(info, explicitReceiverValue, parentGroup)
|
||||
|
||||
|
||||
+3
@@ -29,6 +29,9 @@ class FirProviderImpl(val session: FirSession, val kotlinScopeProvider: FirKotli
|
||||
symbol.originalIfFakeOverride()?.let {
|
||||
return getFirCallableContainerFile(it)
|
||||
}
|
||||
if (symbol is FirBackingFieldSymbol) {
|
||||
return getFirCallableContainerFile(symbol.fir.propertySymbol)
|
||||
}
|
||||
if (symbol is FirAccessorSymbol) {
|
||||
val fir = symbol.fir
|
||||
if (fir is FirSyntheticProperty) {
|
||||
|
||||
Reference in New Issue
Block a user