IrTypes: Implicit casts, take 1

Keep KotlinType along with IrTypes created by psi2ir.
This commit is contained in:
Dmitry Petrov
2018-05-15 10:21:14 +03:00
parent 54e9a2bb7b
commit e8fe788df6
5 changed files with 67 additions and 37 deletions
@@ -17,18 +17,18 @@
package org.jetbrains.kotlin.psi2ir.transformations package org.jetbrains.kotlin.psi2ir.transformations
import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.ClassifierDescriptor
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.expressions.impl.IrTypeOperatorCallImpl import org.jetbrains.kotlin.ir.expressions.impl.IrTypeOperatorCallImpl
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.util.ScopedTypeParametersResolver import org.jetbrains.kotlin.ir.types.classifierOrFail
import org.jetbrains.kotlin.ir.util.SymbolTable import org.jetbrains.kotlin.ir.types.impl.originalKotlinType
import org.jetbrains.kotlin.ir.util.TypeTranslator
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.psi2ir.containsNull import org.jetbrains.kotlin.psi2ir.containsNull
import org.jetbrains.kotlin.psi2ir.generators.GeneratorContext
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
import org.jetbrains.kotlin.types.isError import org.jetbrains.kotlin.types.isError
@@ -37,27 +37,26 @@ import org.jetbrains.kotlin.types.typeUtil.makeNotNullable
import org.jetbrains.kotlin.types.typeUtil.makeNullable import org.jetbrains.kotlin.types.typeUtil.makeNullable
import org.jetbrains.kotlin.types.upperIfFlexible import org.jetbrains.kotlin.types.upperIfFlexible
fun insertImplicitCasts(builtIns: KotlinBuiltIns, element: IrElement, symbolTable: SymbolTable) { fun insertImplicitCasts(element: IrElement, context: GeneratorContext) {
element.transformChildren(InsertImplicitCasts(builtIns, symbolTable), null) element.transformChildren(InsertImplicitCasts(context), null)
} }
class InsertImplicitCasts(private val builtIns: KotlinBuiltIns, private val symbolTable: SymbolTable) : IrElementTransformerVoid() { class InsertImplicitCasts(context: GeneratorContext) : IrElementTransformerVoid() {
private val typeParameterResolver = ScopedTypeParametersResolver() private val builtIns = context.builtIns
private val irBuiltIns = context.irBuiltIns
private val symbolTable = context.symbolTable
private val typeTranslator = TypeTranslator(context.moduleDescriptor, symbolTable)
private fun KotlinType.toIrType() = typeTranslator.translateType(this)
private inline fun <T> runInTypeParameterScope(typeParametersContainer: IrTypeParametersContainer, fn: () -> T): T { private inline fun <T> runInTypeParameterScope(typeParametersContainer: IrTypeParametersContainer, fn: () -> T): T {
typeParameterResolver.enterTypeParameterScope(typeParametersContainer) typeTranslator.enterScope(typeParametersContainer)
val result = fn() val result = fn()
typeParameterResolver.leaveTypeParameterScope() typeTranslator.leaveScope()
return result return result
} }
private fun resolveScopedTypeParameter(classifier: ClassifierDescriptor): IrTypeParameterSymbol? =
if (classifier is TypeParameterDescriptor)
typeParameterResolver.resolveScopedTypeParameter(classifier)
else
null
override fun visitCallableReference(expression: IrCallableReference): IrExpression = override fun visitCallableReference(expression: IrCallableReference): IrExpression =
expression.transformPostfix { expression.transformPostfix {
transformReceiverArguments() transformReceiverArguments()
@@ -188,13 +187,16 @@ class InsertImplicitCasts(private val builtIns: KotlinBuiltIns, private val symb
expression = expression.cast(expectedType) expression = expression.cast(expectedType)
} }
private fun IrExpression.cast(irType: IrType): IrExpression =
cast(irType.originalKotlinType)
private fun IrExpression.cast(expectedType: KotlinType?): IrExpression { private fun IrExpression.cast(expectedType: KotlinType?): IrExpression {
if (expectedType == null) return this if (expectedType == null) return this
if (expectedType.isError) return this if (expectedType.isError) return this
val notNullableExpectedType = expectedType.makeNotNullable() val notNullableExpectedType = expectedType.makeNotNullable()
val valueType = this.type val valueType = this.type.originalKotlinType!!
return when { return when {
KotlinBuiltIns.isUnit(expectedType) -> KotlinBuiltIns.isUnit(expectedType) ->
@@ -225,29 +227,28 @@ class InsertImplicitCasts(private val builtIns: KotlinBuiltIns, private val symb
targetType: KotlinType, targetType: KotlinType,
typeOperator: IrTypeOperator typeOperator: IrTypeOperator
): IrExpression { ): IrExpression {
val typeDescriptor = targetType.constructor.declarationDescriptor val irType = targetType.toIrType()
?: throw AssertionError("No declaration for target type: $targetType")
return IrTypeOperatorCallImpl( return IrTypeOperatorCallImpl(
startOffset, startOffset,
endOffset, endOffset,
targetType, irType,
typeOperator, typeOperator,
targetType, irType, irType.classifierOrFail,
resolveScopedTypeParameter(typeDescriptor) ?: symbolTable.referenceClassifier(typeDescriptor),
this this
) )
} }
private fun IrExpression.coerceToUnit(): IrExpression { private fun IrExpression.coerceToUnit(): IrExpression {
val valueType = this.type val valueType = this.type.originalKotlinType!!
return if (KotlinTypeChecker.DEFAULT.isSubtypeOf(valueType, builtIns.unitType)) return if (KotlinTypeChecker.DEFAULT.isSubtypeOf(valueType, builtIns.unitType))
this this
else else
IrTypeOperatorCallImpl( IrTypeOperatorCallImpl(
startOffset, endOffset, builtIns.unitType, startOffset, endOffset,
IrTypeOperator.IMPLICIT_COERCION_TO_UNIT, builtIns.unitType, symbolTable.referenceClass(builtIns.unit), irBuiltIns.unitType,
IrTypeOperator.IMPLICIT_COERCION_TO_UNIT,
irBuiltIns.unitType, irBuiltIns.unitType.classifierOrFail,
this this
) )
} }
@@ -8,27 +8,42 @@ package org.jetbrains.kotlin.ir.types.impl
import org.jetbrains.kotlin.ir.expressions.IrCall import org.jetbrains.kotlin.ir.expressions.IrCall
import org.jetbrains.kotlin.ir.symbols.IrClassifierSymbol import org.jetbrains.kotlin.ir.symbols.IrClassifierSymbol
import org.jetbrains.kotlin.ir.types.* import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.Variance import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
class IrSimpleTypeImpl( class IrSimpleTypeImpl(
kotlinType: KotlinType?,
override val classifier: IrClassifierSymbol, override val classifier: IrClassifierSymbol,
override val hasQuestionMark: Boolean, override val hasQuestionMark: Boolean,
override val arguments: List<IrTypeProjection>, override val arguments: List<IrTypeProjection>,
annotations: List<IrCall>, annotations: List<IrCall>,
variance: Variance variance: Variance
) : IrTypeBase(annotations, variance), IrSimpleType, IrTypeProjection { ) : IrTypeBase(kotlinType, annotations, variance), IrSimpleType, IrTypeProjection {
constructor( constructor(
classifier: IrClassifierSymbol, classifier: IrClassifierSymbol,
hasQuestionMark: Boolean, hasQuestionMark: Boolean,
arguments: List<IrTypeProjection>, arguments: List<IrTypeProjection>,
annotations: List<IrCall> annotations: List<IrCall>
) : this(classifier, hasQuestionMark, arguments, annotations, Variance.INVARIANT) ) : this(null, classifier, hasQuestionMark, arguments, annotations, Variance.INVARIANT)
constructor(
kotlinType: KotlinType?,
classifier: IrClassifierSymbol,
hasQuestionMark: Boolean,
arguments: List<IrTypeProjection>,
annotations: List<IrCall>
) : this(kotlinType, classifier, hasQuestionMark, arguments, annotations, Variance.INVARIANT)
constructor( constructor(
other: IrSimpleType, other: IrSimpleType,
variance: Variance variance: Variance
) : this(other.classifier, other.hasQuestionMark, other.arguments, other.annotations, variance) ) :
this(
other.safeAs<IrSimpleTypeImpl>()?.kotlinType,
other.classifier, other.hasQuestionMark, other.arguments, other.annotations, variance
)
} }
@@ -41,7 +56,7 @@ fun makeTypeProjection(type: IrType, variance: Variance): IrTypeProjection =
when { when {
type is IrTypeProjection && type.variance == variance -> type type is IrTypeProjection && type.variance == variance -> type
type is IrSimpleType -> IrSimpleTypeImpl(type, variance) type is IrSimpleType -> IrSimpleTypeImpl(type, variance)
type is IrDynamicType -> IrDynamicTypeImpl(type.annotations, variance) type is IrDynamicType -> IrDynamicTypeImpl(type.originalKotlinType, type.annotations, variance)
type is IrErrorType -> IrErrorTypeImpl(type.annotations, variance) type is IrErrorType -> IrErrorTypeImpl(type.originalKotlinType, type.annotations, variance)
else -> IrTypeProjectionImpl(type, variance) else -> IrTypeProjectionImpl(type, variance)
} }
@@ -10,9 +10,12 @@ import org.jetbrains.kotlin.ir.types.IrDynamicType
import org.jetbrains.kotlin.ir.types.IrErrorType import org.jetbrains.kotlin.ir.types.IrErrorType
import org.jetbrains.kotlin.ir.types.IrType import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.IrTypeProjection import org.jetbrains.kotlin.ir.types.IrTypeProjection
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.Variance import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
abstract class IrTypeBase( abstract class IrTypeBase(
val kotlinType: KotlinType?,
override val annotations: List<IrCall>, override val annotations: List<IrCall>,
override val variance: Variance override val variance: Variance
) : IrType, IrTypeProjection { ) : IrType, IrTypeProjection {
@@ -22,11 +25,17 @@ abstract class IrTypeBase(
} }
class IrErrorTypeImpl( class IrErrorTypeImpl(
kotlinType: KotlinType?,
annotations: List<IrCall>, annotations: List<IrCall>,
variance: Variance variance: Variance
) : IrTypeBase(annotations, variance), IrErrorType ) : IrTypeBase(kotlinType, annotations, variance), IrErrorType
class IrDynamicTypeImpl( class IrDynamicTypeImpl(
kotlinType: KotlinType?,
annotations: List<IrCall>, annotations: List<IrCall>,
variance: Variance variance: Variance
) : IrTypeBase(annotations, variance), IrDynamicType, IrTypeProjection ) : IrTypeBase(kotlinType, annotations, variance), IrDynamicType, IrTypeProjection
val IrType.originalKotlinType: KotlinType?
get() = safeAs<IrTypeBase>()?.kotlinType
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.ir.types
import org.jetbrains.kotlin.ir.symbols.IrClassifierSymbol import org.jetbrains.kotlin.ir.symbols.IrClassifierSymbol
import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl
import org.jetbrains.kotlin.ir.types.impl.originalKotlinType
import org.jetbrains.kotlin.types.Variance import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.utils.addToStdlib.cast import org.jetbrains.kotlin.utils.addToStdlib.cast
import org.jetbrains.kotlin.utils.addToStdlib.safeAs import org.jetbrains.kotlin.utils.addToStdlib.safeAs
@@ -17,7 +18,7 @@ fun IrType.withHasQuestionMark(hasQuestionMark: Boolean): IrType =
if (this.hasQuestionMark == hasQuestionMark) if (this.hasQuestionMark == hasQuestionMark)
this this
else else
IrSimpleTypeImpl(classifier, hasQuestionMark, arguments, annotations) IrSimpleTypeImpl(originalKotlinType, classifier, hasQuestionMark, arguments, annotations)
else -> this else -> this
} }
@@ -30,6 +31,7 @@ val IrType.classifierOrNull: IrClassifierSymbol?
fun IrType.makeNotNull() = fun IrType.makeNotNull() =
if (this is IrSimpleType && this.hasQuestionMark) if (this is IrSimpleType && this.hasQuestionMark)
IrSimpleTypeImpl( IrSimpleTypeImpl(
originalKotlinType,
classifier, classifier,
false, false,
arguments, arguments,
@@ -42,6 +44,7 @@ fun IrType.makeNotNull() =
fun IrType.makeNullable() = fun IrType.makeNullable() =
if (this is IrSimpleType && !this.hasQuestionMark) if (this is IrSimpleType && !this.hasQuestionMark)
IrSimpleTypeImpl( IrSimpleTypeImpl(
originalKotlinType,
classifier, classifier,
true, true,
arguments, arguments,
@@ -47,9 +47,9 @@ class TypeTranslator(
val ktTypeUpper = approximateCapturedTypes(ktType0).upper val ktTypeUpper = approximateCapturedTypes(ktType0).upper
when { when {
ktTypeUpper.isError -> return IrErrorTypeImpl(translateTypeAnnotations(ktTypeUpper.annotations), variance) ktTypeUpper.isError -> return IrErrorTypeImpl(ktTypeUpper, translateTypeAnnotations(ktTypeUpper.annotations), variance)
ktTypeUpper.isFlexible() -> return translateType(ktTypeUpper.upperIfFlexible(), variance) ktTypeUpper.isFlexible() -> return translateType(ktTypeUpper.upperIfFlexible(), variance)
ktTypeUpper.isDynamic() -> return IrDynamicTypeImpl(translateTypeAnnotations(ktTypeUpper.annotations), variance) ktTypeUpper.isDynamic() -> return IrDynamicTypeImpl(ktTypeUpper, translateTypeAnnotations(ktTypeUpper.annotations), variance)
} }
val ktTypeConstructor = ktTypeUpper.constructor val ktTypeConstructor = ktTypeUpper.constructor
@@ -58,6 +58,7 @@ class TypeTranslator(
return when (ktTypeDescriptor) { return when (ktTypeDescriptor) {
is TypeParameterDescriptor -> is TypeParameterDescriptor ->
IrSimpleTypeImpl( IrSimpleTypeImpl(
ktTypeUpper,
resolveTypeParameter(ktTypeDescriptor), resolveTypeParameter(ktTypeDescriptor),
ktTypeUpper.isMarkedNullable, ktTypeUpper.isMarkedNullable,
emptyList(), emptyList(),
@@ -67,6 +68,7 @@ class TypeTranslator(
is ClassDescriptor -> is ClassDescriptor ->
IrSimpleTypeImpl( IrSimpleTypeImpl(
ktTypeUpper,
symbolTable.referenceClass(ktTypeDescriptor), symbolTable.referenceClass(ktTypeDescriptor),
ktTypeUpper.isMarkedNullable, ktTypeUpper.isMarkedNullable,
translateTypeArguments(ktTypeUpper.arguments), translateTypeArguments(ktTypeUpper.arguments),