[FIR2IR] Generate fake overrides earlier and bind them later
Before this commit, we generated fake overrides at last FIR2IR stage, after having all functions and classes built. This could lead to a situation when fake override was called before it was generated. This commit fixes this situation.
This commit is contained in:
@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.fir.FirSession
|
|||||||
import org.jetbrains.kotlin.fir.backend.evaluate.evaluateConstants
|
import org.jetbrains.kotlin.fir.backend.evaluate.evaluateConstants
|
||||||
import org.jetbrains.kotlin.fir.backend.generators.AnnotationGenerator
|
import org.jetbrains.kotlin.fir.backend.generators.AnnotationGenerator
|
||||||
import org.jetbrains.kotlin.fir.backend.generators.CallAndReferenceGenerator
|
import org.jetbrains.kotlin.fir.backend.generators.CallAndReferenceGenerator
|
||||||
|
import org.jetbrains.kotlin.fir.backend.generators.DataClassMembersGenerator
|
||||||
import org.jetbrains.kotlin.fir.backend.generators.FakeOverrideGenerator
|
import org.jetbrains.kotlin.fir.backend.generators.FakeOverrideGenerator
|
||||||
import org.jetbrains.kotlin.fir.declarations.*
|
import org.jetbrains.kotlin.fir.declarations.*
|
||||||
import org.jetbrains.kotlin.fir.descriptors.FirModuleDescriptor
|
import org.jetbrains.kotlin.fir.descriptors.FirModuleDescriptor
|
||||||
@@ -23,6 +24,7 @@ import org.jetbrains.kotlin.ir.declarations.impl.IrModuleFragmentImpl
|
|||||||
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
|
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
|
||||||
import org.jetbrains.kotlin.ir.descriptors.WrappedDeclarationDescriptor
|
import org.jetbrains.kotlin.ir.descriptors.WrappedDeclarationDescriptor
|
||||||
import org.jetbrains.kotlin.ir.util.*
|
import org.jetbrains.kotlin.ir.util.*
|
||||||
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.psi.KtFile
|
import org.jetbrains.kotlin.psi.KtFile
|
||||||
import org.jetbrains.kotlin.psi2ir.PsiSourceManager
|
import org.jetbrains.kotlin.psi2ir.PsiSourceManager
|
||||||
import org.jetbrains.kotlin.psi2ir.generators.GeneratorExtensions
|
import org.jetbrains.kotlin.psi2ir.generators.GeneratorExtensions
|
||||||
@@ -89,40 +91,90 @@ class Fir2IrConverter(
|
|||||||
it, irClass, isLocal = true
|
it, irClass, isLocal = true
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
val processedCallableNames = mutableSetOf<Name>()
|
||||||
for (declaration in sortBySynthetic(anonymousObject.declarations)) {
|
for (declaration in sortBySynthetic(anonymousObject.declarations)) {
|
||||||
if (declaration is FirRegularClass) {
|
if (declaration is FirRegularClass) {
|
||||||
registerClassAndNestedClasses(declaration, irClass)
|
registerClassAndNestedClasses(declaration, irClass)
|
||||||
processClassAndNestedClassHeaders(declaration)
|
processClassAndNestedClassHeaders(declaration)
|
||||||
}
|
}
|
||||||
val irDeclaration = processMemberDeclaration(declaration, anonymousObject, irClass) ?: continue
|
val irDeclaration = processMemberDeclaration(declaration, anonymousObject, irClass) ?: continue
|
||||||
|
when (declaration) {
|
||||||
|
is FirSimpleFunction -> processedCallableNames += declaration.name
|
||||||
|
is FirProperty -> processedCallableNames += declaration.name
|
||||||
|
}
|
||||||
irClass.declarations += irDeclaration
|
irClass.declarations += irDeclaration
|
||||||
}
|
}
|
||||||
return irClass
|
// Add delegated members *before* fake override generations.
|
||||||
}
|
// Otherwise, fake overrides for delegated members, which are redundant, will be added.
|
||||||
|
processedCallableNames += delegatedMemberNames(irClass)
|
||||||
|
with(fakeOverrideGenerator) {
|
||||||
|
irClass.addFakeOverrides(anonymousObject, processedCallableNames)
|
||||||
|
}
|
||||||
|
|
||||||
// Sort declarations so that all non-synthetic declarations are before synthetic ones.
|
return irClass
|
||||||
// This is needed because converting synthetic fields for implementation delegation needs to know
|
|
||||||
// existing declarations in the class to avoid adding redundant delegated members.
|
|
||||||
private fun sortBySynthetic(declarations: List<FirDeclaration>) : Iterable<FirDeclaration> {
|
|
||||||
return declarations.sortedBy { it.isSynthetic }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun processClassMembers(
|
private fun processClassMembers(
|
||||||
regularClass: FirRegularClass,
|
regularClass: FirRegularClass,
|
||||||
irClass: IrClass = classifierStorage.getCachedIrClass(regularClass)!!
|
irClass: IrClass = classifierStorage.getCachedIrClass(regularClass)!!
|
||||||
): IrClass {
|
): IrClass {
|
||||||
regularClass.getPrimaryConstructorIfAny()?.let {
|
val irConstructor = regularClass.getPrimaryConstructorIfAny()?.let {
|
||||||
irClass.declarations += declarationStorage.createIrConstructor(
|
declarationStorage.createIrConstructor(it, irClass, isLocal = regularClass.isLocal)
|
||||||
it, irClass, isLocal = regularClass.isLocal
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
if (irConstructor != null) {
|
||||||
|
irClass.declarations += irConstructor
|
||||||
|
}
|
||||||
|
val processedCallableNames = mutableSetOf<Name>()
|
||||||
for (declaration in sortBySynthetic(regularClass.declarations)) {
|
for (declaration in sortBySynthetic(regularClass.declarations)) {
|
||||||
val irDeclaration = processMemberDeclaration(declaration, regularClass, irClass) ?: continue
|
val irDeclaration = processMemberDeclaration(declaration, regularClass, irClass) ?: continue
|
||||||
|
when (declaration) {
|
||||||
|
is FirSimpleFunction -> processedCallableNames += declaration.name
|
||||||
|
is FirProperty -> processedCallableNames += declaration.name
|
||||||
|
}
|
||||||
irClass.declarations += irDeclaration
|
irClass.declarations += irDeclaration
|
||||||
}
|
}
|
||||||
|
// Add delegated members *before* fake override generations.
|
||||||
|
// Otherwise, fake overrides for delegated members, which are redundant, will be added.
|
||||||
|
processedCallableNames += delegatedMemberNames(irClass)
|
||||||
|
// Add synthetic members *before* fake override generations.
|
||||||
|
// Otherwise, redundant members, e.g., synthetic toString _and_ fake override toString, will be added.
|
||||||
|
if (irConstructor != null && (irClass.isInline || irClass.isData)) {
|
||||||
|
declarationStorage.enterScope(irConstructor)
|
||||||
|
val dataClassMembersGenerator = DataClassMembersGenerator(components)
|
||||||
|
if (irClass.isInline) {
|
||||||
|
processedCallableNames += dataClassMembersGenerator.generateInlineClassMembers(regularClass, irClass)
|
||||||
|
}
|
||||||
|
if (irClass.isData) {
|
||||||
|
processedCallableNames += dataClassMembersGenerator.generateDataClassMembers(regularClass, irClass)
|
||||||
|
}
|
||||||
|
declarationStorage.leaveScope(irConstructor)
|
||||||
|
}
|
||||||
|
with(fakeOverrideGenerator) {
|
||||||
|
irClass.addFakeOverrides(regularClass, processedCallableNames)
|
||||||
|
}
|
||||||
|
|
||||||
return irClass
|
return irClass
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun delegatedMemberNames(irClass: IrClass): List<Name> {
|
||||||
|
return irClass.declarations.filter {
|
||||||
|
it.origin == IrDeclarationOrigin.DELEGATED_MEMBER
|
||||||
|
}.mapNotNull {
|
||||||
|
when (it) {
|
||||||
|
is IrSimpleFunction -> it.name
|
||||||
|
is IrProperty -> it.name
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sort declarations so that all non-synthetic declarations are before synthetic ones.
|
||||||
|
// This is needed because converting synthetic fields for implementation delegation needs to know
|
||||||
|
// existing declarations in the class to avoid adding redundant delegated members.
|
||||||
|
private fun sortBySynthetic(declarations: List<FirDeclaration>): Iterable<FirDeclaration> {
|
||||||
|
return declarations.sortedBy { it.isSynthetic }
|
||||||
|
}
|
||||||
|
|
||||||
private fun registerClassAndNestedClasses(regularClass: FirRegularClass, parent: IrDeclarationParent): IrClass {
|
private fun registerClassAndNestedClasses(regularClass: FirRegularClass, parent: IrDeclarationParent): IrClass {
|
||||||
val irClass = classifierStorage.registerIrClass(regularClass, parent)
|
val irClass = classifierStorage.registerIrClass(regularClass, parent)
|
||||||
regularClass.declarations.forEach {
|
regularClass.declarations.forEach {
|
||||||
|
|||||||
+1
-32
@@ -15,19 +15,13 @@ import org.jetbrains.kotlin.fir.expressions.FirExpression
|
|||||||
import org.jetbrains.kotlin.fir.expressions.impl.FirNoReceiverExpression
|
import org.jetbrains.kotlin.fir.expressions.impl.FirNoReceiverExpression
|
||||||
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
|
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
|
||||||
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
|
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
|
||||||
import org.jetbrains.kotlin.fir.scopes.ProcessorAction
|
|
||||||
import org.jetbrains.kotlin.fir.scopes.processDirectlyOverriddenProperties
|
|
||||||
import org.jetbrains.kotlin.fir.scopes.unsubstitutedScope
|
|
||||||
import org.jetbrains.kotlin.fir.symbols.impl.FirConstructorSymbol
|
import org.jetbrains.kotlin.fir.symbols.impl.FirConstructorSymbol
|
||||||
import org.jetbrains.kotlin.fir.symbols.impl.unwrapSubstitutionOverrides
|
|
||||||
import org.jetbrains.kotlin.fir.types.*
|
import org.jetbrains.kotlin.fir.types.*
|
||||||
import org.jetbrains.kotlin.ir.declarations.*
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrFieldAccessExpression
|
import org.jetbrains.kotlin.ir.expressions.IrFieldAccessExpression
|
||||||
import org.jetbrains.kotlin.ir.expressions.impl.*
|
import org.jetbrains.kotlin.ir.expressions.impl.*
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrPropertySymbol
|
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
|
|
||||||
import org.jetbrains.kotlin.ir.types.IrType
|
import org.jetbrains.kotlin.ir.types.IrType
|
||||||
import org.jetbrains.kotlin.ir.util.constructedClassType
|
import org.jetbrains.kotlin.ir.util.constructedClassType
|
||||||
import org.jetbrains.kotlin.ir.util.isAnnotationClass
|
import org.jetbrains.kotlin.ir.util.isAnnotationClass
|
||||||
@@ -61,32 +55,7 @@ internal class ClassMemberGenerator(
|
|||||||
convertFunctionContent(irPrimaryConstructor, primaryConstructor, containingClass = klass)
|
convertFunctionContent(irPrimaryConstructor, primaryConstructor, containingClass = klass)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val processedCallableNames = klass.declarations.mapNotNullTo(mutableSetOf()) {
|
fakeOverrideGenerator.bindOverriddenSymbols(irClass.declarations)
|
||||||
when (it) {
|
|
||||||
is FirSimpleFunction -> it.name
|
|
||||||
is FirProperty -> it.name
|
|
||||||
else -> null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Add delegated members *before* fake override generations.
|
|
||||||
// Otherwise, fake overrides for delegated members, which are redundant, will be added.
|
|
||||||
irClass.declarations.filter {
|
|
||||||
it.origin == IrDeclarationOrigin.DELEGATED_MEMBER
|
|
||||||
}.forEach {
|
|
||||||
when (it) {
|
|
||||||
is IrSimpleFunction -> processedCallableNames += it.name
|
|
||||||
is IrProperty -> processedCallableNames += it.name
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Add synthetic members *before* fake override generations.
|
|
||||||
// Otherwise, redundant members, e.g., synthetic toString _and_ fake override toString, will be added.
|
|
||||||
if (irClass.isInline && klass.getPrimaryConstructorIfAny() != null) {
|
|
||||||
processedCallableNames += DataClassMembersGenerator(components).generateInlineClassMembers(klass, irClass)
|
|
||||||
}
|
|
||||||
if (irClass.isData && klass.getPrimaryConstructorIfAny() != null) {
|
|
||||||
processedCallableNames += DataClassMembersGenerator(components).generateDataClassMembers(klass, irClass)
|
|
||||||
}
|
|
||||||
with(fakeOverrideGenerator) { irClass.addFakeOverrides(klass, processedCallableNames) }
|
|
||||||
klass.declarations.forEach { declaration ->
|
klass.declarations.forEach { declaration ->
|
||||||
when {
|
when {
|
||||||
declaration is FirTypeAlias -> {
|
declaration is FirTypeAlias -> {
|
||||||
|
|||||||
+35
-18
@@ -33,6 +33,9 @@ class FakeOverrideGenerator(
|
|||||||
private val fakeOverrideMode: FakeOverrideMode
|
private val fakeOverrideMode: FakeOverrideMode
|
||||||
) {
|
) {
|
||||||
|
|
||||||
|
private val baseFunctionSymbols = mutableMapOf<IrFunction, FirNamedFunctionSymbol>()
|
||||||
|
private val basePropertySymbols = mutableMapOf<IrProperty, FirPropertySymbol>()
|
||||||
|
|
||||||
private fun IrSimpleFunction.withFunction(f: IrSimpleFunction.() -> Unit): IrSimpleFunction {
|
private fun IrSimpleFunction.withFunction(f: IrSimpleFunction.() -> Unit): IrSimpleFunction {
|
||||||
return conversionScope.withFunction(this, f)
|
return conversionScope.withFunction(this, f)
|
||||||
}
|
}
|
||||||
@@ -98,11 +101,9 @@ class FakeOverrideGenerator(
|
|||||||
// In fake overrides, parent logic is a bit specific, because
|
// In fake overrides, parent logic is a bit specific, because
|
||||||
// parent of *original* function (base class) is used for dispatch receiver,
|
// parent of *original* function (base class) is used for dispatch receiver,
|
||||||
// but fake override itself uses parent from its containing (derived) class
|
// but fake override itself uses parent from its containing (derived) class
|
||||||
val overriddenSymbol = declarationStorage.getIrFunctionSymbol(baseSymbol) as IrSimpleFunctionSymbol
|
|
||||||
irFunction.parent = this
|
irFunction.parent = this
|
||||||
result += irFunction.withFunction {
|
baseFunctionSymbols[irFunction] = baseSymbol
|
||||||
overriddenSymbols = listOf(overriddenSymbol)
|
result += irFunction
|
||||||
}
|
|
||||||
} else if (fakeOverrideMode != FakeOverrideMode.SUBSTITUTION && originalFunction.allowsToHaveFakeOverrideIn(klass)) {
|
} else if (fakeOverrideMode != FakeOverrideMode.SUBSTITUTION && originalFunction.allowsToHaveFakeOverrideIn(klass)) {
|
||||||
// Trivial fake override case
|
// Trivial fake override case
|
||||||
val fakeOverrideSymbol = FirClassSubstitutionScope.createFakeOverrideFunction(
|
val fakeOverrideSymbol = FirClassSubstitutionScope.createFakeOverrideFunction(
|
||||||
@@ -123,11 +124,9 @@ class FakeOverrideGenerator(
|
|||||||
if (irFunction.returnType.containsErrorType() || irFunction.valueParameters.any { it.type.containsErrorType() }) {
|
if (irFunction.returnType.containsErrorType() || irFunction.valueParameters.any { it.type.containsErrorType() }) {
|
||||||
return@processFunctionsByName
|
return@processFunctionsByName
|
||||||
}
|
}
|
||||||
val overriddenSymbol = declarationStorage.getIrFunctionSymbol(baseSymbol) as IrSimpleFunctionSymbol
|
|
||||||
irFunction.parent = this
|
irFunction.parent = this
|
||||||
result += irFunction.withFunction {
|
baseFunctionSymbols[irFunction] = baseSymbol
|
||||||
overriddenSymbols = listOf(overriddenSymbol)
|
result += irFunction
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -149,10 +148,8 @@ class FakeOverrideGenerator(
|
|||||||
isLocal = isLocal
|
isLocal = isLocal
|
||||||
)
|
)
|
||||||
irProperty.parent = this
|
irProperty.parent = this
|
||||||
result += irProperty.withProperty {
|
basePropertySymbols[irProperty] = baseSymbol
|
||||||
discardAccessorsAccordingToBaseVisibility(baseSymbol)
|
result += irProperty
|
||||||
setOverriddenSymbolsForAccessors(declarationStorage, originalProperty, firOverriddenSymbol = baseSymbol)
|
|
||||||
}
|
|
||||||
} else if (fakeOverrideMode != FakeOverrideMode.SUBSTITUTION && originalProperty.allowsToHaveFakeOverrideIn(klass)) {
|
} else if (fakeOverrideMode != FakeOverrideMode.SUBSTITUTION && originalProperty.allowsToHaveFakeOverrideIn(klass)) {
|
||||||
// Trivial fake override case
|
// Trivial fake override case
|
||||||
val fakeOverrideSymbol = FirClassSubstitutionScope.createFakeOverrideProperty(
|
val fakeOverrideSymbol = FirClassSubstitutionScope.createFakeOverrideProperty(
|
||||||
@@ -175,10 +172,8 @@ class FakeOverrideGenerator(
|
|||||||
return@processPropertiesByName
|
return@processPropertiesByName
|
||||||
}
|
}
|
||||||
irProperty.parent = this
|
irProperty.parent = this
|
||||||
result += irProperty.withProperty {
|
basePropertySymbols[irProperty] = baseSymbol
|
||||||
discardAccessorsAccordingToBaseVisibility(baseSymbol)
|
result += irProperty
|
||||||
setOverriddenSymbolsForAccessors(declarationStorage, fakeOverrideProperty, firOverriddenSymbol = baseSymbol)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -186,6 +181,28 @@ class FakeOverrideGenerator(
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun bindOverriddenSymbols(declarations: List<IrDeclaration>) {
|
||||||
|
for (declaration in declarations) {
|
||||||
|
if (declaration.origin != IrDeclarationOrigin.FAKE_OVERRIDE) continue
|
||||||
|
when (declaration) {
|
||||||
|
is IrSimpleFunction -> {
|
||||||
|
val baseSymbol = baseFunctionSymbols[declaration]!!
|
||||||
|
val overriddenSymbol = declarationStorage.getIrFunctionSymbol(baseSymbol) as IrSimpleFunctionSymbol
|
||||||
|
declaration.withFunction {
|
||||||
|
overriddenSymbols = listOf(overriddenSymbol)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
is IrProperty -> {
|
||||||
|
val baseSymbol = basePropertySymbols[declaration]!!
|
||||||
|
declaration.withProperty {
|
||||||
|
discardAccessorsAccordingToBaseVisibility(baseSymbol)
|
||||||
|
setOverriddenSymbolsForAccessors(declarationStorage, declaration.isVar, firOverriddenSymbol = baseSymbol)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun IrProperty.discardAccessorsAccordingToBaseVisibility(baseSymbol: FirPropertySymbol) {
|
private fun IrProperty.discardAccessorsAccordingToBaseVisibility(baseSymbol: FirPropertySymbol) {
|
||||||
// Do not create fake overrides for accessors if not allowed to do so, e.g., private lateinit var.
|
// Do not create fake overrides for accessors if not allowed to do so, e.g., private lateinit var.
|
||||||
if (baseSymbol.fir.getter?.allowsToHaveFakeOverride != true) {
|
if (baseSymbol.fir.getter?.allowsToHaveFakeOverride != true) {
|
||||||
@@ -199,7 +216,7 @@ class FakeOverrideGenerator(
|
|||||||
|
|
||||||
private fun IrProperty.setOverriddenSymbolsForAccessors(
|
private fun IrProperty.setOverriddenSymbolsForAccessors(
|
||||||
declarationStorage: Fir2IrDeclarationStorage,
|
declarationStorage: Fir2IrDeclarationStorage,
|
||||||
property: FirProperty,
|
isVar: Boolean,
|
||||||
firOverriddenSymbol: FirPropertySymbol
|
firOverriddenSymbol: FirPropertySymbol
|
||||||
): IrProperty {
|
): IrProperty {
|
||||||
val irSymbol = declarationStorage.getIrPropertyOrFieldSymbol(firOverriddenSymbol) as? IrPropertySymbol ?: return this
|
val irSymbol = declarationStorage.getIrPropertyOrFieldSymbol(firOverriddenSymbol) as? IrPropertySymbol ?: return this
|
||||||
@@ -207,7 +224,7 @@ class FakeOverrideGenerator(
|
|||||||
getter?.apply {
|
getter?.apply {
|
||||||
overriddenProperty.getter?.symbol?.let { overriddenSymbols = listOf(it) }
|
overriddenProperty.getter?.symbol?.let { overriddenSymbols = listOf(it) }
|
||||||
}
|
}
|
||||||
if (property.isVar) {
|
if (isVar) {
|
||||||
setter?.apply {
|
setter?.apply {
|
||||||
overriddenProperty.setter?.symbol?.let { overriddenSymbols = listOf(it) }
|
overriddenProperty.setter?.symbol?.let { overriddenSymbols = listOf(it) }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -164,7 +164,9 @@ class Fir2IrLazyClass(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
with(fakeOverrideGenerator) {
|
with(fakeOverrideGenerator) {
|
||||||
result += getFakeOverrides(fir, processedNames)
|
val fakeOverrides = getFakeOverrides(fir, processedNames)
|
||||||
|
bindOverriddenSymbols(fakeOverrides)
|
||||||
|
result += fakeOverrides
|
||||||
}
|
}
|
||||||
// TODO: remove this check to save time
|
// TODO: remove this check to save time
|
||||||
for (declaration in result) {
|
for (declaration in result) {
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND_FIR: JVM_IR
|
|
||||||
fun box() = Class().printSome()
|
fun box() = Class().printSome()
|
||||||
|
|
||||||
public abstract class AbstractClass<T> {
|
public abstract class AbstractClass<T> {
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND_FIR: JVM_IR
|
|
||||||
// TARGET_BACKEND: JVM
|
// TARGET_BACKEND: JVM
|
||||||
// JVM_TARGET: 1.8
|
// JVM_TARGET: 1.8
|
||||||
// See also kt33054.kt
|
// See also kt33054.kt
|
||||||
|
|||||||
Reference in New Issue
Block a user