Handle nullable case in '==' with smart cast using safe call
This commit is contained in:
+11
@@ -30,7 +30,9 @@ import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.endOffset
|
||||
import org.jetbrains.kotlin.psi.psiUtil.startOffset
|
||||
import org.jetbrains.kotlin.psi2ir.containsNull
|
||||
import org.jetbrains.kotlin.psi2ir.findSingleFunction
|
||||
import org.jetbrains.kotlin.psi2ir.intermediate.safeCallOnDispatchReceiver
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.checkers.PrimitiveNumericComparisonInfo
|
||||
@@ -277,6 +279,15 @@ class OperatorExpressionGenerator(statementGenerator: StatementGenerator) : Stat
|
||||
operandType == targetType || operandNNType == targetType ->
|
||||
this
|
||||
|
||||
type.containsNull() ->
|
||||
safeCallOnDispatchReceiver(this@OperatorExpressionGenerator, startOffset, endOffset) { dispatchReceiver ->
|
||||
invokeConversionFunction(
|
||||
startOffset, endOffset,
|
||||
conversionFunction ?: throw AssertionError("No conversion function for $type ~> $targetType"),
|
||||
dispatchReceiver
|
||||
)
|
||||
}
|
||||
|
||||
else ->
|
||||
invokeConversionFunction(
|
||||
startOffset, endOffset,
|
||||
|
||||
+17
-1
@@ -67,4 +67,20 @@ class SafeCallReceiver(
|
||||
|
||||
return irBlock
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun IrExpression.safeCallOnDispatchReceiver(
|
||||
generator: GeneratorWithScope,
|
||||
startOffset: Int,
|
||||
endOffset: Int,
|
||||
ifNotNull: (IrExpression) -> IrExpression
|
||||
) =
|
||||
SafeCallReceiver(
|
||||
generator, startOffset, endOffset,
|
||||
extensionReceiver = null,
|
||||
dispatchReceiver = OnceExpressionValue(this),
|
||||
isAssignmentReceiver = false
|
||||
).call { dispatchReceiverValue, _ ->
|
||||
ifNotNull(dispatchReceiverValue!!.load())
|
||||
}
|
||||
Vendored
+13
-2
@@ -9,9 +9,20 @@ FILE fqName:<root> fileName:/nullableAnyAsIntToDouble.kt
|
||||
if: TYPE_OP type=kotlin.Boolean origin=INSTANCEOF typeOperand=kotlin.Int
|
||||
GET_VAR 'value-parameter x: Any?' type=kotlin.Any? origin=null
|
||||
then: CALL 'less(Double, Double): Boolean' type=kotlin.Boolean origin=LT
|
||||
arg0: CALL 'toDouble(): Double' type=kotlin.Double origin=null
|
||||
$this: TYPE_OP type=kotlin.Int origin=IMPLICIT_CAST typeOperand=kotlin.Int
|
||||
arg0: BLOCK type=kotlin.Double? origin=SAFE_CALL
|
||||
VAR IR_TEMPORARY_VARIABLE name:tmp0_safe_receiver type:kotlin.Any? flags:val
|
||||
GET_VAR 'value-parameter x: Any?' type=kotlin.Any? origin=null
|
||||
WHEN type=kotlin.Double? origin=SAFE_CALL
|
||||
BRANCH
|
||||
if: CALL 'EQEQ(Any?, Any?): Boolean' type=kotlin.Boolean origin=EQEQ
|
||||
arg0: GET_VAR 'tmp0_safe_receiver: Any?' type=kotlin.Any? origin=null
|
||||
arg1: CONST Null type=kotlin.Nothing? value=null
|
||||
then: CONST Null type=kotlin.Nothing? value=null
|
||||
BRANCH
|
||||
if: CONST Boolean type=kotlin.Boolean value=true
|
||||
then: CALL 'toDouble(): Double' type=kotlin.Double origin=null
|
||||
$this: TYPE_OP type=kotlin.Int origin=IMPLICIT_CAST typeOperand=kotlin.Int
|
||||
GET_VAR 'tmp0_safe_receiver: Any?' type=kotlin.Any? origin=null
|
||||
arg1: GET_VAR 'value-parameter y: Double' type=kotlin.Double origin=null
|
||||
BRANCH
|
||||
if: CONST Boolean type=kotlin.Boolean value=true
|
||||
|
||||
Vendored
+2
-1
@@ -1,3 +1,4 @@
|
||||
fun testDD(x: Double?, y: Double?) = x == y
|
||||
fun testDF(x: Double?, y: Any?) = y is Float? && x == y
|
||||
fun testDI(x: Double?, y: Any?) = y is Int? && x == y
|
||||
fun testDI(x: Double?, y: Any?) = y is Int? && x == y
|
||||
fun testDI2(x: Any?, y: Any?) = x is Int? && y is Double && x == y
|
||||
Vendored
+62
-4
@@ -18,9 +18,20 @@ FILE fqName:<root> fileName:/nullableFloatingPointEqeq.kt
|
||||
GET_VAR 'value-parameter y: Any?' type=kotlin.Any? origin=null
|
||||
then: CALL 'ieee754equals(Double?, Double?): Boolean' type=kotlin.Boolean origin=EQEQ
|
||||
arg0: GET_VAR 'value-parameter x: Double?' type=kotlin.Double? origin=null
|
||||
arg1: CALL 'toDouble(): Double' type=kotlin.Double origin=null
|
||||
$this: TYPE_OP type=kotlin.Float origin=IMPLICIT_CAST typeOperand=kotlin.Float
|
||||
arg1: BLOCK type=kotlin.Double? origin=SAFE_CALL
|
||||
VAR IR_TEMPORARY_VARIABLE name:tmp0_safe_receiver type:kotlin.Any? flags:val
|
||||
GET_VAR 'value-parameter y: Any?' type=kotlin.Any? origin=null
|
||||
WHEN type=kotlin.Double? origin=SAFE_CALL
|
||||
BRANCH
|
||||
if: CALL 'EQEQ(Any?, Any?): Boolean' type=kotlin.Boolean origin=EQEQ
|
||||
arg0: GET_VAR 'tmp0_safe_receiver: Any?' type=kotlin.Any? origin=null
|
||||
arg1: CONST Null type=kotlin.Nothing? value=null
|
||||
then: CONST Null type=kotlin.Nothing? value=null
|
||||
BRANCH
|
||||
if: CONST Boolean type=kotlin.Boolean value=true
|
||||
then: CALL 'toDouble(): Double' type=kotlin.Double origin=null
|
||||
$this: TYPE_OP type=kotlin.Float origin=IMPLICIT_CAST typeOperand=kotlin.Float
|
||||
GET_VAR 'tmp0_safe_receiver: Any?' type=kotlin.Any? origin=null
|
||||
BRANCH
|
||||
if: CONST Boolean type=kotlin.Boolean value=true
|
||||
then: CONST Boolean type=kotlin.Boolean value=false
|
||||
@@ -35,9 +46,56 @@ FILE fqName:<root> fileName:/nullableFloatingPointEqeq.kt
|
||||
GET_VAR 'value-parameter y: Any?' type=kotlin.Any? origin=null
|
||||
then: CALL 'ieee754equals(Double?, Double?): Boolean' type=kotlin.Boolean origin=EQEQ
|
||||
arg0: GET_VAR 'value-parameter x: Double?' type=kotlin.Double? origin=null
|
||||
arg1: CALL 'toDouble(): Double' type=kotlin.Double origin=null
|
||||
$this: TYPE_OP type=kotlin.Int origin=IMPLICIT_CAST typeOperand=kotlin.Int
|
||||
arg1: BLOCK type=kotlin.Double? origin=SAFE_CALL
|
||||
VAR IR_TEMPORARY_VARIABLE name:tmp0_safe_receiver type:kotlin.Any? flags:val
|
||||
GET_VAR 'value-parameter y: Any?' type=kotlin.Any? origin=null
|
||||
WHEN type=kotlin.Double? origin=SAFE_CALL
|
||||
BRANCH
|
||||
if: CALL 'EQEQ(Any?, Any?): Boolean' type=kotlin.Boolean origin=EQEQ
|
||||
arg0: GET_VAR 'tmp0_safe_receiver: Any?' type=kotlin.Any? origin=null
|
||||
arg1: CONST Null type=kotlin.Nothing? value=null
|
||||
then: CONST Null type=kotlin.Nothing? value=null
|
||||
BRANCH
|
||||
if: CONST Boolean type=kotlin.Boolean value=true
|
||||
then: CALL 'toDouble(): Double' type=kotlin.Double origin=null
|
||||
$this: TYPE_OP type=kotlin.Int origin=IMPLICIT_CAST typeOperand=kotlin.Int
|
||||
GET_VAR 'tmp0_safe_receiver: Any?' type=kotlin.Any? origin=null
|
||||
BRANCH
|
||||
if: CONST Boolean type=kotlin.Boolean value=true
|
||||
then: CONST Boolean type=kotlin.Boolean value=false
|
||||
FUN name:testDI2 visibility:public modality:FINAL <> (x:kotlin.Any?, y:kotlin.Any?) returnType:Boolean flags:
|
||||
VALUE_PARAMETER name:x index:0 type:kotlin.Any? flags:
|
||||
VALUE_PARAMETER name:y index:1 type:kotlin.Any? flags:
|
||||
BLOCK_BODY
|
||||
RETURN type=kotlin.Nothing from='testDI2(Any?, Any?): Boolean'
|
||||
WHEN type=kotlin.Boolean origin=ANDAND
|
||||
BRANCH
|
||||
if: WHEN type=kotlin.Boolean origin=ANDAND
|
||||
BRANCH
|
||||
if: TYPE_OP type=kotlin.Boolean origin=INSTANCEOF typeOperand=kotlin.Int?
|
||||
GET_VAR 'value-parameter x: Any?' type=kotlin.Any? origin=null
|
||||
then: TYPE_OP type=kotlin.Boolean origin=INSTANCEOF typeOperand=kotlin.Double
|
||||
GET_VAR 'value-parameter y: Any?' type=kotlin.Any? origin=null
|
||||
BRANCH
|
||||
if: CONST Boolean type=kotlin.Boolean value=true
|
||||
then: CONST Boolean type=kotlin.Boolean value=false
|
||||
then: CALL 'ieee754equals(Double?, Double?): Boolean' type=kotlin.Boolean origin=EQEQ
|
||||
arg0: BLOCK type=kotlin.Double? origin=SAFE_CALL
|
||||
VAR IR_TEMPORARY_VARIABLE name:tmp0_safe_receiver type:kotlin.Any? flags:val
|
||||
GET_VAR 'value-parameter x: Any?' type=kotlin.Any? origin=null
|
||||
WHEN type=kotlin.Double? origin=SAFE_CALL
|
||||
BRANCH
|
||||
if: CALL 'EQEQ(Any?, Any?): Boolean' type=kotlin.Boolean origin=EQEQ
|
||||
arg0: GET_VAR 'tmp0_safe_receiver: Any?' type=kotlin.Any? origin=null
|
||||
arg1: CONST Null type=kotlin.Nothing? value=null
|
||||
then: CONST Null type=kotlin.Nothing? value=null
|
||||
BRANCH
|
||||
if: CONST Boolean type=kotlin.Boolean value=true
|
||||
then: CALL 'toDouble(): Double' type=kotlin.Double origin=null
|
||||
$this: TYPE_OP type=kotlin.Int origin=IMPLICIT_CAST typeOperand=kotlin.Int
|
||||
GET_VAR 'tmp0_safe_receiver: Any?' type=kotlin.Any? origin=null
|
||||
arg1: TYPE_OP type=kotlin.Double? origin=IMPLICIT_CAST typeOperand=kotlin.Double?
|
||||
GET_VAR 'value-parameter y: Any?' type=kotlin.Any? origin=null
|
||||
BRANCH
|
||||
if: CONST Boolean type=kotlin.Boolean value=true
|
||||
then: CONST Boolean type=kotlin.Boolean value=false
|
||||
|
||||
Reference in New Issue
Block a user