[EE-IR] Fragment Compiler Entrypoint in IR Backend

This commit introduces a new entrypoint for the IR backend, and starts
the work of accomodating the evaluator in psi2ir.

The evaluator expects a certain class and method structure of the
compiled fragment, but PSI is only supplied for the actual fragment.

So, to that end, this commit introduces a new "front end" of psi2ir
that "synthesizes" the module, class and method structure around the
fragment before calling into the existing psi2ir pipeline to obtain
the IR for the fragment.

The primary complication so far is handling the captured variables of
the fragment: they are mapped to parameters of the method surrounding
the fragment, and passed as arguments on evaluation. Hence, the IR
translation of the fragment needs to remap captured variables to the
appropriate parameter, in essentially all places they can be referred
to in the fragment (and hence in psi2ir). This commit introduces a
decorated symbol table that intercepts symbol look-ups and remaps as
appropriate.

Other cases that dispatches based on descriptor (see
`CallGenerator.kt`) needs other metadata to generate correct code.

It also introduces a shim in DeserializedContainerSource in the psi2ir
pipeline to facilitate facade class generation for the code that is
being debugged (which are generated as "external ir declarations").

Finally, in passing we resolve a small leftover from previous
refactoring that left an asssertion re. allowing IR to _assign_ to
parameters of methods.
This commit is contained in:
Kristoffer Andersen
2021-08-13 14:51:26 +02:00
committed by Alexander Udalov
parent 783c3d1500
commit 247cbffbac
19 changed files with 421 additions and 25 deletions
@@ -92,7 +92,7 @@ abstract class DeclarationStubGenerator(
fun generateOrGetFacadeClass(descriptor: DeclarationDescriptor): IrClass? {
val directMember = descriptor.safeAs<PropertyAccessorDescriptor>()?.correspondingProperty ?: descriptor
val packageFragment = directMember.containingDeclaration as? PackageFragmentDescriptor ?: return null
val containerSource = directMember.safeAs<DescriptorWithContainerSource>()?.containerSource ?: return null
val containerSource = extensions.getContainerSource(directMember) ?: return null
return facadeClassMap.getOrPut(containerSource) {
extensions.generateFacadeClass(symbolTable.irFactory, containerSource, this)?.also { facade ->
val packageStub = generateOrGetEmptyExternalPackageFragmentStub(packageFragment)
@@ -26,6 +26,15 @@ open class StubGeneratorExtensions {
stubGenerator: DeclarationStubGenerator,
): IrClass? = null
// Extension point for the JVM Debugger IDEA plug-in: it compiles fragments
// (conditions on breakpoints, "Evaluate expression...", watches, etc...)
// in the context of an open intellij project that is being debugged. These
// classes are supplied to the fragment evaluator as PSI, not class files,
// as the old backend assumes for external declarations. Hence, we need to
// intercept and supply "fake" deserialized sources.
open fun getContainerSource(descriptor: DeclarationDescriptor): DeserializedContainerSource? = null
open fun isPropertyWithPlatformField(descriptor: PropertyDescriptor): Boolean = false
open fun isStaticFunction(descriptor: FunctionDescriptor): Boolean = false
@@ -60,7 +60,7 @@ interface ReferenceSymbolTable {
fun leaveScope(owner: IrDeclaration)
}
class SymbolTable(
open class SymbolTable(
val signaturer: IdSignatureComposer,
val irFactory: IrFactory,
val nameProvider: NameProvider = NameProvider.DEFAULT
@@ -1000,11 +1000,12 @@ class SymbolTable(
type: IrType,
varargElementType: IrType? = null,
name: Name? = null,
isAssignable: Boolean = false,
valueParameterFactory: (IrValueParameterSymbol) -> IrValueParameter = {
irFactory.createValueParameter(
startOffset, endOffset, origin, it, name ?: nameProvider.nameForDeclaration(descriptor),
descriptor.indexOrMinusOne, type, varargElementType, descriptor.isCrossinline, descriptor.isNoinline,
isHidden = false, isAssignable = false
isHidden = false, isAssignable = isAssignable
)
}
): IrValueParameter =
@@ -1110,7 +1111,7 @@ class SymbolTable(
leaveScope(owner.symbol)
}
fun referenceValue(value: ValueDescriptor): IrValueSymbol =
open fun referenceValue(value: ValueDescriptor): IrValueSymbol =
when (value) {
is ParameterDescriptor ->
valueParameterSymbolTable.referenced(value) { throw AssertionError("Undefined parameter referenced: $value") }