IR: IMPLICIT_DYNAMIC_CAST
Generate IMPLICIT_DYNAMIC_CAST for implicit casts from `dynamic` to `T`
This commit is contained in:
+7
-3
@@ -182,11 +182,15 @@ class CheckIrElementVisitor(
|
||||
IrTypeOperator.IMPLICIT_NOTNULL,
|
||||
IrTypeOperator.IMPLICIT_COERCION_TO_UNIT,
|
||||
IrTypeOperator.IMPLICIT_INTEGER_COERCION,
|
||||
IrTypeOperator.SAM_CONVERSION -> typeOperand
|
||||
IrTypeOperator.SAM_CONVERSION,
|
||||
IrTypeOperator.IMPLICIT_DYNAMIC_CAST ->
|
||||
typeOperand
|
||||
|
||||
IrTypeOperator.SAFE_CAST -> typeOperand.makeNullable()
|
||||
IrTypeOperator.SAFE_CAST ->
|
||||
typeOperand.makeNullable()
|
||||
|
||||
IrTypeOperator.INSTANCEOF, IrTypeOperator.NOT_INSTANCEOF -> irBuiltIns.booleanType
|
||||
IrTypeOperator.INSTANCEOF, IrTypeOperator.NOT_INSTANCEOF ->
|
||||
irBuiltIns.booleanType
|
||||
}
|
||||
|
||||
if (operator == IrTypeOperator.IMPLICIT_COERCION_TO_UNIT && !typeOperand.isUnit()) {
|
||||
|
||||
+6
@@ -69,6 +69,7 @@ class TypeOperatorLowering(val context: JsIrBackendContext) : FileLoweringPass {
|
||||
|
||||
return when (expression.operator) {
|
||||
IrTypeOperator.IMPLICIT_CAST -> lowerImplicitCast(expression)
|
||||
IrTypeOperator.IMPLICIT_DYNAMIC_CAST -> lowerImplicitDynamicCast(expression)
|
||||
IrTypeOperator.IMPLICIT_COERCION_TO_UNIT -> lowerCoercionToUnit(expression)
|
||||
IrTypeOperator.IMPLICIT_INTEGER_COERCION -> lowerIntegerCoercion(expression, data)
|
||||
IrTypeOperator.IMPLICIT_NOTNULL -> lowerImplicitNotNull(expression, data)
|
||||
@@ -122,6 +123,11 @@ class TypeOperatorLowering(val context: JsIrBackendContext) : FileLoweringPass {
|
||||
argument
|
||||
}
|
||||
|
||||
private fun lowerImplicitDynamicCast(expression: IrTypeOperatorCall) = expression.run {
|
||||
assert(operator == IrTypeOperator.IMPLICIT_DYNAMIC_CAST)
|
||||
argument
|
||||
}
|
||||
|
||||
// Note: native `instanceOf` is not used which is important because of null-behaviour
|
||||
private fun advancedCheckRequired(type: IrType) = type.isInterface() ||
|
||||
type.isArray() ||
|
||||
|
||||
+1
-1
@@ -291,7 +291,7 @@ open class InsertImplicitCasts(
|
||||
if (expectedType.isNullableAny()) {
|
||||
this
|
||||
} else {
|
||||
implicitCast(expectedType, IrTypeOperator.IMPLICIT_CAST)
|
||||
implicitCast(expectedType, IrTypeOperator.IMPLICIT_DYNAMIC_CAST)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -44,7 +44,12 @@ enum class IrTypeOperator {
|
||||
* SAM conversion: value of functional type F is used where Single Abstract Method interface value is expected.
|
||||
* Currently this is possible in Kotlin/JVM only, however, there's a big demand for SAM conversion for Kotlin interfaces.
|
||||
*/
|
||||
SAM_CONVERSION;
|
||||
SAM_CONVERSION,
|
||||
/**
|
||||
* Implicit dynamic cast: implicit cast from `dynamic` to `T`.
|
||||
* This currently can happen in Kotlin/JS only.
|
||||
*/
|
||||
IMPLICIT_DYNAMIC_CAST;
|
||||
}
|
||||
|
||||
interface IrTypeOperatorCall : IrExpression {
|
||||
|
||||
@@ -512,6 +512,7 @@ enum IrTypeOperator {
|
||||
INSTANCEOF = 7;
|
||||
NOT_INSTANCEOF = 8;
|
||||
SAM_CONVERSION = 9;
|
||||
IMPLICIT_DYNAMIC_CAST = 10;
|
||||
}
|
||||
|
||||
|
||||
|
||||
+20
-18
@@ -530,24 +530,26 @@ abstract class IrModuleDeserializer(
|
||||
}
|
||||
|
||||
private fun deserializeTypeOperator(operator: KotlinIr.IrTypeOperator) = when (operator) {
|
||||
KotlinIr.IrTypeOperator.CAST
|
||||
-> IrTypeOperator.CAST
|
||||
KotlinIr.IrTypeOperator.IMPLICIT_CAST
|
||||
-> IrTypeOperator.IMPLICIT_CAST
|
||||
KotlinIr.IrTypeOperator.IMPLICIT_NOTNULL
|
||||
-> IrTypeOperator.IMPLICIT_NOTNULL
|
||||
KotlinIr.IrTypeOperator.IMPLICIT_COERCION_TO_UNIT
|
||||
-> IrTypeOperator.IMPLICIT_COERCION_TO_UNIT
|
||||
KotlinIr.IrTypeOperator.IMPLICIT_INTEGER_COERCION
|
||||
-> IrTypeOperator.IMPLICIT_INTEGER_COERCION
|
||||
KotlinIr.IrTypeOperator.SAFE_CAST
|
||||
-> IrTypeOperator.SAFE_CAST
|
||||
KotlinIr.IrTypeOperator.INSTANCEOF
|
||||
-> IrTypeOperator.INSTANCEOF
|
||||
KotlinIr.IrTypeOperator.NOT_INSTANCEOF
|
||||
-> IrTypeOperator.NOT_INSTANCEOF
|
||||
KotlinIr.IrTypeOperator.SAM_CONVERSION
|
||||
-> IrTypeOperator.SAM_CONVERSION
|
||||
KotlinIr.IrTypeOperator.CAST ->
|
||||
IrTypeOperator.CAST
|
||||
KotlinIr.IrTypeOperator.IMPLICIT_CAST ->
|
||||
IrTypeOperator.IMPLICIT_CAST
|
||||
KotlinIr.IrTypeOperator.IMPLICIT_NOTNULL ->
|
||||
IrTypeOperator.IMPLICIT_NOTNULL
|
||||
KotlinIr.IrTypeOperator.IMPLICIT_COERCION_TO_UNIT ->
|
||||
IrTypeOperator.IMPLICIT_COERCION_TO_UNIT
|
||||
KotlinIr.IrTypeOperator.IMPLICIT_INTEGER_COERCION ->
|
||||
IrTypeOperator.IMPLICIT_INTEGER_COERCION
|
||||
KotlinIr.IrTypeOperator.SAFE_CAST ->
|
||||
IrTypeOperator.SAFE_CAST
|
||||
KotlinIr.IrTypeOperator.INSTANCEOF ->
|
||||
IrTypeOperator.INSTANCEOF
|
||||
KotlinIr.IrTypeOperator.NOT_INSTANCEOF ->
|
||||
IrTypeOperator.NOT_INSTANCEOF
|
||||
KotlinIr.IrTypeOperator.SAM_CONVERSION ->
|
||||
IrTypeOperator.SAM_CONVERSION
|
||||
KotlinIr.IrTypeOperator.IMPLICIT_DYNAMIC_CAST ->
|
||||
IrTypeOperator.IMPLICIT_DYNAMIC_CAST
|
||||
}
|
||||
|
||||
private fun deserializeTypeOp(proto: KotlinIr.IrTypeOp, start: Int, end: Int, type: IrType): IrTypeOperatorCall {
|
||||
|
||||
+20
-18
@@ -601,24 +601,26 @@ open class IrModuleSerializer(
|
||||
}
|
||||
|
||||
private fun serializeTypeOperator(operator: IrTypeOperator): KotlinIr.IrTypeOperator = when (operator) {
|
||||
IrTypeOperator.CAST
|
||||
-> KotlinIr.IrTypeOperator.CAST
|
||||
IrTypeOperator.IMPLICIT_CAST
|
||||
-> KotlinIr.IrTypeOperator.IMPLICIT_CAST
|
||||
IrTypeOperator.IMPLICIT_NOTNULL
|
||||
-> KotlinIr.IrTypeOperator.IMPLICIT_NOTNULL
|
||||
IrTypeOperator.IMPLICIT_COERCION_TO_UNIT
|
||||
-> KotlinIr.IrTypeOperator.IMPLICIT_COERCION_TO_UNIT
|
||||
IrTypeOperator.IMPLICIT_INTEGER_COERCION
|
||||
-> KotlinIr.IrTypeOperator.IMPLICIT_INTEGER_COERCION
|
||||
IrTypeOperator.SAFE_CAST
|
||||
-> KotlinIr.IrTypeOperator.SAFE_CAST
|
||||
IrTypeOperator.INSTANCEOF
|
||||
-> KotlinIr.IrTypeOperator.INSTANCEOF
|
||||
IrTypeOperator.NOT_INSTANCEOF
|
||||
-> KotlinIr.IrTypeOperator.NOT_INSTANCEOF
|
||||
IrTypeOperator.SAM_CONVERSION
|
||||
-> KotlinIr.IrTypeOperator.SAM_CONVERSION
|
||||
IrTypeOperator.CAST ->
|
||||
KotlinIr.IrTypeOperator.CAST
|
||||
IrTypeOperator.IMPLICIT_CAST ->
|
||||
KotlinIr.IrTypeOperator.IMPLICIT_CAST
|
||||
IrTypeOperator.IMPLICIT_NOTNULL ->
|
||||
KotlinIr.IrTypeOperator.IMPLICIT_NOTNULL
|
||||
IrTypeOperator.IMPLICIT_COERCION_TO_UNIT ->
|
||||
KotlinIr.IrTypeOperator.IMPLICIT_COERCION_TO_UNIT
|
||||
IrTypeOperator.IMPLICIT_INTEGER_COERCION ->
|
||||
KotlinIr.IrTypeOperator.IMPLICIT_INTEGER_COERCION
|
||||
IrTypeOperator.SAFE_CAST ->
|
||||
KotlinIr.IrTypeOperator.SAFE_CAST
|
||||
IrTypeOperator.INSTANCEOF ->
|
||||
KotlinIr.IrTypeOperator.INSTANCEOF
|
||||
IrTypeOperator.NOT_INSTANCEOF ->
|
||||
KotlinIr.IrTypeOperator.NOT_INSTANCEOF
|
||||
IrTypeOperator.SAM_CONVERSION ->
|
||||
KotlinIr.IrTypeOperator.SAM_CONVERSION
|
||||
IrTypeOperator.IMPLICIT_DYNAMIC_CAST ->
|
||||
KotlinIr.IrTypeOperator.IMPLICIT_DYNAMIC_CAST
|
||||
}
|
||||
|
||||
private fun serializeTypeOp(expression: IrTypeOperatorCall): KotlinIr.IrTypeOp {
|
||||
|
||||
+9
@@ -588,6 +588,10 @@ public final class KotlinIr {
|
||||
* <code>SAM_CONVERSION = 9;</code>
|
||||
*/
|
||||
SAM_CONVERSION(8, 9),
|
||||
/**
|
||||
* <code>IMPLICIT_DYNAMIC_CAST = 10;</code>
|
||||
*/
|
||||
IMPLICIT_DYNAMIC_CAST(9, 10),
|
||||
;
|
||||
|
||||
/**
|
||||
@@ -626,6 +630,10 @@ public final class KotlinIr {
|
||||
* <code>SAM_CONVERSION = 9;</code>
|
||||
*/
|
||||
public static final int SAM_CONVERSION_VALUE = 9;
|
||||
/**
|
||||
* <code>IMPLICIT_DYNAMIC_CAST = 10;</code>
|
||||
*/
|
||||
public static final int IMPLICIT_DYNAMIC_CAST_VALUE = 10;
|
||||
|
||||
|
||||
public final int getNumber() { return value; }
|
||||
@@ -641,6 +649,7 @@ public final class KotlinIr {
|
||||
case 7: return INSTANCEOF;
|
||||
case 8: return NOT_INSTANCEOF;
|
||||
case 9: return SAM_CONVERSION;
|
||||
case 10: return IMPLICIT_DYNAMIC_CAST;
|
||||
default: return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,20 +4,20 @@ FILE fqName:<root> fileName:/dynamicAndMembersOfAny.kt
|
||||
BLOCK_BODY
|
||||
RETURN type=kotlin.Nothing from='public final fun test1 (d: dynamic): kotlin.String declared in <root>'
|
||||
CALL 'public open fun toString (): kotlin.String declared in kotlin.Any' type=kotlin.String origin=null
|
||||
$this: TYPE_OP type=kotlin.Any origin=IMPLICIT_CAST typeOperand=kotlin.Any
|
||||
$this: TYPE_OP type=kotlin.Any origin=IMPLICIT_DYNAMIC_CAST typeOperand=kotlin.Any
|
||||
GET_VAR 'd: dynamic declared in <root>.test1' type=dynamic origin=null
|
||||
FUN name:test2 visibility:public modality:FINAL <> (d:dynamic) returnType:kotlin.Int
|
||||
VALUE_PARAMETER name:d index:0 type:dynamic
|
||||
BLOCK_BODY
|
||||
RETURN type=kotlin.Nothing from='public final fun test2 (d: dynamic): kotlin.Int declared in <root>'
|
||||
CALL 'public open fun hashCode (): kotlin.Int declared in kotlin.Any' type=kotlin.Int origin=null
|
||||
$this: TYPE_OP type=kotlin.Any origin=IMPLICIT_CAST typeOperand=kotlin.Any
|
||||
$this: TYPE_OP type=kotlin.Any origin=IMPLICIT_DYNAMIC_CAST typeOperand=kotlin.Any
|
||||
GET_VAR 'd: dynamic declared in <root>.test2' type=dynamic origin=null
|
||||
FUN name:test3 visibility:public modality:FINAL <> (d:dynamic) returnType:kotlin.Boolean
|
||||
VALUE_PARAMETER name:d index:0 type:dynamic
|
||||
BLOCK_BODY
|
||||
RETURN type=kotlin.Nothing from='public final fun test3 (d: dynamic): kotlin.Boolean declared in <root>'
|
||||
CALL 'public open fun equals (other: kotlin.Any?): kotlin.Boolean declared in kotlin.Any' type=kotlin.Boolean origin=null
|
||||
$this: TYPE_OP type=kotlin.Any origin=IMPLICIT_CAST typeOperand=kotlin.Any
|
||||
$this: TYPE_OP type=kotlin.Any origin=IMPLICIT_DYNAMIC_CAST typeOperand=kotlin.Any
|
||||
GET_VAR 'd: dynamic declared in <root>.test3' type=dynamic origin=null
|
||||
other: CONST Int type=kotlin.Int value=42
|
||||
|
||||
@@ -8,7 +8,7 @@ FILE fqName:<root> fileName:/dynamicWithSmartCast.kt
|
||||
if: TYPE_OP type=kotlin.Boolean origin=INSTANCEOF typeOperand=kotlin.String
|
||||
GET_VAR 'd: dynamic declared in <root>.test1' type=dynamic origin=null
|
||||
then: CALL 'public open fun <get-length> (): kotlin.Int declared in kotlin.String' type=kotlin.Int origin=GET_PROPERTY
|
||||
$this: TYPE_OP type=kotlin.String origin=IMPLICIT_CAST typeOperand=kotlin.String
|
||||
$this: TYPE_OP type=kotlin.String origin=IMPLICIT_DYNAMIC_CAST typeOperand=kotlin.String
|
||||
GET_VAR 'd: dynamic declared in <root>.test1' type=dynamic origin=null
|
||||
BRANCH
|
||||
if: CONST Boolean type=kotlin.Boolean value=true
|
||||
@@ -22,7 +22,7 @@ FILE fqName:<root> fileName:/dynamicWithSmartCast.kt
|
||||
if: TYPE_OP type=kotlin.Boolean origin=INSTANCEOF typeOperand=kotlin.Array<*>
|
||||
GET_VAR 'd: dynamic declared in <root>.test2' type=dynamic origin=null
|
||||
then: CALL 'public final fun <get-size> (): kotlin.Int declared in kotlin.Array' type=kotlin.Int origin=GET_PROPERTY
|
||||
$this: TYPE_OP type=kotlin.Array<out kotlin.Any?> origin=IMPLICIT_CAST typeOperand=kotlin.Array<out kotlin.Any?>
|
||||
$this: TYPE_OP type=kotlin.Array<T of kotlin.Array> origin=IMPLICIT_DYNAMIC_CAST typeOperand=kotlin.Array<T of kotlin.Array>
|
||||
GET_VAR 'd: dynamic declared in <root>.test2' type=dynamic origin=null
|
||||
BRANCH
|
||||
if: CONST Boolean type=kotlin.Boolean value=true
|
||||
|
||||
@@ -11,7 +11,7 @@ FILE fqName:<root> fileName:/implicitCastFromDynamic.kt
|
||||
PROPERTY name:p visibility:public modality:FINAL [val]
|
||||
FIELD PROPERTY_BACKING_FIELD name:p type:kotlin.Int visibility:public [final,static]
|
||||
EXPRESSION_BODY
|
||||
TYPE_OP type=kotlin.Int origin=IMPLICIT_CAST typeOperand=kotlin.Int
|
||||
TYPE_OP type=kotlin.Int origin=IMPLICIT_DYNAMIC_CAST typeOperand=kotlin.Int
|
||||
CALL 'public final fun <get-d> (): dynamic declared in <root>' type=dynamic origin=GET_PROPERTY
|
||||
FUN DEFAULT_PROPERTY_ACCESSOR name:<get-p> visibility:public modality:FINAL <> () returnType:kotlin.Int
|
||||
correspondingProperty: PROPERTY name:p visibility:public modality:FINAL [val]
|
||||
@@ -22,13 +22,13 @@ FILE fqName:<root> fileName:/implicitCastFromDynamic.kt
|
||||
VALUE_PARAMETER name:d index:0 type:dynamic
|
||||
BLOCK_BODY
|
||||
RETURN type=kotlin.Nothing from='public final fun test1 (d: dynamic): kotlin.Int declared in <root>'
|
||||
TYPE_OP type=kotlin.Int origin=IMPLICIT_CAST typeOperand=kotlin.Int
|
||||
TYPE_OP type=kotlin.Int origin=IMPLICIT_DYNAMIC_CAST typeOperand=kotlin.Int
|
||||
GET_VAR 'd: dynamic declared in <root>.test1' type=dynamic origin=null
|
||||
FUN name:test2 visibility:public modality:FINAL <> (d:dynamic) returnType:kotlin.Any
|
||||
VALUE_PARAMETER name:d index:0 type:dynamic
|
||||
BLOCK_BODY
|
||||
RETURN type=kotlin.Nothing from='public final fun test2 (d: dynamic): kotlin.Any declared in <root>'
|
||||
TYPE_OP type=kotlin.Any origin=IMPLICIT_CAST typeOperand=kotlin.Any
|
||||
TYPE_OP type=kotlin.Any origin=IMPLICIT_DYNAMIC_CAST typeOperand=kotlin.Any
|
||||
GET_VAR 'd: dynamic declared in <root>.test2' type=dynamic origin=null
|
||||
FUN name:test3 visibility:public modality:FINAL <> (d:dynamic) returnType:kotlin.Any?
|
||||
VALUE_PARAMETER name:d index:0 type:dynamic
|
||||
@@ -39,7 +39,7 @@ FILE fqName:<root> fileName:/implicitCastFromDynamic.kt
|
||||
VALUE_PARAMETER name:d index:0 type:dynamic
|
||||
BLOCK_BODY
|
||||
RETURN type=kotlin.Nothing from='public final fun test4 (d: dynamic): kotlin.String declared in <root>'
|
||||
TYPE_OP type=kotlin.String origin=IMPLICIT_CAST typeOperand=kotlin.String
|
||||
TYPE_OP type=kotlin.String origin=IMPLICIT_DYNAMIC_CAST typeOperand=kotlin.String
|
||||
DYN_OP operator=INVOKE type=dynamic
|
||||
receiver: DYN_MEMBER memberName='member' type=dynamic
|
||||
GET_VAR 'd: dynamic declared in <root>.test4' type=dynamic origin=null
|
||||
|
||||
Reference in New Issue
Block a user