[IR] Use erased types in backing field initializer in case of generic delegated property
- Since neither IrProperty nor IrField is Type Parameter container using of proprty's type parameter in IrField related code leads to creation of "hanging" type parameters which should be considered as incorrect IR. - Such code designed to be prohibited in LV 1.5 - The fix makes use of erased type in such case where type parameter is expected.
This commit is contained in:
+33
-27
@@ -65,7 +65,7 @@ class DelegatedPropertyGenerator(declarationGenerator: DeclarationGenerator) : D
|
||||
val irDelegate = irProperty.backingField!!
|
||||
|
||||
val thisClass = propertyDescriptor.containingDeclaration as? ClassDescriptor
|
||||
val delegateReceiverValue = createBackingFieldValueForDelegate(irDelegate.symbol, thisClass, ktDelegate)
|
||||
val delegateReceiverValue = createBackingFieldValueForDelegate(irDelegate.symbol, thisClass, ktDelegate, propertyDescriptor)
|
||||
val getterDescriptor = propertyDescriptor.getter!!
|
||||
irProperty.getter = generateDelegatedPropertyAccessor(ktProperty, ktDelegate, getterDescriptor) { irGetter ->
|
||||
generateDelegatedPropertyGetterBody(
|
||||
@@ -120,24 +120,26 @@ class DelegatedPropertyGenerator(declarationGenerator: DeclarationGenerator) : D
|
||||
kPropertyType: KotlinType,
|
||||
ktDelegate: KtPropertyDelegate
|
||||
): IrField {
|
||||
val delegateType = getDelegatedPropertyDelegateType(propertyDescriptor, ktDelegate)
|
||||
val delegateDescriptor = createPropertyDelegateDescriptor(propertyDescriptor, delegateType, kPropertyType)
|
||||
return context.typeTranslator.withTypeErasure(propertyDescriptor) {
|
||||
val delegateType = getDelegatedPropertyDelegateType(propertyDescriptor, ktDelegate)
|
||||
val delegateDescriptor = createPropertyDelegateDescriptor(propertyDescriptor, delegateType, kPropertyType)
|
||||
|
||||
val startOffset = ktDelegate.startOffsetSkippingComments
|
||||
val endOffset = ktDelegate.endOffset
|
||||
val origin = IrDeclarationOrigin.PROPERTY_DELEGATE
|
||||
val type = delegateDescriptor.type.toIrType()
|
||||
return context.symbolTable.declareField(
|
||||
startOffset, endOffset, origin, delegateDescriptor, type
|
||||
) {
|
||||
IrFieldImpl(startOffset, endOffset, origin, it, type).apply {
|
||||
metadata = MetadataSource.Property(propertyDescriptor)
|
||||
val startOffset = ktDelegate.startOffsetSkippingComments
|
||||
val endOffset = ktDelegate.endOffset
|
||||
val origin = IrDeclarationOrigin.PROPERTY_DELEGATE
|
||||
val type = delegateDescriptor.type.toIrType()
|
||||
context.symbolTable.declareField(
|
||||
startOffset, endOffset, origin, delegateDescriptor, type
|
||||
) {
|
||||
IrFieldImpl(startOffset, endOffset, origin, it, type).apply {
|
||||
metadata = MetadataSource.Property(propertyDescriptor)
|
||||
}
|
||||
}.also { irDelegate ->
|
||||
irDelegate.initializer = generateInitializerBodyForPropertyDelegate(
|
||||
propertyDescriptor, kPropertyType, ktDelegate,
|
||||
irDelegate.symbol
|
||||
)
|
||||
}
|
||||
}.also { irDelegate ->
|
||||
irDelegate.initializer = generateInitializerBodyForPropertyDelegate(
|
||||
propertyDescriptor, kPropertyType, ktDelegate,
|
||||
irDelegate.symbol
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -166,17 +168,21 @@ class DelegatedPropertyGenerator(declarationGenerator: DeclarationGenerator) : D
|
||||
private fun createBackingFieldValueForDelegate(
|
||||
irDelegateField: IrFieldSymbol,
|
||||
thisClass: ClassDescriptor?,
|
||||
ktDelegate: KtPropertyDelegate
|
||||
ktDelegate: KtPropertyDelegate,
|
||||
propertyDescriptor: PropertyDescriptor
|
||||
): IntermediateValue {
|
||||
val thisValue = createThisValueForDelegate(thisClass, ktDelegate)
|
||||
return BackingFieldLValue(
|
||||
context,
|
||||
ktDelegate.startOffsetSkippingComments, ktDelegate.endOffset,
|
||||
irDelegateField.descriptor.type.toIrType(),
|
||||
irDelegateField,
|
||||
thisValue,
|
||||
null
|
||||
)
|
||||
return context.typeTranslator.withTypeErasure(propertyDescriptor) {
|
||||
// TODO: do not erase type here
|
||||
val thisValue = createThisValueForDelegate(thisClass, ktDelegate)
|
||||
BackingFieldLValue(
|
||||
context,
|
||||
ktDelegate.startOffsetSkippingComments, ktDelegate.endOffset,
|
||||
irDelegateField.descriptor.type.toIrType(),
|
||||
irDelegateField,
|
||||
thisValue,
|
||||
null
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun createThisValueForDelegate(thisClass: ClassDescriptor?, ktDelegate: KtPropertyDelegate): IntermediateValue? =
|
||||
|
||||
+6
-3
@@ -203,10 +203,13 @@ internal class InsertImplicitCasts(
|
||||
initializer = initializer?.cast(declaration.descriptor.type)
|
||||
}
|
||||
|
||||
override fun visitField(declaration: IrField): IrStatement =
|
||||
declaration.transformPostfix {
|
||||
initializer?.coerceInnerExpression(descriptor.type)
|
||||
override fun visitField(declaration: IrField): IrStatement {
|
||||
return typeTranslator.withTypeErasure(declaration.correspondingPropertySymbol?.descriptor ?: declaration.descriptor) {
|
||||
declaration.transformPostfix {
|
||||
initializer?.coerceInnerExpression(descriptor.type)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitFunction(declaration: IrFunction): IrStatement =
|
||||
typeTranslator.buildWithScope(declaration) {
|
||||
|
||||
@@ -9,6 +9,7 @@ import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.TypeAliasDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||
@@ -22,6 +23,7 @@ import org.jetbrains.kotlin.ir.types.impl.*
|
||||
import org.jetbrains.kotlin.types.*
|
||||
import org.jetbrains.kotlin.types.typeUtil.replaceArgumentsWithStarProjections
|
||||
import org.jetbrains.kotlin.types.typesApproximation.approximateCapturedTypes
|
||||
import java.util.*
|
||||
|
||||
class TypeTranslator(
|
||||
private val symbolTable: ReferenceSymbolTable,
|
||||
@@ -31,6 +33,8 @@ class TypeTranslator(
|
||||
private val enterTableScope: Boolean = false
|
||||
) {
|
||||
|
||||
private val erasureStack = Stack<PropertyDescriptor>()
|
||||
|
||||
private val typeApproximatorForNI = TypeApproximator(builtIns)
|
||||
lateinit var constantValueGenerator: ConstantValueGenerator
|
||||
|
||||
@@ -48,6 +52,15 @@ class TypeTranslator(
|
||||
}
|
||||
}
|
||||
|
||||
fun <T> withTypeErasure(propertyDescriptor: PropertyDescriptor, b: () -> T): T {
|
||||
try {
|
||||
erasureStack.push(propertyDescriptor)
|
||||
return b()
|
||||
} finally {
|
||||
erasureStack.pop()
|
||||
}
|
||||
}
|
||||
|
||||
inline fun <T> buildWithScope(container: IrTypeParametersContainer, builder: () -> T): T {
|
||||
enterScope(container)
|
||||
val result = builder()
|
||||
@@ -80,6 +93,17 @@ class TypeTranslator(
|
||||
val ktTypeDescriptor = ktTypeConstructor.declarationDescriptor
|
||||
?: throw AssertionError("No descriptor for type $approximatedType")
|
||||
|
||||
if (erasureStack.isNotEmpty()) {
|
||||
if (ktTypeDescriptor is TypeParameterDescriptor) {
|
||||
if (ktTypeDescriptor.containingDeclaration in erasureStack) {
|
||||
// This hack is about type parameter leak in case of generic delegated property
|
||||
// Such code has to be prohibited since LV 1.5
|
||||
// For more details see commit message or KT-24643
|
||||
return approximateUpperBounds(ktTypeDescriptor.upperBounds, variance)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return IrSimpleTypeBuilder().apply {
|
||||
this.kotlinType = flexibleApproximatedType
|
||||
this.hasQuestionMark = approximatedType.isMarkedNullable
|
||||
@@ -103,6 +127,11 @@ class TypeTranslator(
|
||||
}.buildTypeProjection()
|
||||
}
|
||||
|
||||
private fun approximateUpperBounds(upperBounds: Collection<KotlinType>, variance: Variance): IrTypeProjection {
|
||||
val commonSupertype = CommonSupertypes.commonSupertype(upperBounds)
|
||||
return translateType(approximate(commonSupertype.replaceArgumentsWithStarProjections()), variance)
|
||||
}
|
||||
|
||||
private fun SimpleType.toIrTypeAbbreviation(): IrTypeAbbreviation {
|
||||
val typeAliasDescriptor = constructor.declarationDescriptor.let {
|
||||
it as? TypeAliasDescriptor
|
||||
|
||||
Reference in New Issue
Block a user