diff --git a/compiler/ir/backend.jvm/entrypoint/src/org/jetbrains/kotlin/backend/jvm/FacadeClassSourceShimForFragmentCompilation.kt b/compiler/ir/backend.jvm/entrypoint/src/org/jetbrains/kotlin/backend/jvm/FacadeClassSourceShimForFragmentCompilation.kt new file mode 100644 index 00000000000..58314ba3f23 --- /dev/null +++ b/compiler/ir/backend.jvm/entrypoint/src/org/jetbrains/kotlin/backend/jvm/FacadeClassSourceShimForFragmentCompilation.kt @@ -0,0 +1,43 @@ +/* + * Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.backend.jvm + +import org.jetbrains.kotlin.descriptors.SourceFile +import org.jetbrains.kotlin.fileClasses.JvmFileClassInfo +import org.jetbrains.kotlin.fileClasses.JvmFileClassUtil.getFileClassInfoNoResolve +import org.jetbrains.kotlin.load.kotlin.FacadeClassSource +import org.jetbrains.kotlin.psi.KtFile +import org.jetbrains.kotlin.resolve.jvm.JvmClassName +import org.jetbrains.kotlin.resolve.source.PsiSourceFile +import org.jetbrains.kotlin.serialization.deserialization.IncompatibleVersionErrorData +import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedContainerAbiStability +import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedContainerSource + +// Used from CodeFragmentCompiler for IDE Debugger Plug-In +@Suppress("unused") +class FacadeClassSourceShimForFragmentCompilation(private val containingFile: PsiSourceFile) : + DeserializedContainerSource, FacadeClassSource { + + private val fileClassInfo = getFileClassInfoNoResolve(containingFile.psiFile as KtFile) + + override val incompatibility: IncompatibleVersionErrorData<*>? + get() = null + override val isPreReleaseInvisible: Boolean + get() = false + override val abiStability: DeserializedContainerAbiStability + get() = DeserializedContainerAbiStability.STABLE + override val presentableString: String + get() = "Fragment for $containingFile" + + override fun getContainingFile(): SourceFile { + return containingFile + } + + override val className: JvmClassName + get() = JvmClassName.byFqNameWithoutInnerClasses(fileClassInfo.fileClassFqName) + override val facadeClassName: JvmClassName? + get() = JvmClassName.byFqNameWithoutInnerClasses(fileClassInfo.facadeClassFqName) +} diff --git a/compiler/ir/backend.jvm/entrypoint/src/org/jetbrains/kotlin/backend/jvm/JvmGeneratorExtensionsImpl.kt b/compiler/ir/backend.jvm/entrypoint/src/org/jetbrains/kotlin/backend/jvm/JvmGeneratorExtensionsImpl.kt index 2eacd58927a..c216d3ab1c6 100644 --- a/compiler/ir/backend.jvm/entrypoint/src/org/jetbrains/kotlin/backend/jvm/JvmGeneratorExtensionsImpl.kt +++ b/compiler/ir/backend.jvm/entrypoint/src/org/jetbrains/kotlin/backend/jvm/JvmGeneratorExtensionsImpl.kt @@ -38,6 +38,7 @@ import org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor import org.jetbrains.kotlin.load.java.descriptors.getParentJavaStaticClassScope import org.jetbrains.kotlin.load.java.sam.JavaSingleAbstractMethodUtils import org.jetbrains.kotlin.load.java.typeEnhancement.hasEnhancedNullability +import org.jetbrains.kotlin.load.kotlin.FacadeClassSource import org.jetbrains.kotlin.load.kotlin.JvmPackagePartSource import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinarySourceElement import org.jetbrains.kotlin.name.FqName @@ -55,10 +56,12 @@ import org.jetbrains.kotlin.resolve.jvm.JvmClassName import org.jetbrains.kotlin.resolve.jvm.annotations.hasJvmFieldAnnotation import org.jetbrains.kotlin.resolve.jvm.annotations.isJvmRecord import org.jetbrains.kotlin.resolve.scopes.MemberScope +import org.jetbrains.kotlin.serialization.deserialization.descriptors.DescriptorWithContainerSource import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedContainerSource import org.jetbrains.kotlin.synthetic.SyntheticJavaPropertyDescriptor import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.typeUtil.replaceAnnotations +import org.jetbrains.kotlin.utils.addToStdlib.safeAs open class JvmGeneratorExtensionsImpl( configuration: CompilerConfiguration, @@ -81,6 +84,10 @@ open class JvmGeneratorExtensionsImpl( companion object Instance : JvmSamConversion() } + override fun getContainerSource(descriptor: DeclarationDescriptor): DeserializedContainerSource? { + return descriptor.safeAs()?.containerSource + } + override fun computeFieldVisibility(descriptor: PropertyDescriptor): DescriptorVisibility? = if (descriptor.hasJvmFieldAnnotation() || descriptor is JavaCallableMemberDescriptor) descriptor.visibility @@ -98,7 +105,7 @@ open class JvmGeneratorExtensionsImpl( deserializedSource: DeserializedContainerSource, stubGenerator: DeclarationStubGenerator ): IrClass? { - if (!generateFacades || deserializedSource !is JvmPackagePartSource) return null + if (!generateFacades || deserializedSource !is FacadeClassSource) return null val facadeName = deserializedSource.facadeClassName ?: deserializedSource.className return JvmFileFacadeClass( if (deserializedSource.facadeClassName != null) IrDeclarationOrigin.JVM_MULTIFILE_CLASS else IrDeclarationOrigin.FILE_CLASS, diff --git a/compiler/ir/backend.jvm/entrypoint/src/org/jetbrains/kotlin/backend/jvm/JvmIrCodegenFactory.kt b/compiler/ir/backend.jvm/entrypoint/src/org/jetbrains/kotlin/backend/jvm/JvmIrCodegenFactory.kt index a6e1d46b041..13ac0e81e79 100644 --- a/compiler/ir/backend.jvm/entrypoint/src/org/jetbrains/kotlin/backend/jvm/JvmIrCodegenFactory.kt +++ b/compiler/ir/backend.jvm/entrypoint/src/org/jetbrains/kotlin/backend/jvm/JvmIrCodegenFactory.kt @@ -34,6 +34,8 @@ import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi2ir.Psi2IrConfiguration import org.jetbrains.kotlin.psi2ir.Psi2IrTranslator import org.jetbrains.kotlin.psi2ir.generators.DeclarationStubGeneratorImpl +import org.jetbrains.kotlin.psi2ir.generators.fragments.EvaluatorFragmentInfo +import org.jetbrains.kotlin.psi2ir.generators.fragments.FragmentContext import org.jetbrains.kotlin.psi2ir.generators.generateTypicalIrProviderList import org.jetbrains.kotlin.psi2ir.preprocessing.SourceDeclarationsPreprocessor import org.jetbrains.kotlin.resolve.CleanableBindingContext @@ -44,6 +46,7 @@ open class JvmIrCodegenFactory( private val externalMangler: JvmDescriptorMangler? = null, private val externalSymbolTable: SymbolTable? = null, private val jvmGeneratorExtensions: JvmGeneratorExtensionsImpl = JvmGeneratorExtensionsImpl(configuration), + private val evaluatorFragmentInfoForPsi2Ir: EvaluatorFragmentInfo? = null ) : CodegenFactory { data class JvmIrBackendInput( val irModuleFragment: IrModuleFragment, @@ -65,7 +68,13 @@ open class JvmIrCodegenFactory( } val psi2ir = Psi2IrTranslator(input.languageVersionSettings, Psi2IrConfiguration(input.ignoreErrors)) val messageLogger = input.configuration[IrMessageLogger.IR_MESSAGE_LOGGER] ?: IrMessageLogger.None - val psi2irContext = psi2ir.createGeneratorContext(input.module, input.bindingContext, symbolTable, jvmGeneratorExtensions) + val psi2irContext = psi2ir.createGeneratorContext( + input.module, + input.bindingContext, + symbolTable, + jvmGeneratorExtensions, + fragmentContext = if (evaluatorFragmentInfoForPsi2Ir != null) FragmentContext() else null, + ) val pluginExtensions = IrGenerationExtension.getInstances(input.project) val stubGenerator = @@ -134,10 +143,22 @@ open class JvmIrCodegenFactory( } irLinker.deserializeIrModuleHeader(it, kotlinLibrary, _moduleName = it.name.asString()) } - val irProviders = listOf(irLinker) + + val irProviders = if (evaluatorFragmentInfoForPsi2Ir != null) { + listOf(stubGenerator, irLinker) + } else { + listOf(irLinker) + } val irModuleFragment = - psi2ir.generateModuleFragment(psi2irContext, input.files, irProviders, pluginExtensions, expectDescriptorToSymbol = null) + psi2ir.generateModuleFragment( + psi2irContext, + input.files, + irProviders, + pluginExtensions, + expectDescriptorToSymbol = null, + fragmentInfo = evaluatorFragmentInfoForPsi2Ir) + irLinker.postProcess() stubGenerator.unboundSymbolGeneration = true diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/Psi2IrTranslator.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/Psi2IrTranslator.kt index 9b42bc188de..a1b43604efb 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/Psi2IrTranslator.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/Psi2IrTranslator.kt @@ -31,6 +31,9 @@ import org.jetbrains.kotlin.psi2ir.generators.GeneratorContext import org.jetbrains.kotlin.psi2ir.generators.GeneratorExtensions import org.jetbrains.kotlin.psi2ir.generators.ModuleGenerator import org.jetbrains.kotlin.psi2ir.generators.TypeTranslatorImpl +import org.jetbrains.kotlin.psi2ir.generators.fragments.EvaluatorFragmentInfo +import org.jetbrains.kotlin.psi2ir.generators.fragments.FragmentContext +import org.jetbrains.kotlin.psi2ir.generators.fragments.FragmentModuleGenerator import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.utils.SmartList @@ -52,7 +55,8 @@ class Psi2IrTranslator( moduleDescriptor: ModuleDescriptor, bindingContext: BindingContext, symbolTable: SymbolTable, - extensions: GeneratorExtensions = GeneratorExtensions() + extensions: GeneratorExtensions = GeneratorExtensions(), + fragmentContext: FragmentContext? = null ): GeneratorContext { val typeTranslator = TypeTranslatorImpl(symbolTable, languageVersionSettings, moduleDescriptor, extensions = extensions) return GeneratorContext( @@ -64,6 +68,7 @@ class Psi2IrTranslator( extensions, typeTranslator, IrBuiltInsOverDescriptors(moduleDescriptor.builtIns, typeTranslator, symbolTable), + fragmentContext ) } @@ -72,9 +77,13 @@ class Psi2IrTranslator( ktFiles: Collection, irProviders: List, linkerExtensions: Collection, - expectDescriptorToSymbol: MutableMap? = null + expectDescriptorToSymbol: MutableMap? = null, + fragmentInfo: EvaluatorFragmentInfo? = null ): IrModuleFragment { - val moduleGenerator = ModuleGenerator(context, expectDescriptorToSymbol) + val moduleGenerator = fragmentInfo?.let { + FragmentModuleGenerator(context, it) + } ?: ModuleGenerator(context, expectDescriptorToSymbol) + val irModule = moduleGenerator.generateModuleFragment(ktFiles) val deserializers = irProviders.filterIsInstance() diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/CallGenerator.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/CallGenerator.kt index c1f94c47d38..fcf7c0d2e13 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/CallGenerator.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/CallGenerator.kt @@ -89,8 +89,16 @@ class CallGenerator(statementGenerator: StatementGenerator) : StatementGenerator resolvedCall: ResolvedCall<*>?, origin: IrStatementOrigin?, smartCastIrType: IrType? = null - ): IrExpression = - when (descriptor) { + ): IrExpression { + context.fragmentContext?.capturedDescriptorToFragmentParameterMap?.get(descriptor)?.let { + val getValue = IrGetValueImpl(startOffset, endOffset, it.descriptor.type.toIrType(), it, origin) + return if (smartCastIrType != null) { + IrTypeOperatorCallImpl(startOffset, endOffset, smartCastIrType, IrTypeOperator.IMPLICIT_CAST, smartCastIrType, getValue) + } else { + getValue + } + } + return when (descriptor) { is FakeCallableDescriptorForObject -> generateValueReference(startOffset, endOffset, descriptor.getReferencedDescriptor(), resolvedCall, origin, smartCastIrType) is TypeAliasDescriptor -> @@ -117,6 +125,7 @@ class CallGenerator(statementGenerator: StatementGenerator) : StatementGenerator else -> TODO("Unexpected callable descriptor: $descriptor ${descriptor::class.java.simpleName}") } + } private fun generateGetVariable( startOffset: Int, diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/GeneratorContext.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/GeneratorContext.kt index 341ee897c71..d3d3c232fb5 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/GeneratorContext.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/GeneratorContext.kt @@ -9,16 +9,18 @@ import org.jetbrains.kotlin.backend.common.SamTypeApproximator import org.jetbrains.kotlin.builtins.ReflectionTypes import org.jetbrains.kotlin.config.LanguageVersionSettings import org.jetbrains.kotlin.descriptors.CallableDescriptor +import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.descriptors.ModuleDescriptor import org.jetbrains.kotlin.descriptors.NotFoundClasses import org.jetbrains.kotlin.ir.IrBuiltIns import org.jetbrains.kotlin.ir.builders.IrGeneratorContext -import org.jetbrains.kotlin.ir.descriptors.IrBuiltInsOverDescriptors import org.jetbrains.kotlin.ir.expressions.IrDeclarationReference +import org.jetbrains.kotlin.ir.symbols.IrValueParameterSymbol import org.jetbrains.kotlin.ir.util.SymbolTable import org.jetbrains.kotlin.ir.util.TypeTranslator import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi2ir.Psi2IrConfiguration +import org.jetbrains.kotlin.psi2ir.generators.fragments.FragmentContext import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.storage.LockBasedStorageManager @@ -31,7 +33,8 @@ class GeneratorContext private constructor( val extensions: GeneratorExtensions, val typeTranslator: TypeTranslator, override val irBuiltIns: IrBuiltIns, - internal val callToSubstitutedDescriptorMap: MutableMap + internal val callToSubstitutedDescriptorMap: MutableMap, + internal val fragmentContext: FragmentContext?, ) : IrGeneratorContext { constructor( @@ -43,6 +46,7 @@ class GeneratorContext private constructor( extensions: GeneratorExtensions, typeTranslator: TypeTranslator, irBuiltIns: IrBuiltIns, + fragmentContext: FragmentContext? = null ) : this( configuration, moduleDescriptor, @@ -52,7 +56,8 @@ class GeneratorContext private constructor( extensions, typeTranslator, irBuiltIns, - mutableMapOf() + mutableMapOf(), + fragmentContext, ) val constantValueGenerator = typeTranslator.constantValueGenerator @@ -76,8 +81,8 @@ class GeneratorContext private constructor( extensions, TypeTranslatorImpl(symbolTable, languageVersionSettings, moduleDescriptor, extensions = extensions, ktFile = ktFile), irBuiltIns, - callToSubstitutedDescriptorMap + callToSubstitutedDescriptorMap, + fragmentContext, ) } - } diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/ModuleGenerator.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/ModuleGenerator.kt index cb5d09b3b3b..e2c39f64687 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/ModuleGenerator.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/ModuleGenerator.kt @@ -34,12 +34,12 @@ import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.lazy.descriptors.findPackageFragmentForFile import org.jetbrains.kotlin.utils.addIfNotNull -class ModuleGenerator( +open class ModuleGenerator( override val context: GeneratorContext, private val expectDescriptorToSymbol: MutableMap? = null ) : Generator { - fun generateModuleFragment(ktFiles: Collection): IrModuleFragment = + open fun generateModuleFragment(ktFiles: Collection): IrModuleFragment = IrModuleFragmentImpl(context.moduleDescriptor, context.irBuiltIns).also { irModule -> ktFiles.toSet().mapTo(irModule.files) { ktFile -> val fileContext = context.createFileScopeContext(ktFile) diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/fragments/EvaluatorFragmentInfo.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/fragments/EvaluatorFragmentInfo.kt new file mode 100644 index 00000000000..fd941e67415 --- /dev/null +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/fragments/EvaluatorFragmentInfo.kt @@ -0,0 +1,26 @@ +/* + * Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.psi2ir.generators.fragments + +import org.jetbrains.kotlin.descriptors.ClassDescriptor +import org.jetbrains.kotlin.descriptors.DeclarationDescriptor +import org.jetbrains.kotlin.descriptors.FunctionDescriptor + +/** + * Information for compilation of code fragments for `evaluate expression` + * + * The expression evaluator works by wrapping a code fragment in a method. + * The free variables of the fragment are closed over by the parameters of + * that method, and finally the method is placed in a class. + * + * This data structure contains "synthesized" descriptors for that class, + * method and parameter lay-out. + */ +class EvaluatorFragmentInfo( + val classDescriptor: ClassDescriptor, + val methodDescriptor: FunctionDescriptor, + val parameters: List +) \ No newline at end of file diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/fragments/FragmentCompilerSymbolTableDecorator.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/fragments/FragmentCompilerSymbolTableDecorator.kt new file mode 100644 index 00000000000..387caa489f0 --- /dev/null +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/fragments/FragmentCompilerSymbolTableDecorator.kt @@ -0,0 +1,62 @@ +/* + * Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.psi2ir.generators.fragments + +import org.jetbrains.kotlin.descriptors.DeclarationDescriptor +import org.jetbrains.kotlin.descriptors.ParameterDescriptor +import org.jetbrains.kotlin.descriptors.ReceiverParameterDescriptor +import org.jetbrains.kotlin.descriptors.ValueDescriptor +import org.jetbrains.kotlin.ir.declarations.IrFactory +import org.jetbrains.kotlin.ir.symbols.IrValueParameterSymbol +import org.jetbrains.kotlin.ir.symbols.IrValueSymbol +import org.jetbrains.kotlin.ir.util.IdSignatureComposer +import org.jetbrains.kotlin.ir.util.NameProvider +import org.jetbrains.kotlin.ir.util.SymbolTable +import org.jetbrains.kotlin.psi2ir.generators.fragments.EvaluatorFragmentInfo +import org.jetbrains.kotlin.resolve.scopes.receivers.ExtensionReceiver +import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitClassReceiver +import org.jetbrains.kotlin.resolve.scopes.receivers.ThisClassReceiver + +// Used from CodeFragmentCompiler for IDE Debugger Plug-In +@Suppress("unused") +class FragmentCompilerSymbolTableDecorator( + signatureComposer: IdSignatureComposer, + irFactory: IrFactory, + private val fragmentInfo: EvaluatorFragmentInfo, + nameProvider: NameProvider = NameProvider.DEFAULT, +) : SymbolTable(signatureComposer, irFactory, nameProvider) { + + override fun referenceValueParameter(descriptor: ParameterDescriptor): IrValueParameterSymbol { + if (descriptor !is ReceiverParameterDescriptor) return super.referenceValueParameter(descriptor) + + val finderPredicate = when (val receiverValue = descriptor.value) { + is ExtensionReceiver -> { targetDescriptor: DeclarationDescriptor -> + receiverValue == (targetDescriptor as? ReceiverParameterDescriptor)?.value + } + is ThisClassReceiver -> { targetDescriptor: DeclarationDescriptor -> + receiverValue.classDescriptor == targetDescriptor.original + } + else -> TODO("Unimplemented") + } + + val parameterPosition = + fragmentInfo.parameters.indexOfFirst(finderPredicate) + if (parameterPosition > -1) { + return super.referenceValueParameter(fragmentInfo.methodDescriptor.valueParameters[parameterPosition]) + } + return super.referenceValueParameter(descriptor) + } + + override fun referenceValue(value: ValueDescriptor): IrValueSymbol { + val parameterPosition = + fragmentInfo.parameters.indexOf(value) + if (parameterPosition > -1) { + return super.referenceValueParameter(fragmentInfo.methodDescriptor.valueParameters[parameterPosition]) + } + + return super.referenceValue(value) + } +} \ No newline at end of file diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/fragments/FragmentContext.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/fragments/FragmentContext.kt new file mode 100644 index 00000000000..84257eb6b3d --- /dev/null +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/fragments/FragmentContext.kt @@ -0,0 +1,13 @@ +/* + * Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.psi2ir.generators.fragments + +import org.jetbrains.kotlin.descriptors.DeclarationDescriptor +import org.jetbrains.kotlin.ir.symbols.IrValueParameterSymbol + +class FragmentContext( + val capturedDescriptorToFragmentParameterMap: MutableMap = mutableMapOf() +) \ No newline at end of file diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/fragments/FragmentDeclarationGenerator.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/fragments/FragmentDeclarationGenerator.kt new file mode 100644 index 00000000000..38ef2764339 --- /dev/null +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/fragments/FragmentDeclarationGenerator.kt @@ -0,0 +1,129 @@ +/* + * Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.psi2ir.generators.fragments + +import org.jetbrains.kotlin.descriptors.Modality +import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor +import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET +import org.jetbrains.kotlin.ir.declarations.* +import org.jetbrains.kotlin.ir.symbols.impl.IrConstructorPublicSymbolImpl +import org.jetbrains.kotlin.ir.util.createIrClassFromDescriptor +import org.jetbrains.kotlin.ir.util.declareSimpleFunctionWithOverrides +import org.jetbrains.kotlin.ir.util.defaultType +import org.jetbrains.kotlin.ir.util.withScope +import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.psi.KtBlockCodeFragment +import org.jetbrains.kotlin.psi2ir.generators.Generator +import org.jetbrains.kotlin.psi2ir.generators.GeneratorContext +import org.jetbrains.kotlin.psi2ir.generators.createBodyGenerator +import org.jetbrains.kotlin.types.KotlinType + +open class FragmentDeclarationGenerator( + override val context: GeneratorContext, + private val fragmentInfo: EvaluatorFragmentInfo +) : Generator { + + fun generateClassForCodeFragment(ktFile: KtBlockCodeFragment): IrClass { + val classDescriptor = fragmentInfo.classDescriptor + val startOffset = UNDEFINED_OFFSET + val endOffset = UNDEFINED_OFFSET + + return context.symbolTable.declareClass(classDescriptor) { + context.irFactory.createIrClassFromDescriptor( + startOffset, endOffset, + IrDeclarationOrigin.DEFINED, + symbol = it, + classDescriptor, + context.symbolTable.nameProvider.nameForDeclaration(classDescriptor), + classDescriptor.visibility, + Modality.FINAL + ) + }.buildWithScope { irClass -> + irClass.thisReceiver = context.symbolTable.declareValueParameter( + startOffset, endOffset, + IrDeclarationOrigin.INSTANCE_RECEIVER, + classDescriptor.thisAsReceiverParameter, + classDescriptor.thisAsReceiverParameter.type.toIrType() + ) + + generatePrimaryConstructor(irClass) + + irClass.declarations.add( + generateFunctionForFragment(ktFile) + ) + } + } + + private fun generatePrimaryConstructor(irClass: IrClass) { + val constructor = context.irFactory.createConstructor( + startOffset = UNDEFINED_OFFSET, + endOffset = UNDEFINED_OFFSET, + origin = IrDeclarationOrigin.DEFINED, + symbol = IrConstructorPublicSymbolImpl(context.symbolTable.signaturer.composeSignature(irClass.descriptor)!!), + Name.special(""), + irClass.visibility, + irClass.defaultType, + isInline = false, + isExternal = false, + isPrimary = true, + isExpect = false + ) + constructor.parent = irClass + constructor.body = context.irFactory.createBlockBody(UNDEFINED_OFFSET, UNDEFINED_OFFSET) + irClass.addMember(constructor) + } + + private fun generateFunctionForFragment(ktFile: KtBlockCodeFragment): IrSimpleFunction { + return context.symbolTable.declareSimpleFunctionWithOverrides( + UNDEFINED_OFFSET, UNDEFINED_OFFSET, + IrDeclarationOrigin.DEFINED, + fragmentInfo.methodDescriptor + ).buildWithScope { irFunction -> + irFunction.returnType = fragmentInfo.methodDescriptor.returnType!!.toIrType() + generateFragmentValueParameterDeclarations(irFunction) + irFunction.body = createBodyGenerator(irFunction.symbol).generateExpressionBody(ktFile.getContentElement()) + } + } + + private fun generateFragmentValueParameterDeclarations(irFunction: IrSimpleFunction) { + val functionDescriptor = irFunction.descriptor + functionDescriptor.valueParameters.forEachIndexed { index, valueParameterDescriptor -> + irFunction.valueParameters += declareParameter(valueParameterDescriptor).apply { + context.fragmentContext!!.capturedDescriptorToFragmentParameterMap[fragmentInfo.parameters[index]] = this.symbol + } + } + } + + private fun declareParameter(descriptor: ValueParameterDescriptor): IrValueParameter { + // Parameter must be _assignable_: + // These parameters model the captured variables of the fragment. The captured + // _values_ are extracted from the call stack of the JVM being debugged, and supplied + // to the fragment evaluator via these parameters. Any modifications by the fragment + // are written directly to the parameter, and then extracted from the stack frame + // of the interpreter/JVM evaluating the fragment and written back into the call + // stack of the JVM being debugged. + return context.symbolTable.declareValueParameter( + UNDEFINED_OFFSET, + UNDEFINED_OFFSET, + IrDeclarationOrigin.DEFINED, + descriptor, + descriptor.type.toIrType(), + (descriptor as? ValueParameterDescriptor)?.varargElementType?.toIrType(), + null, + isAssignable = true + ) + } + + private fun KotlinType.toIrType() = context.typeTranslator.translateType(this) + + private inline fun T.buildWithScope(builder: (T) -> Unit): T = + also { irDeclaration: T -> + context.symbolTable.withScope(irDeclaration) { + builder(irDeclaration) + } + } + +} \ No newline at end of file diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/fragments/FragmentModuleGenerator.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/fragments/FragmentModuleGenerator.kt new file mode 100644 index 00000000000..dd0ccd67287 --- /dev/null +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/fragments/FragmentModuleGenerator.kt @@ -0,0 +1,47 @@ +/* + * Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.psi2ir.generators.fragments + +import org.jetbrains.kotlin.ir.PsiIrFileEntry +import org.jetbrains.kotlin.ir.declarations.IrModuleFragment +import org.jetbrains.kotlin.ir.declarations.impl.IrFileImpl +import org.jetbrains.kotlin.ir.declarations.impl.IrModuleFragmentImpl +import org.jetbrains.kotlin.ir.util.patchDeclarationParents +import org.jetbrains.kotlin.psi.KtBlockCodeFragment +import org.jetbrains.kotlin.psi.KtFile +import org.jetbrains.kotlin.psi2ir.generators.GeneratorContext +import org.jetbrains.kotlin.psi2ir.generators.ModuleGenerator +import org.jetbrains.kotlin.resolve.lazy.descriptors.findPackageFragmentForFile + +class FragmentModuleGenerator( + override val context: GeneratorContext, + private val fragmentInfo: EvaluatorFragmentInfo +) : ModuleGenerator(context, expectDescriptorToSymbol = null) { + + override fun generateModuleFragment( + ktFiles: Collection, + ): IrModuleFragment { + val ktBlockCodeFragment = ktFiles.singleOrNull() as? KtBlockCodeFragment + ?: TODO("Multiple fragments in one compilation not understood and implemented yet") + return IrModuleFragmentImpl(context.moduleDescriptor, context.irBuiltIns).also { irModule -> + val irDeclarationGenerator = FragmentDeclarationGenerator(context, fragmentInfo) + irModule.files.add( + createEmptyIrFile(ktBlockCodeFragment).apply { + declarations.add( + irDeclarationGenerator.generateClassForCodeFragment(ktBlockCodeFragment) + ) + patchDeclarationParents() + } + ) + } + } + + private fun createEmptyIrFile(ktFile: KtFile): IrFileImpl { + val fileEntry = PsiIrFileEntry(ktFile) + val packageFragmentDescriptor = context.moduleDescriptor.findPackageFragmentForFile(ktFile)!! + return IrFileImpl(fileEntry, packageFragmentDescriptor) + } +} \ No newline at end of file diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/intermediate/VariableLValue.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/intermediate/VariableLValue.kt index fa23aae2a0e..509a6183f67 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/intermediate/VariableLValue.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/intermediate/VariableLValue.kt @@ -48,7 +48,7 @@ class VariableLValue( IrSetValueImpl( startOffset, endOffset, context.irBuiltIns.unitType, - symbol.assertedCast { "Not a variable: ${symbol.descriptor}" }, + symbol, irExpression, origin ) diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/DeclarationStubGenerator.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/DeclarationStubGenerator.kt index da91412813b..2e999c96029 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/DeclarationStubGenerator.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/DeclarationStubGenerator.kt @@ -92,7 +92,7 @@ abstract class DeclarationStubGenerator( fun generateOrGetFacadeClass(descriptor: DeclarationDescriptor): IrClass? { val directMember = descriptor.safeAs()?.correspondingProperty ?: descriptor val packageFragment = directMember.containingDeclaration as? PackageFragmentDescriptor ?: return null - val containerSource = directMember.safeAs()?.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) diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/StubGeneratorExtensions.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/StubGeneratorExtensions.kt index 58f4ba9ae18..d0bf61e9810 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/StubGeneratorExtensions.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/StubGeneratorExtensions.kt @@ -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 diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/SymbolTable.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/SymbolTable.kt index 27db7179a1c..e3983043389 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/SymbolTable.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/SymbolTable.kt @@ -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") } diff --git a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/DescriptorByIdSignatureFinder.kt b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/DescriptorByIdSignatureFinder.kt index a2d8a2da27a..91ef3394c66 100644 --- a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/DescriptorByIdSignatureFinder.kt +++ b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/DescriptorByIdSignatureFinder.kt @@ -22,7 +22,9 @@ class DescriptorByIdSignatureFinder( private val lookupMode: LookupMode ) { init { - assert(lookupMode != LookupMode.MODULE_ONLY || moduleDescriptor is ModuleDescriptorImpl) + assert(lookupMode != LookupMode.MODULE_ONLY || moduleDescriptor is ModuleDescriptorImpl) { + "Incorrect lookup mode $lookupMode for $moduleDescriptor" + } } /** diff --git a/core/deserialization.common.jvm/src/org/jetbrains/kotlin/load/kotlin/FacadeClassSource.kt b/core/deserialization.common.jvm/src/org/jetbrains/kotlin/load/kotlin/FacadeClassSource.kt new file mode 100644 index 00000000000..f3af1f3abd3 --- /dev/null +++ b/core/deserialization.common.jvm/src/org/jetbrains/kotlin/load/kotlin/FacadeClassSource.kt @@ -0,0 +1,13 @@ +/* + * Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.load.kotlin + +import org.jetbrains.kotlin.resolve.jvm.JvmClassName + +interface FacadeClassSource { + val className: JvmClassName + val facadeClassName: JvmClassName? +} \ No newline at end of file diff --git a/core/deserialization.common.jvm/src/org/jetbrains/kotlin/load/kotlin/JvmPackagePartSource.kt b/core/deserialization.common.jvm/src/org/jetbrains/kotlin/load/kotlin/JvmPackagePartSource.kt index 418779741af..6a59045c7b7 100644 --- a/core/deserialization.common.jvm/src/org/jetbrains/kotlin/load/kotlin/JvmPackagePartSource.kt +++ b/core/deserialization.common.jvm/src/org/jetbrains/kotlin/load/kotlin/JvmPackagePartSource.kt @@ -20,15 +20,15 @@ import org.jetbrains.kotlin.serialization.deserialization.descriptors.Deserializ import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedContainerSource class JvmPackagePartSource( - val className: JvmClassName, - val facadeClassName: JvmClassName?, + override val className: JvmClassName, + override val facadeClassName: JvmClassName?, packageProto: ProtoBuf.Package, nameResolver: NameResolver, override val incompatibility: IncompatibleVersionErrorData? = null, override val isPreReleaseInvisible: Boolean = false, override val abiStability: DeserializedContainerAbiStability = DeserializedContainerAbiStability.STABLE, val knownJvmBinaryClass: KotlinJvmBinaryClass? = null -) : DeserializedContainerSource { +) : DeserializedContainerSource, FacadeClassSource { constructor( kotlinClass: KotlinJvmBinaryClass, packageProto: ProtoBuf.Package,