blob: 34b60fdf002b4e0655e672a045d665104dd1d7d8 [file]
// TARGET_BACKEND: NATIVE
// FILECHECK_STAGE: CStubs
// FREE_COMPILER_ARGS: -Xbinary=genericSafeCasts=true
open class RTObject
class Glue : RTObject()
class StringValue : RTObject()
class Other
// CHECK-LABEL: define {{i1|zeroext i1}} @"kfun:#reproduce(RTObject;kotlin.Any){}kotlin.Boolean"
fun reproduce(obj: RTObject, o: Any): Boolean {
val glue = if (obj is Glue) obj else null
val text = if (obj is StringValue) obj else null
if (glue == null && text != null) {
// This block is reachable, so `o is Other` must be kept, not folded to a constant.
// CHECK-DEBUG: @IsSubtype{{.*}}@"kclass:Other"
// CHECK-OPT: {{call|call zeroext}} i1 @IsSubclassFast
return o is Other
}
return false
// CHECK-LABEL: epilogue:
}
// CHECK-LABEL: define {{i1|zeroext i1}} @"kfun:#reproduce2(Glue?;kotlin.Any){}kotlin.Boolean"
fun reproduce2(v: Glue?, o: Any): Boolean {
val x = if (v is Glue?) v else null
if (x == null) {
// Reachable when v == null, so `o is Other` must be kept, not folded to a constant.
// CHECK-DEBUG: @IsSubtype{{.*}}@"kclass:Other"
// CHECK-OPT: {{call|call zeroext}} i1 @IsSubclassFast
return o is Other
}
return false
// CHECK-LABEL: epilogue:
}
// CHECK-LABEL: define {{i1|zeroext i1}} @"kfun:#reproduce3(RTObject;kotlin.Any){}kotlin.Boolean"
fun reproduce3(obj: RTObject, o: Any): Boolean {
val glue = if (obj as? Glue != null) obj else null
val text = if (obj as? StringValue != null) obj else null
if (glue == null && text != null) {
// This block is reachable, so `o is Other` must be kept, not folded to a constant.
// CHECK-DEBUG: @IsSubtype{{.*}}@"kclass:Other"
// CHECK-OPT: {{call|call zeroext}} i1 @IsSubclassFast
return o is Other
}
return false
// CHECK-LABEL: epilogue:
}
// CHECK-LABEL: define {{i1|zeroext i1}} @"kfun:#reproduce4(kotlin.Any;kotlin.Any?){}kotlin.Boolean"
fun reproduce4(obj: Any, t: Any?): Boolean {
// CHECK-DEBUG: @IsSubtype{{.*}}@"kclass:Other"
if (obj is Other) {
// Reachable with t == null, when the safe call evaluates to null, so the `is Other` check on
// its result must be kept, not folded to a constant despite the safe call's result aliasing
// to `obj`. The explicit type arguments keep the frontend from narrowing the safe call's type
// (which would legitimately reduce the check to a null check).
// CHECK-DEBUG: @IsSubtype{{.*}}@"kclass:Other"
// CHECK-OPT: {{call|call zeroext}} i1 @IsSubclassFast
return (t?.let<Any, Any> { obj }) is Other
}
return false
// CHECK-LABEL: epilogue:
}
// CHECK-LABEL: define ptr @"kfun:#box(){}kotlin.String"
fun box(): String {
if (reproduce(StringValue(), Any())) return "FAIL KT-87261 (type check): o is Other folded to true"
if (reproduce2(null, Any())) return "FAIL KT-87261 (nullable type operand): o is Other folded to true"
if (reproduce3(StringValue(), Any())) return "FAIL KT-87261 (safe type check): o is Other folded to true"
if (reproduce4(Other(), null)) return "FAIL KT-87261 (safe call with unrelated result): is Other folded to true"
return "OK"
}