in compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/generators/Fir2IrCallableDeclarationsGenerator.kt [218:366]
fun createIrProperty(
property: FirProperty,
irParent: IrDeclarationParent?,
symbols: PropertySymbols,
predefinedOrigin: IrDeclarationOrigin? = null,
fakeOverrideOwnerLookupTag: ConeClassLikeLookupTag? = null,
allowLazyDeclarationsCreation: Boolean
): IrProperty = convertCatching(property) {
val origin = when {
!predefinedOrigin.isExternal &&
property.isStatic &&
property.name in Fir2IrDeclarationStorage.ENUM_SYNTHETIC_NAMES
-> IrDeclarationOrigin.ENUM_CLASS_SPECIAL_MEMBER
else -> property.computeIrOrigin(
predefinedOrigin,
parentOrigin = (irParent as? IrDeclaration)?.origin,
fakeOverrideOwnerLookupTag
)
}
// See similar comments in createIrFunction above
val parentIsExternal = irParent.isExternalParent()
if (parentIsExternal) {
if (!allowLazyDeclarationsCreation) {
error("Lazy properties should be processed in Fir2IrDeclarationStorage: ${property.render()}")
}
@OptIn(UnsafeDuringIrConstructionAPI::class)
if (symbols.propertySymbol.isBound) return symbols.propertySymbol.owner
// For private functions signature is null, fallback to non-lazy property
return lazyDeclarationsGenerator.createIrLazyProperty(property, irParent, symbols, origin)
}
return property.convertWithOffsets { startOffset, endOffset ->
classifierStorage.preCacheTypeParameters(property)
IrFactoryImpl.createProperty(
startOffset = if (origin == IrDeclarationOrigin.ENUM_CLASS_SPECIAL_MEMBER) SYNTHETIC_OFFSET else startOffset,
endOffset = if (origin == IrDeclarationOrigin.ENUM_CLASS_SPECIAL_MEMBER) SYNTHETIC_OFFSET else endOffset,
origin = origin,
name = property.name,
visibility = c.visibilityConverter.convertToDescriptorVisibility(property.visibility),
modality = property.modality!!,
symbol = symbols.propertySymbol,
isVar = property.isVar,
isConst = property.isConst,
isLateinit = property.isLateInit,
isDelegated = property.delegate != null,
isExternal = isEffectivelyExternal(property, irParent),
containerSource = property.containerSource,
isExpect = property.isExpect,
).apply {
metadata = FirMetadataSource.Property(property)
convertAnnotationsForNonDeclaredMembers(property, origin)
declarationStorage.withScope(symbol) {
// IrProperty is never created for local variables
setParent(irParent)
addDeclarationToParent(this, irParent)
val type = property.returnTypeRef.toIrType()
val delegate = property.delegate
val getter = property.getter
val setter = property.setter
if (delegate != null || property.hasBackingField) {
val backingField = if (delegate != null) {
((delegate as? FirQualifiedAccessExpression)?.calleeReference?.toResolvedBaseSymbol()?.fir as? FirTypeParameterRefsOwner)?.let {
classifierStorage.preCacheTypeParameters(it)
}
createBackingField(
irProperty = this,
firProperty = property,
origin = IrDeclarationOrigin.PROPERTY_DELEGATE,
symbol = symbols.backingFieldSymbol!!,
visibility = c.visibilityConverter.convertToDescriptorVisibility(property.fieldVisibility),
name = NameUtils.propertyDelegateName(property.name),
isFinal = true,
firInitializerExpression = delegate.takeIf { property.isReplSnippetDeclaration != true },
type = delegate.resolvedType.toIrType(),
)
} else {
// REPL snippet properties are initialized within the `$$eval` function.
// TODO(KT-82578): split declaration and initializer to hopefully simplify FIR2IR
val initializer = runIf(property.isReplSnippetDeclaration != true) {
getEffectivePropertyInitializer(property, resolveIfNeeded = true)
}
// 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(
this,
property,
IrDeclarationOrigin.PROPERTY_BACKING_FIELD,
symbols.backingFieldSymbol!!,
c.visibilityConverter.convertToDescriptorVisibility(property.fieldVisibility),
property.name,
property.isVal,
initializer,
typeToUse,
).also { field ->
if (initializer is FirLiteralExpression) {
val constType = initializer.resolvedType.toIrType()
field.initializer = factory.createExpressionBody(initializer.toIrConst(constType))
}
}
}
this.backingField = backingField
}
if (irParent != null) {
backingField?.parent = irParent
}
this.getter = symbols.getterSymbol?.let { getterSymbol ->
getter.convertWithOffsets(startOffset, endOffset) { startOffset, endOffset ->
createIrPropertyAccessor(
getter, property, this, getterSymbol, type, irParent, false,
when {
origin == IrDeclarationOrigin.IR_EXTERNAL_DECLARATION_STUB -> origin
origin == IrDeclarationOrigin.ENUM_CLASS_SPECIAL_MEMBER -> origin
delegate != null -> IrDeclarationOrigin.DELEGATED_PROPERTY_ACCESSOR
origin == IrDeclarationOrigin.FAKE_OVERRIDE -> origin
origin == IrDeclarationOrigin.DELEGATED_MEMBER -> origin
getter == null || getter is FirDefaultPropertyGetter -> IrDeclarationOrigin.DEFAULT_PROPERTY_ACCESSOR
else -> origin
},
if (origin == IrDeclarationOrigin.ENUM_CLASS_SPECIAL_MEMBER) SYNTHETIC_OFFSET else startOffset,
if (origin == IrDeclarationOrigin.ENUM_CLASS_SPECIAL_MEMBER) SYNTHETIC_OFFSET else endOffset,
property.unwrapFakeOverrides().getter,
)
}
}
if (property.isVar && symbols.setterSymbol != null) {
this.setter = setter.convertWithOffsets(startOffset, endOffset) { startOffset, endOffset ->
createIrPropertyAccessor(
setter, property, this, symbols.setterSymbol, type, irParent, true,
when {
delegate != null -> IrDeclarationOrigin.DELEGATED_PROPERTY_ACCESSOR
origin == IrDeclarationOrigin.FAKE_OVERRIDE -> origin
origin == IrDeclarationOrigin.DELEGATED_MEMBER -> origin
setter is FirDefaultPropertySetter -> IrDeclarationOrigin.DEFAULT_PROPERTY_ACCESSOR
else -> origin
},
startOffset, endOffset,
property.unwrapFakeOverrides().setter,
)
}
}
}
}
}
}