diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrClassifierStorage.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrClassifierStorage.kt index f268f055feb..0363b6de75b 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrClassifierStorage.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrClassifierStorage.kt @@ -82,9 +82,12 @@ class Fir2IrClassifierStorage( internal fun preCacheTypeParameters(owner: FirTypeParametersOwner) { owner.typeParameters.mapIndexed { index, typeParameter -> - getIrTypeParameter(typeParameter, index) + getCachedIrTypeParameter(typeParameter, index) + ?: createIrTypeParameterWithoutBounds(typeParameter, index) if (owner is FirProperty && owner.isVar) { - getIrTypeParameter(typeParameter, index, ConversionTypeContext.DEFAULT.inSetter()) + val context = ConversionTypeContext.DEFAULT.inSetter() + getCachedIrTypeParameter(typeParameter, index, context) + ?: createIrTypeParameterWithoutBounds(typeParameter, index, context) } } } @@ -94,12 +97,18 @@ class Fir2IrClassifierStorage( typeContext: ConversionTypeContext = ConversionTypeContext.DEFAULT ) { typeParameters = owner.typeParameters.mapIndexed { index, typeParameter -> - getIrTypeParameter(typeParameter, index, typeContext).apply { parent = this@setTypeParameters } + getIrTypeParameter(typeParameter, index, typeContext).apply { + parent = this@setTypeParameters + if (superTypes.isEmpty()) { + typeParameter.bounds.mapTo(superTypes) { it.toIrType() } + } + } } } private fun IrClass.declareSupertypesAndTypeParameters(klass: FirClass<*>): IrClass { if (klass is FirRegularClass) { + preCacheTypeParameters(klass) setTypeParameters(klass) } superTypes = klass.superTypeRefs.map { superTypeRef -> superTypeRef.toIrType() } @@ -230,11 +239,43 @@ class Fir2IrClassifierStorage( return createIrAnonymousObject(anonymousObject, Visibilities.PRIVATE, name, irParent) } - private fun getIrTypeParameter( + private fun createIrTypeParameterWithoutBounds( + typeParameter: FirTypeParameter, + index: Int, + typeContext: ConversionTypeContext = ConversionTypeContext.DEFAULT + ): IrTypeParameter { + require(index >= 0) + val descriptor = WrappedTypeParameterDescriptor() + val origin = IrDeclarationOrigin.DEFINED + val irTypeParameter = with(typeParameter) { + convertWithOffsets { startOffset, endOffset -> + symbolTable.declareGlobalTypeParameter(startOffset, endOffset, origin, descriptor) { symbol -> + IrTypeParameterImpl( + startOffset, endOffset, origin, symbol, + name, if (index < 0) 0 else index, + isReified, + variance + ).apply { + descriptor.bind(this) + } + } + } + } + + // Cache the type parameter BEFORE processing its bounds/supertypes, to properly handle recursive type bounds. + if (typeContext.origin == ConversionTypeOrigin.SETTER) { + typeParameterCacheForSetter[typeParameter] = irTypeParameter + } else { + typeParameterCache[typeParameter] = irTypeParameter + } + return irTypeParameter + } + + private fun getCachedIrTypeParameter( typeParameter: FirTypeParameter, index: Int = -1, typeContext: ConversionTypeContext = ConversionTypeContext.DEFAULT - ): IrTypeParameter { + ): IrTypeParameter? { // Here transformation is a bit difficult because one FIR property type parameter // can be transformed to two different type parameters: one for getter and another one for setter val simpleCachedParameter = typeParameterCache[typeParameter] @@ -252,33 +293,17 @@ class Fir2IrClassifierStorage( if (typeContext.origin == ConversionTypeOrigin.SETTER) { typeParameterCacheForSetter[typeParameter]?.let { return it } } - return typeParameter.run { - // Yet I don't want to enable this requirement because it breaks some tests - // However, if we get here it *should* mean that type parameter index is given explicitly - // At this moment (20.02.2020) this requirement breaks 11/355 Fir2IrText tests - // require(index != -1) - val descriptor = WrappedTypeParameterDescriptor() - val origin = IrDeclarationOrigin.DEFINED - val irTypeParameter = - convertWithOffsets { startOffset, endOffset -> - symbolTable.declareGlobalTypeParameter(startOffset, endOffset, origin, descriptor) { symbol -> - IrTypeParameterImpl( - startOffset, endOffset, origin, symbol, - name, if (index < 0) 0 else index, - isReified, - variance - ).apply { - descriptor.bind(this) - } - } - } + return null + } - // Cache the type parameter BEFORE processing its bounds/supertypes, to properly handle recursive type bounds. - if (typeContext.origin == ConversionTypeOrigin.SETTER) { - typeParameterCacheForSetter[typeParameter] = irTypeParameter - } else { - typeParameterCache[typeParameter] = irTypeParameter - } + private fun getIrTypeParameter( + typeParameter: FirTypeParameter, + index: Int, + typeContext: ConversionTypeContext = ConversionTypeContext.DEFAULT + ): IrTypeParameter { + getCachedIrTypeParameter(typeParameter, index, typeContext)?.let { return it } + return typeParameter.run { + val irTypeParameter = createIrTypeParameterWithoutBounds(typeParameter, index, typeContext) bounds.mapTo(irTypeParameter.superTypes) { it.toIrType() } irTypeParameter } @@ -359,8 +384,8 @@ class Fir2IrClassifierStorage( firTypeParameterSymbol: FirTypeParameterSymbol, typeContext: ConversionTypeContext ): IrTypeParameterSymbol { - // TODO: use cached type parameter here - val irTypeParameter = getIrTypeParameter(firTypeParameterSymbol.fir, typeContext = typeContext) + val irTypeParameter = getCachedIrTypeParameter(firTypeParameterSymbol.fir, typeContext = typeContext) + ?: throw AssertionError("Cannot find cached type parameter by FIR symbol: ${firTypeParameterSymbol.name}") return symbolTable.referenceTypeParameter(irTypeParameter.descriptor) } } \ No newline at end of file diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrDeclarationStorage.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrDeclarationStorage.kt index 7d5199dcf5f..ab088dea1d8 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrDeclarationStorage.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrDeclarationStorage.kt @@ -393,6 +393,7 @@ class Fir2IrDeclarationStorage( Modality.SEALED -> Visibilities.PRIVATE else -> constructor.visibility } + classifierStorage.preCacheTypeParameters(constructor) val created = constructor.convertWithOffsets { startOffset, endOffset -> symbolTable.declareConstructor(startOffset, endOffset, origin, descriptor) { symbol -> IrConstructorImpl( diff --git a/compiler/testData/ir/irText/declarations/parameters/typeParameterBeforeBound.fir.txt b/compiler/testData/ir/irText/declarations/parameters/typeParameterBeforeBound.fir.txt index aaa17e273de..b95ea768bb3 100644 --- a/compiler/testData/ir/irText/declarations/parameters/typeParameterBeforeBound.fir.txt +++ b/compiler/testData/ir/irText/declarations/parameters/typeParameterBeforeBound.fir.txt @@ -2,7 +2,7 @@ FILE fqName: fileName:/typeParameterBeforeBound.kt CLASS CLASS name:Test1 modality:FINAL visibility:public superTypes:[kotlin.Any] $this: VALUE_PARAMETER INSTANCE_RECEIVER name: type:.Test1.Test1, U of .Test1> TYPE_PARAMETER name:T index:0 variance: superTypes:[U of .Test1] - TYPE_PARAMETER name:U index:0 variance: superTypes:[kotlin.Any?] + TYPE_PARAMETER name:U index:1 variance: superTypes:[kotlin.Any?] CONSTRUCTOR visibility:public <> () returnType:.Test1.Test1, U of .Test1> [primary] BLOCK_BODY DELEGATING_CONSTRUCTOR_CALL 'public constructor () [primary] declared in kotlin.Any' @@ -22,13 +22,13 @@ FILE fqName: fileName:/typeParameterBeforeBound.kt $this: VALUE_PARAMETER name: type:kotlin.Any FUN name:test2 visibility:public modality:FINAL () returnType:kotlin.Unit TYPE_PARAMETER name:T index:0 variance: superTypes:[U of .test2] - TYPE_PARAMETER name:U index:0 variance: superTypes:[kotlin.Any?] + TYPE_PARAMETER name:U index:1 variance: superTypes:[kotlin.Any?] BLOCK_BODY PROPERTY name:test3 visibility:public modality:FINAL [var] FUN name: visibility:public modality:FINAL ($receiver:.Test1., U of .>) returnType:kotlin.Unit correspondingProperty: PROPERTY name:test3 visibility:public modality:FINAL [var] TYPE_PARAMETER name:T index:0 variance: superTypes:[U of .] - TYPE_PARAMETER name:U index:0 variance: superTypes:[kotlin.Any?] + TYPE_PARAMETER name:U index:1 variance: superTypes:[kotlin.Any?] $receiver: VALUE_PARAMETER name: type:.Test1., U of .> BLOCK_BODY FUN name: visibility:public modality:FINAL ($receiver:.Test1., U of .>, value:kotlin.Unit) returnType:kotlin.Unit diff --git a/compiler/testData/ir/irText/expressions/implicitCastToNonNull.fir.txt b/compiler/testData/ir/irText/expressions/implicitCastToNonNull.fir.txt index 2af255a3dad..12c5701884f 100644 --- a/compiler/testData/ir/irText/expressions/implicitCastToNonNull.fir.txt +++ b/compiler/testData/ir/irText/expressions/implicitCastToNonNull.fir.txt @@ -61,7 +61,7 @@ FILE fqName: fileName:/implicitCastToNonNull.kt GET_VAR 'x: kotlin.Any? declared in .test4' type=kotlin.Any? origin=null FUN name:test5 visibility:public modality:FINAL (x:T of .test5, fn:kotlin.Function1.test5, kotlin.Unit>) returnType:kotlin.Unit TYPE_PARAMETER name:T index:0 variance: superTypes:[S of .test5?] - TYPE_PARAMETER name:S index:0 variance: superTypes:[kotlin.Any?] + TYPE_PARAMETER name:S index:1 variance: superTypes:[kotlin.Any?] VALUE_PARAMETER name:x index:0 type:T of .test5 VALUE_PARAMETER name:fn index:1 type:kotlin.Function1.test5, kotlin.Unit> BLOCK_BODY