Kapt+JVM_IR: support annotations with error types
This is a hack to implement KT-32596 in the JVM IR version of kapt. Basically we allow psi2ir to generate annotations whose classifier is error class, which happens when it's unresolved. Because there's no physical IR for an error class, we create stub IR for it via SyntheticDeclarationsGenerator in case we'll need it. With this hack, annotations with unresolved classifiers magically survive all the way until the codegen (with a minor change in IrBasedDescriptors) where they are generated as `@error.NonExistentClass`, which then gets corrected by the kapt's "correct error types" mode as in all other cases of error types.
This commit is contained in:
@@ -64,7 +64,10 @@ class Psi2IrTranslator(
|
||||
extensions: GeneratorExtensions = GeneratorExtensions(),
|
||||
fragmentContext: FragmentContext? = null
|
||||
): GeneratorContext {
|
||||
val typeTranslator = TypeTranslatorImpl(symbolTable, languageVersionSettings, moduleDescriptor, extensions = extensions)
|
||||
val typeTranslator = TypeTranslatorImpl(
|
||||
symbolTable, languageVersionSettings, moduleDescriptor, extensions = extensions,
|
||||
allowErrorTypeInAnnotations = configuration.skipBodies,
|
||||
)
|
||||
return GeneratorContext(
|
||||
configuration,
|
||||
moduleDescriptor,
|
||||
|
||||
+2
-1
@@ -22,7 +22,8 @@ class ConstantValueGeneratorImpl(
|
||||
moduleDescriptor: ModuleDescriptor,
|
||||
symbolTable: ReferenceSymbolTable,
|
||||
typeTranslator: TypeTranslator,
|
||||
) : ConstantValueGenerator(moduleDescriptor, symbolTable, typeTranslator) {
|
||||
allowErrorTypeInAnnotations: Boolean,
|
||||
) : ConstantValueGenerator(moduleDescriptor, symbolTable, typeTranslator, allowErrorTypeInAnnotations) {
|
||||
override fun extractAnnotationOffsets(annotationDescriptor: AnnotationDescriptor): Pair<Int, Int> =
|
||||
extractOffsets(annotationDescriptor.source)
|
||||
|
||||
|
||||
+4
-5
@@ -9,15 +9,11 @@ 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.declarations.IrClass
|
||||
import org.jetbrains.kotlin.ir.expressions.IrDeclarationReference
|
||||
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
||||
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
|
||||
@@ -83,7 +79,10 @@ class GeneratorContext private constructor(
|
||||
languageVersionSettings,
|
||||
symbolTable,
|
||||
extensions,
|
||||
TypeTranslatorImpl(symbolTable, languageVersionSettings, moduleDescriptor, extensions = extensions, ktFile = ktFile),
|
||||
TypeTranslatorImpl(
|
||||
symbolTable, languageVersionSettings, moduleDescriptor, extensions = extensions, ktFile = ktFile,
|
||||
allowErrorTypeInAnnotations = configuration.skipBodies,
|
||||
),
|
||||
irBuiltIns,
|
||||
callToSubstitutedDescriptorMap,
|
||||
fragmentContext,
|
||||
|
||||
+35
-1
@@ -18,7 +18,11 @@ package org.jetbrains.kotlin.psi2ir.generators
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.CodegenUtil
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.impl.EmptyPackageFragmentDescriptor
|
||||
import org.jetbrains.kotlin.ir.IrFileEntry
|
||||
import org.jetbrains.kotlin.ir.PsiIrFileEntry
|
||||
import org.jetbrains.kotlin.ir.SourceRangeInfo
|
||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||
import org.jetbrains.kotlin.ir.declarations.DescriptorMetadataSource
|
||||
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrFileImpl
|
||||
@@ -28,10 +32,12 @@ import org.jetbrains.kotlin.ir.symbols.IrSymbol
|
||||
import org.jetbrains.kotlin.ir.util.ExternalDependenciesGenerator
|
||||
import org.jetbrains.kotlin.ir.util.patchDeclarationParents
|
||||
import org.jetbrains.kotlin.ir.visitors.acceptVoid
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.psi2ir.transformations.insertImplicitCasts
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.lazy.descriptors.findPackageFragmentForFile
|
||||
import org.jetbrains.kotlin.types.error.ErrorUtils
|
||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||
|
||||
open class ModuleGenerator(
|
||||
@@ -75,6 +81,13 @@ open class ModuleGenerator(
|
||||
|
||||
IrSyntheticDeclarationGenerator(context).generateSyntheticDeclarations(irFile)
|
||||
|
||||
if (context.configuration.skipBodies) {
|
||||
// In KAPT3 mode (skipBodies = true), we create stub IR for error class, so that it would be possible to have annotations
|
||||
// with unresolved types in the IR and they could survive all transformations up until the codegen.
|
||||
// This is a hack which should preferably be removed as soon as KAPT3 is no longer used.
|
||||
createStubIrForErrorClass()
|
||||
}
|
||||
|
||||
insertImplicitCasts(irFile, context)
|
||||
context.callToSubstitutedDescriptorMap.clear()
|
||||
|
||||
@@ -85,11 +98,32 @@ open class ModuleGenerator(
|
||||
return irFile
|
||||
}
|
||||
|
||||
fun createEmptyIrFile(ktFile: KtFile, module: IrModuleFragment): IrFileImpl {
|
||||
private fun createEmptyIrFile(ktFile: KtFile, module: IrModuleFragment): IrFileImpl {
|
||||
val fileEntry = PsiIrFileEntry(ktFile)
|
||||
val packageFragmentDescriptor = context.moduleDescriptor.findPackageFragmentForFile(ktFile)!!
|
||||
return IrFileImpl(fileEntry, packageFragmentDescriptor, module).apply {
|
||||
metadata = DescriptorMetadataSource.File(CodegenUtil.getMemberDescriptorsToGenerate(ktFile, context.bindingContext))
|
||||
}
|
||||
}
|
||||
|
||||
private fun createStubIrForErrorClass() {
|
||||
val fakeFileEntry = object : IrFileEntry {
|
||||
override val name: String = "<error-class>"
|
||||
override val maxOffset: Int = UNDEFINED_OFFSET
|
||||
|
||||
override fun getSourceRangeInfo(beginOffset: Int, endOffset: Int): SourceRangeInfo = TODO("Not yet implemented")
|
||||
override fun getLineNumber(offset: Int): Int = TODO("Not yet implemented")
|
||||
override fun getColumnNumber(offset: Int): Int = TODO("Not yet implemented")
|
||||
}
|
||||
val fakeFile = IrFileImpl(
|
||||
fakeFileEntry,
|
||||
EmptyPackageFragmentDescriptor(context.moduleDescriptor, FqName(fakeFileEntry.name)),
|
||||
)
|
||||
val gen = SyntheticDeclarationsGenerator(context)
|
||||
gen.visitClassDescriptor(ErrorUtils.errorClass, fakeFile)
|
||||
gen.visitConstructorDescriptor(
|
||||
ErrorUtils.errorClass.unsubstitutedPrimaryConstructor!!,
|
||||
context.symbolTable.referenceClass(ErrorUtils.errorClass).owner,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
+5
-3
@@ -14,16 +14,18 @@ import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.resolve.source.getPsi
|
||||
import org.jetbrains.kotlin.types.*
|
||||
|
||||
open class TypeTranslatorImpl(
|
||||
class TypeTranslatorImpl(
|
||||
symbolTable: ReferenceSymbolTable,
|
||||
languageVersionSettings: LanguageVersionSettings,
|
||||
moduleDescriptor: ModuleDescriptor,
|
||||
typeParametersResolverBuilder: () -> TypeParametersResolver = { ScopedTypeParametersResolver() },
|
||||
enterTableScope: Boolean = false,
|
||||
extensions: StubGeneratorExtensions = StubGeneratorExtensions.EMPTY,
|
||||
private val ktFile: KtFile? = null
|
||||
private val ktFile: KtFile? = null,
|
||||
allowErrorTypeInAnnotations: Boolean = false,
|
||||
) : TypeTranslator(symbolTable, languageVersionSettings, typeParametersResolverBuilder, enterTableScope, extensions) {
|
||||
override val constantValueGenerator: ConstantValueGenerator = ConstantValueGeneratorImpl(moduleDescriptor, symbolTable, this)
|
||||
override val constantValueGenerator: ConstantValueGenerator =
|
||||
ConstantValueGeneratorImpl(moduleDescriptor, symbolTable, this, allowErrorTypeInAnnotations)
|
||||
|
||||
private val typeApproximatorForNI = TypeApproximator(moduleDescriptor.builtIns, languageVersionSettings)
|
||||
|
||||
|
||||
@@ -30,6 +30,7 @@ import org.jetbrains.kotlin.serialization.deserialization.descriptors.Deserializ
|
||||
import org.jetbrains.kotlin.storage.LockBasedStorageManager
|
||||
import org.jetbrains.kotlin.storage.StorageManager
|
||||
import org.jetbrains.kotlin.types.*
|
||||
import org.jetbrains.kotlin.types.error.ErrorUtils
|
||||
|
||||
/* Descriptors that serve purely as a view into IR structures.
|
||||
Created each time at the borderline between IR-based and descriptor-based code (such as inliner).
|
||||
@@ -44,11 +45,21 @@ abstract class IrBasedDeclarationDescriptor<T : IrDeclaration>(val owner: T) : D
|
||||
}
|
||||
|
||||
private fun IrConstructorCall.toAnnotationDescriptor(): AnnotationDescriptor {
|
||||
assert(symbol.owner.parentAsClass.isAnnotationClass) {
|
||||
val annotationClass = symbol.owner.parentAsClass
|
||||
|
||||
@OptIn(ObsoleteDescriptorBasedAPI::class)
|
||||
if (annotationClass.symbol.descriptor == ErrorUtils.errorClass) {
|
||||
// This should be possible only in case of KAPT3 where IR generated by psi2ir can have annotations with unresolved types.
|
||||
// Apparently annotations with unresolved types is a useful feature for KAPT3 in the "correct error types mode", see kt32596.kt.
|
||||
// This is a hack which should preferably be removed as soon as KAPT3 is no longer used.
|
||||
return AnnotationDescriptorImpl(type.toKotlinType(), emptyMap(), source)
|
||||
}
|
||||
|
||||
assert(annotationClass.isAnnotationClass) {
|
||||
"Expected call to constructor of annotation class but was: ${this.dump()}"
|
||||
}
|
||||
return AnnotationDescriptorImpl(
|
||||
symbol.owner.parentAsClass.defaultType.toIrBasedKotlinType(),
|
||||
annotationClass.defaultType.toIrBasedKotlinType(),
|
||||
symbol.owner.valueParameters.map { it.name to getValueArgument(it.index) }
|
||||
.filter { it.second != null }
|
||||
.associate { it.first to it.second!!.toConstantValue() },
|
||||
|
||||
@@ -21,6 +21,7 @@ import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.constants.*
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.TypeConstructorSubstitution
|
||||
import org.jetbrains.kotlin.types.error.ErrorClassDescriptor
|
||||
import org.jetbrains.kotlin.types.isError
|
||||
import org.jetbrains.kotlin.types.typeUtil.builtIns
|
||||
|
||||
@@ -28,6 +29,7 @@ abstract class ConstantValueGenerator(
|
||||
private val moduleDescriptor: ModuleDescriptor,
|
||||
private val symbolTable: ReferenceSymbolTable,
|
||||
private val typeTranslator: TypeTranslator,
|
||||
private val allowErrorTypeInAnnotations: Boolean,
|
||||
) {
|
||||
protected abstract fun extractAnnotationOffsets(annotationDescriptor: AnnotationDescriptor): Pair<Int, Int>
|
||||
|
||||
@@ -158,7 +160,10 @@ abstract class ConstantValueGenerator(
|
||||
if (annotationClassDescriptor !is ClassDescriptor) return null
|
||||
if (annotationClassDescriptor is NotFoundClasses.MockClassDescriptor) return null
|
||||
|
||||
assert(DescriptorUtils.isAnnotationClass(annotationClassDescriptor)) {
|
||||
assert(
|
||||
DescriptorUtils.isAnnotationClass(annotationClassDescriptor) ||
|
||||
(allowErrorTypeInAnnotations && annotationClassDescriptor is ErrorClassDescriptor)
|
||||
) {
|
||||
"Annotation class expected: $annotationClassDescriptor"
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
// CORRECT_ERROR_TYPES
|
||||
|
||||
@file:Suppress("UNRESOLVED_REFERENCE", "ANNOTATION_ARGUMENT_MUST_BE_CONST")
|
||||
@@ -15,6 +14,6 @@ class ErrorSomeMissingAnnotations
|
||||
|
||||
annotation class Anno(val klass: KClass<*>)
|
||||
|
||||
// EXPECTED_ERROR: (kotlin:10:1) cannot find symbol
|
||||
// EXPECTED_ERROR: (kotlin:13:1) cannot find symbol
|
||||
// EXPECTED_ERROR: (kotlin:7:1) cannot find symbol
|
||||
// EXPECTED_ERROR: (kotlin:9:1) cannot find symbol
|
||||
// EXPECTED_ERROR: (kotlin:12:1) cannot find symbol
|
||||
// EXPECTED_ERROR: (kotlin:6:1) cannot find symbol
|
||||
|
||||
Reference in New Issue
Block a user