Type translation, initial import

This commit is contained in:
Dmitry Petrov
2018-04-16 13:15:16 +03:00
parent d1fe32a486
commit d3a1d93460
7 changed files with 205 additions and 42 deletions
@@ -21,7 +21,6 @@ import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
import org.jetbrains.kotlin.ir.util.patchDeclarationParents
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi2ir.transformations.AnnotationGenerator
import org.jetbrains.kotlin.psi2ir.generators.GeneratorContext
import org.jetbrains.kotlin.psi2ir.generators.ModuleGenerator
import org.jetbrains.kotlin.psi2ir.transformations.generateAnnotationsForDeclarations
@@ -6,28 +6,36 @@
package org.jetbrains.kotlin.psi2ir.generators
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrGetEnumValueImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrVarargImpl
import org.jetbrains.kotlin.ir.util.SymbolTable
import org.jetbrains.kotlin.psi2ir.transformations.AnnotationGenerator
import org.jetbrains.kotlin.resolve.constants.*
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.typeUtil.builtIns
class ConstantValueGenerator(
private val context: GeneratorContext,
private val annotationGenerator: AnnotationGenerator? = null
private val moduleDescriptor: ModuleDescriptor,
private val symbolTable: SymbolTable,
private val annotationGenerator: AnnotationGenerator?
) {
constructor(
context: GeneratorContext,
annotationGenerator: AnnotationGenerator? = null
) : this(context.moduleDescriptor, context.symbolTable, annotationGenerator)
fun generateConstantValueAsExpression(
startOffset: Int,
endOffset: Int,
constantValue: ConstantValue<*>,
varargElementType: KotlinType? = null
): IrExpression {
val constantType = constantValue.getType(context.moduleDescriptor)
val constantType = constantValue.getType(moduleDescriptor)
return when (constantValue) {
is StringValue -> IrConstImpl.string(startOffset, endOffset, constantType, constantValue.value)
@@ -63,7 +71,7 @@ class ConstantValueGenerator(
IrGetEnumValueImpl(
startOffset, endOffset,
constantType,
context.symbolTable.referenceEnumEntry(enumEntryDescriptor)
symbolTable.referenceEnumEntry(enumEntryDescriptor)
)
}
@@ -6,6 +6,7 @@
package org.jetbrains.kotlin.psi2ir.transformations
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.descriptors.PropertySetterDescriptor
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget
@@ -15,6 +16,7 @@ import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.IrCall
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
import org.jetbrains.kotlin.ir.util.SymbolTable
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
import org.jetbrains.kotlin.ir.visitors.acceptVoid
@@ -26,12 +28,18 @@ import org.jetbrains.kotlin.resolve.source.PsiSourceElement
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
fun generateAnnotationsForDeclarations(context: GeneratorContext, irElement: IrElement) {
irElement.acceptVoid(AnnotationGenerator(context))
val annotationGenerator = AnnotationGenerator(context.moduleDescriptor, context.symbolTable)
irElement.acceptVoid(annotationGenerator)
}
class AnnotationGenerator(private val context: GeneratorContext) : IrElementVisitorVoid {
class AnnotationGenerator(
moduleDescriptor: ModuleDescriptor,
private val symbolTable: SymbolTable
) : IrElementVisitorVoid {
private val constantValueGenerator = ConstantValueGenerator(context, this)
constructor(context: GeneratorContext) : this(context.moduleDescriptor, context.symbolTable)
private val constantValueGenerator = ConstantValueGenerator(moduleDescriptor, symbolTable, this)
override fun visitElement(element: IrElement) {
element.acceptChildrenVoid(this)
@@ -82,7 +90,7 @@ class AnnotationGenerator(private val context: GeneratorContext) : IrElementVisi
val primaryConstructorDescriptor =
annotationClassDescriptor.safeAs<ClassDescriptor>()?.unsubstitutedPrimaryConstructor
?: throw AssertionError("No primary constructor for annotation class $annotationClassDescriptor")
val primaryConstructorSymbol = context.symbolTable.referenceConstructor(primaryConstructorDescriptor)
val primaryConstructorSymbol = symbolTable.referenceConstructor(primaryConstructorDescriptor)
val psi = annotationDescriptor.source.safeAs<PsiSourceElement>()?.psi
val startOffset = psi?.startOffset ?: UNDEFINED_OFFSET
@@ -34,42 +34,27 @@ import org.jetbrains.kotlin.types.isError
import org.jetbrains.kotlin.types.isNullabilityFlexible
import org.jetbrains.kotlin.types.typeUtil.makeNotNullable
import org.jetbrains.kotlin.types.upperIfFlexible
import java.util.*
fun insertImplicitCasts(builtIns: KotlinBuiltIns, element: IrElement, symbolTable: SymbolTable) {
element.transformChildren(InsertImplicitCasts(builtIns, symbolTable), null)
}
class InsertImplicitCasts(private val builtIns: KotlinBuiltIns, private val symbolTable: SymbolTable) : IrElementTransformerVoid() {
private val typeParameterScopes = ArrayDeque<Map<TypeParameterDescriptor, IrTypeParameterSymbol>>()
private val typeParameterResolver = ScopedTypeParametersResolver()
private inline fun <T> runInTypeParameterScope(typeParametersContainer: IrTypeParametersContainer, fn: () -> T): T {
enterTypeParameterScope(typeParametersContainer)
typeParameterResolver.enterTypeParameterScope(typeParametersContainer)
val result = fn()
leaveTypeParameterScope()
typeParameterResolver.leaveTypeParameterScope()
return result
}
private fun enterTypeParameterScope(typeParametersContainer: IrTypeParametersContainer) {
typeParameterScopes.addFirst(
typeParametersContainer.typeParameters.associate {
it.descriptor to it.symbol
}
)
}
private fun leaveTypeParameterScope() {
typeParameterScopes.removeFirst()
}
private fun resolveScopedTypeParameter(classifier: ClassifierDescriptor): IrTypeParameterSymbol? {
if (classifier !is TypeParameterDescriptor) return null
for (scope in typeParameterScopes) {
val local = scope[classifier]
if (local != null) return local
}
return null
}
private fun resolveScopedTypeParameter(classifier: ClassifierDescriptor): IrTypeParameterSymbol? =
if (classifier is TypeParameterDescriptor)
typeParameterResolver.resolveScopedTypeParameter(classifier)
else
null
override fun visitCallableReference(expression: IrCallableReference): IrExpression =
expression.transformPostfix {
@@ -0,0 +1,36 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. 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.transformations
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
import org.jetbrains.kotlin.ir.declarations.IrTypeParametersContainer
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
import java.util.*
class ScopedTypeParametersResolver {
private val typeParameterScopes = ArrayDeque<Map<TypeParameterDescriptor, IrTypeParameterSymbol>>()
fun enterTypeParameterScope(typeParametersContainer: IrTypeParametersContainer) {
typeParameterScopes.addFirst(
typeParametersContainer.typeParameters.associate {
it.descriptor to it.symbol
}
)
}
fun leaveTypeParameterScope() {
typeParameterScopes.removeFirst()
}
fun resolveScopedTypeParameter(typeParameterDescriptor: TypeParameterDescriptor): IrTypeParameterSymbol? {
for (scope in typeParameterScopes) {
val local = scope[typeParameterDescriptor]
if (local != null) return local
}
return null
}
}
@@ -0,0 +1,128 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. 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.types
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
import org.jetbrains.kotlin.ir.declarations.IrTypeParametersContainer
import org.jetbrains.kotlin.ir.expressions.IrCall
import org.jetbrains.kotlin.ir.expressions.IrExpression
import org.jetbrains.kotlin.ir.types.impl.IrTypeImpl
import org.jetbrains.kotlin.ir.util.SymbolTable
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
import org.jetbrains.kotlin.ir.visitors.acceptVoid
import org.jetbrains.kotlin.psi2ir.generators.GeneratorContext
import org.jetbrains.kotlin.psi2ir.transformations.AnnotationGenerator
import org.jetbrains.kotlin.psi2ir.transformations.ScopedTypeParametersResolver
import org.jetbrains.kotlin.types.*
class TypeTranslator(
moduleDescriptor: ModuleDescriptor,
private val symbolTable: SymbolTable
) {
constructor(context: GeneratorContext) : this(context.moduleDescriptor, context.symbolTable)
private val annotationGenerator = AnnotationGenerator(moduleDescriptor, symbolTable)
private val typeParametersResolver = ScopedTypeParametersResolver()
fun enterScope(irElement: IrTypeParametersContainer) {
typeParametersResolver.enterTypeParameterScope(irElement)
}
fun leaveScope() {
typeParametersResolver.leaveTypeParameterScope()
}
private fun resolveTypeParameter(typeParameterDescriptor: TypeParameterDescriptor) =
typeParametersResolver.resolveScopedTypeParameter(typeParameterDescriptor)
?: symbolTable.referenceTypeParameter(typeParameterDescriptor)
fun translateType(ktType: KotlinType): IrTypeImpl =
translateType(ktType, Variance.INVARIANT)
private fun translateType(ktType: KotlinType, variance: Variance): IrTypeImpl {
if (ktType.isFlexible()) {
return translateType(ktType.upperIfFlexible(), variance)
}
val ktTypeConstructor = ktType.constructor
val ktTypeDescriptor = ktTypeConstructor.declarationDescriptor
return when (ktTypeDescriptor) {
is TypeParameterDescriptor ->
IrTypeImpl(
resolveTypeParameter(ktTypeDescriptor),
ktType.isMarkedNullable,
emptyList(),
translateTypeAnnotations(ktType.annotations),
variance
)
is ClassDescriptor ->
IrTypeImpl(
symbolTable.referenceClass(ktTypeDescriptor),
ktType.isMarkedNullable,
translateTypeArguments(ktType.arguments),
translateTypeAnnotations(ktType.annotations),
variance
)
else ->
TODO()
}
}
private fun translateTypeAnnotations(annotations: Annotations): List<IrCall> =
annotations.getAllAnnotations().map {
// TODO filter out annotation targets
annotationGenerator.generateAnnotationConstructorCall(it.annotation)
}
private fun translateTypeArguments(arguments: List<TypeProjection>) =
arguments.map {
// TODO starProjection
translateType(it.type, it.projectionKind)
}
private inner class SimpleTranslationVisitor : IrElementVisitorVoid {
override fun visitElement(element: IrElement) {
element.acceptChildrenVoid(this)
}
override fun visitDeclaration(declaration: IrDeclaration) {
if (declaration is IrTypeParametersContainer) {
enterScope(declaration)
}
declaration.acceptChildrenVoid(this)
if (declaration is IrTypeParametersContainer) {
leaveScope()
}
}
override fun visitExpression(expression: IrExpression) {
translateType(expression.type)
expression.acceptChildrenVoid(this)
}
}
companion object {
fun tryTranslateAllExpressionTypes(
element: IrElement,
context: GeneratorContext
) {
element.acceptVoid(TypeTranslator(context).SimpleTranslationVisitor())
}
}
}
@@ -26,17 +26,16 @@ class IrTypeImpl(
annotations: List<IrCall>
) : this(classifier, hasQuestionMark, arguments, annotations, Variance.INVARIANT)
constructor(
other: IrType,
variance: Variance
) : this(other.classifier, other.hasQuestionMark, other.arguments, other.annotations, variance)
override val type: IrType get() = this
}
fun makeTypeProjection(type: IrType, variance: Variance): IrTypeProjection =
if (type !is IrTypeImpl || type.variance != variance)
IrTypeImpl(
type.classifier,
type.hasQuestionMark,
type.arguments,
type.annotations,
variance
)
if (type is IrTypeImpl && type.variance == variance)
type
else
type
IrTypeImpl(type, variance)