[JVM IR] KTIJ-24335 Fix stub generation of deduplicated built-ins

- Some built-in symbols like `OptIn` haven't been created yet by the
  time `irBuiltIns` is bound to `SymbolTableWithBuiltInsDeduplication`.
  This caused an issue where `DeclarationStubGenerator` would get the
  built-in symbol from `referenceClass`, but still stub for the original
  duplicate `descriptor` and its associated own symbol. Because
  `generateClassStub` would check `referenceClass.isBound` for the
  built-in symbol, `isBound` was never checked for the duplicate symbol
  and thus a "symbol already bound" exception occurred if
  `generateClassStub` was invoked twice for a duplicate `descriptor`.
- The solution takes the descriptor from the `IrClassSymbol` returned
  by `referenceClass`.
This commit is contained in:
Marco Pennekamp
2023-01-20 14:05:45 +01:00
committed by Space Team
parent f11ea92601
commit d1df6391db
2 changed files with 36 additions and 21 deletions
@@ -31,8 +31,8 @@ class SymbolTableWithBuiltInsDeduplication(
irFactory: IrFactory,
) : SymbolTable(signaturer, irFactory) {
/**
* As long as [IrBuiltIns] aren't bound, the symbol table will operate like [SymbolTable], as it must be assumed that built-ins are
* still being created.
* As long as [IrBuiltIns] aren't bound, the symbol table will operate like [SymbolTable], as the initialization of built-ins requires
* a symbol table.
*/
private var irBuiltIns: IrBuiltInsOverDescriptors? = null
@@ -44,6 +44,14 @@ class SymbolTableWithBuiltInsDeduplication(
}
}
/**
* Gets or creates the [IrClassSymbol] for [descriptor], or for the built-in descriptor with the same name if [descriptor] is a
* duplicate built-in.
*
* Note that not all built-in symbols may have been bound or created by the time [irBuiltIns] has been bound. However, [referenceClass]
* will create a symbol in such a case (via `super.referenceClass`) and [org.jetbrains.kotlin.ir.util.DeclarationStubGenerator] will
* create a stub for the symbol if [referenceClass] was invoked from the stub generator.
*/
@ObsoleteDescriptorBasedAPI
override fun referenceClass(descriptor: ClassDescriptor): IrClassSymbol {
val irBuiltIns = this.irBuiltIns ?: return super.referenceClass(descriptor)
@@ -254,26 +254,33 @@ abstract class DeclarationStubGenerator(
classDescriptor.modality
fun generateClassStub(descriptor: ClassDescriptor): IrClass {
val referenceClass = symbolTable.referenceClass(descriptor)
if (referenceClass.isBound) {
return referenceClass.owner
val irClassSymbol = symbolTable.referenceClass(descriptor)
if (irClassSymbol.isBound) {
return irClassSymbol.owner
}
val origin = computeOrigin(descriptor)
return symbolTable.declareClass(descriptor) {
IrLazyClass(
UNDEFINED_OFFSET, UNDEFINED_OFFSET, origin,
it, descriptor,
descriptor.name, descriptor.kind, descriptor.visibility, getEffectiveModality(descriptor),
isCompanion = descriptor.isCompanionObject,
isInner = descriptor.isInner,
isData = descriptor.isData,
isExternal = descriptor.isEffectivelyExternal(),
isValue = descriptor.isValueClass(),
isExpect = descriptor.isExpect,
isFun = descriptor.isFun,
stubGenerator = this,
typeTranslator = typeTranslator
)
// `irClassSymbol` may have a different descriptor than `descriptor`. For example, a `SymbolTableWithBuiltInsDeduplication` might
// return a built-in symbol that hasn't been bound yet (e.g. `OptIn`). If the stub generator calls `declareClass` with the incorrect
// `descriptor`, a symbol created for `descriptor` will be bound, not the built-in symbol which should be. If `generateClassStub` is
// called twice for such a `descriptor`, an exception will occur because `descriptor`'s symbol will already have been bound.
with(irClassSymbol.descriptor) {
val origin = computeOrigin(this)
return symbolTable.declareClass(this) {
IrLazyClass(
UNDEFINED_OFFSET, UNDEFINED_OFFSET, origin,
it, this,
name, kind, visibility, getEffectiveModality(this),
isCompanion = isCompanionObject,
isInner = isInner,
isData = isData,
isExternal = isEffectivelyExternal(),
isValue = isValueClass(),
isExpect = isExpect,
isFun = isFun,
stubGenerator = this@DeclarationStubGenerator,
typeTranslator = typeTranslator
)
}
}
}