FIR: report UNSAFE_CALL on dot when possible
This commit is contained in:
@@ -3,7 +3,7 @@ fun foo(): String {
|
||||
var s: String?
|
||||
s = null
|
||||
s?.length
|
||||
s.<!UNSAFE_CALL!>length<!>
|
||||
s<!UNSAFE_CALL!>.<!>length
|
||||
if (s == null) return s!!
|
||||
var t: String? = "y"
|
||||
if (t == null) t = "x"
|
||||
|
||||
@@ -13,7 +13,7 @@ fun g(a: SomeClass?) {
|
||||
// 'a' can be cast to SomeSubClass
|
||||
a.hashCode()
|
||||
a.foo
|
||||
(a as? SomeSubClass).<!UNSAFE_CALL!>foo<!>
|
||||
(a as? SomeSubClass)<!UNSAFE_CALL!>.<!>foo
|
||||
(a as SomeSubClass).foo
|
||||
}
|
||||
val b = (a as? SomeSubClass)?.foo
|
||||
@@ -21,7 +21,7 @@ fun g(a: SomeClass?) {
|
||||
// 'a' can be cast to SomeSubClass
|
||||
a.hashCode()
|
||||
a.foo
|
||||
(a as? SomeSubClass).<!UNSAFE_CALL!>foo<!>
|
||||
(a as? SomeSubClass)<!UNSAFE_CALL!>.<!>foo
|
||||
(a as SomeSubClass).foo
|
||||
}
|
||||
val c = a as? SomeSubClass
|
||||
@@ -29,7 +29,7 @@ fun g(a: SomeClass?) {
|
||||
// 'a' and 'c' can be cast to SomeSubClass
|
||||
a.hashCode()
|
||||
a.foo
|
||||
(a as? SomeSubClass).<!UNSAFE_CALL!>foo<!>
|
||||
(a as? SomeSubClass)<!UNSAFE_CALL!>.<!>foo
|
||||
c.hashCode()
|
||||
c.foo
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ fun g(a: SomeClass?) {
|
||||
// 'a' can be cast to SomeSubClass
|
||||
a.hashCode()
|
||||
a.foo
|
||||
(a as? SomeSubClass).<!UNSAFE_CALL!>foo<!>
|
||||
(a as? SomeSubClass)<!UNSAFE_CALL!>.<!>foo
|
||||
(a as SomeSubClass).foo
|
||||
}
|
||||
val b = (a as? SomeSubClass)?.foo
|
||||
@@ -21,7 +21,7 @@ fun g(a: SomeClass?) {
|
||||
// 'a' can be cast to SomeSubClass
|
||||
a.hashCode()
|
||||
a.foo
|
||||
(a as? SomeSubClass).<!UNSAFE_CALL!>foo<!>
|
||||
(a as? SomeSubClass)<!UNSAFE_CALL!>.<!>foo
|
||||
(a as SomeSubClass).foo
|
||||
}
|
||||
val c = a as? SomeSubClass
|
||||
@@ -29,7 +29,7 @@ fun g(a: SomeClass?) {
|
||||
// 'a' and 'c' can be cast to SomeSubClass
|
||||
a.hashCode()
|
||||
a.foo
|
||||
(a as? SomeSubClass).<!UNSAFE_CALL!>foo<!>
|
||||
(a as? SomeSubClass)<!UNSAFE_CALL!>.<!>foo
|
||||
c.hashCode()
|
||||
c.foo
|
||||
}
|
||||
|
||||
@@ -18,18 +18,18 @@ fun g(a: SomeClass?) {
|
||||
b = "Hello"
|
||||
if (b != null) {
|
||||
// 'a' cannot be cast to SomeSubClass!
|
||||
a.<!UNSAFE_CALL!>hashCode<!>()
|
||||
a<!UNSAFE_CALL!>.<!>hashCode()
|
||||
a.<!UNRESOLVED_REFERENCE!>foo<!>
|
||||
(a as? SomeSubClass).<!UNSAFE_CALL!>foo<!>
|
||||
(a as? SomeSubClass)<!UNSAFE_CALL!>.<!>foo
|
||||
(a as SomeSubClass).foo
|
||||
}
|
||||
var c = a as? SomeSubClass
|
||||
c = Impl
|
||||
if (c != null) {
|
||||
// 'a' cannot be cast to SomeSubClass
|
||||
a.<!UNSAFE_CALL!>hashCode<!>()
|
||||
a<!UNSAFE_CALL!>.<!>hashCode()
|
||||
a.<!UNRESOLVED_REFERENCE!>foo<!>
|
||||
(a as? SomeSubClass).<!UNSAFE_CALL!>foo<!>
|
||||
(a as? SomeSubClass)<!UNSAFE_CALL!>.<!>foo
|
||||
c.hashCode()
|
||||
c.foo
|
||||
}
|
||||
@@ -41,18 +41,18 @@ fun f(a: SomeClass?) {
|
||||
if (aa as? SomeSubClass != null) {
|
||||
aa = null
|
||||
// 'aa' cannot be cast to SomeSubClass
|
||||
aa.<!UNSAFE_CALL!>hashCode<!>()
|
||||
aa<!UNSAFE_CALL!>.<!>hashCode()
|
||||
aa.<!UNRESOLVED_REFERENCE!>foo<!>
|
||||
(aa as? SomeSubClass).<!UNSAFE_CALL!>foo<!>
|
||||
(aa as? SomeSubClass)<!UNSAFE_CALL!>.<!>foo
|
||||
(aa as SomeSubClass).foo
|
||||
}
|
||||
val b = (aa as? SomeSubClass)?.foo
|
||||
aa = null
|
||||
if (b != null) {
|
||||
// 'aa' cannot be cast to SomeSubClass
|
||||
aa.<!UNSAFE_CALL!>hashCode<!>()
|
||||
aa<!UNSAFE_CALL!>.<!>hashCode()
|
||||
aa.<!UNRESOLVED_REFERENCE!>foo<!>
|
||||
(aa as? SomeSubClass).<!UNSAFE_CALL!>foo<!>
|
||||
(aa as? SomeSubClass)<!UNSAFE_CALL!>.<!>foo
|
||||
(aa as SomeSubClass).foo
|
||||
}
|
||||
aa = a
|
||||
@@ -61,7 +61,7 @@ fun f(a: SomeClass?) {
|
||||
// 'c' can be cast to SomeSubClass
|
||||
aa.hashCode()
|
||||
aa.foo
|
||||
(aa as? SomeSubClass).<!UNSAFE_CALL!>foo<!>
|
||||
(aa as? SomeSubClass)<!UNSAFE_CALL!>.<!>foo
|
||||
c.hashCode()
|
||||
c.foo
|
||||
}
|
||||
|
||||
@@ -6,30 +6,30 @@ fun foo(x : String?, y : String?) {
|
||||
y.length
|
||||
}
|
||||
else {
|
||||
x.<!UNSAFE_CALL!>length<!>
|
||||
y.<!UNSAFE_CALL!>length<!>
|
||||
x<!UNSAFE_CALL!>.<!>length
|
||||
y<!UNSAFE_CALL!>.<!>length
|
||||
}
|
||||
if (y != null || x == y) {
|
||||
x.<!UNSAFE_CALL!>length<!>
|
||||
y.<!UNSAFE_CALL!>length<!>
|
||||
x<!UNSAFE_CALL!>.<!>length
|
||||
y<!UNSAFE_CALL!>.<!>length
|
||||
}
|
||||
else {
|
||||
// y == null but x != y
|
||||
x.<!UNSAFE_CALL!>length<!>
|
||||
y.<!UNSAFE_CALL!>length<!>
|
||||
x<!UNSAFE_CALL!>.<!>length
|
||||
y<!UNSAFE_CALL!>.<!>length
|
||||
}
|
||||
if (y == null && x != y) {
|
||||
// y == null but x != y
|
||||
x.<!UNSAFE_CALL!>length<!>
|
||||
y.<!UNSAFE_CALL!>length<!>
|
||||
x<!UNSAFE_CALL!>.<!>length
|
||||
y<!UNSAFE_CALL!>.<!>length
|
||||
}
|
||||
else {
|
||||
x.<!UNSAFE_CALL!>length<!>
|
||||
y.<!UNSAFE_CALL!>length<!>
|
||||
x<!UNSAFE_CALL!>.<!>length
|
||||
y<!UNSAFE_CALL!>.<!>length
|
||||
}
|
||||
if (y == null || x != y) {
|
||||
x.<!UNSAFE_CALL!>length<!>
|
||||
y.<!UNSAFE_CALL!>length<!>
|
||||
x<!UNSAFE_CALL!>.<!>length
|
||||
y<!UNSAFE_CALL!>.<!>length
|
||||
}
|
||||
else {
|
||||
// Both not null
|
||||
|
||||
@@ -3,21 +3,21 @@ fun foo(x: String?, y: String?, z: String?, w: String?) {
|
||||
if (x != null && y != null && (x == z || y == z))
|
||||
z.length
|
||||
else
|
||||
z.<!UNSAFE_CALL!>length<!>
|
||||
z<!UNSAFE_CALL!>.<!>length
|
||||
if (x != null || y != null || (x != z && y != z))
|
||||
z.<!UNSAFE_CALL!>length<!>
|
||||
z<!UNSAFE_CALL!>.<!>length
|
||||
else
|
||||
z.<!UNSAFE_CALL!>length<!>
|
||||
z<!UNSAFE_CALL!>.<!>length
|
||||
if (x == null || y == null || (x != z && y != z))
|
||||
z.<!UNSAFE_CALL!>length<!>
|
||||
z<!UNSAFE_CALL!>.<!>length
|
||||
else
|
||||
z.length
|
||||
if (x != null && y == x && z == y && w == z)
|
||||
w.length
|
||||
else
|
||||
w.<!UNSAFE_CALL!>length<!>
|
||||
w<!UNSAFE_CALL!>.<!>length
|
||||
if ((x != null && y == x) || (z != null && y == z))
|
||||
y.length
|
||||
else
|
||||
y.<!UNSAFE_CALL!>length<!>
|
||||
y<!UNSAFE_CALL!>.<!>length
|
||||
}
|
||||
|
||||
+10
-10
@@ -1,26 +1,26 @@
|
||||
fun foo(x: String?, y: String?, z: String?) {
|
||||
if ((x!!.hashCode() == 0 || y!!.hashCode() == 1) && z!!.hashCode() == 2) {
|
||||
x.length
|
||||
y.<!UNSAFE_CALL!>length<!>
|
||||
y<!UNSAFE_CALL!>.<!>length
|
||||
// condition is true => z!! after and is called
|
||||
z.length
|
||||
}
|
||||
else {
|
||||
x.length
|
||||
y.<!UNSAFE_CALL!>length<!>
|
||||
z.<!UNSAFE_CALL!>length<!>
|
||||
y<!UNSAFE_CALL!>.<!>length
|
||||
z<!UNSAFE_CALL!>.<!>length
|
||||
}
|
||||
// First element is always analyzed
|
||||
x.length
|
||||
var xx = y ?: z
|
||||
if ((xx!!.hashCode() == 0 && y!!.hashCode() == 1) || z!!.hashCode() == 2) {
|
||||
xx.length
|
||||
y.<!UNSAFE_CALL!>length<!>
|
||||
z.<!UNSAFE_CALL!>length<!>
|
||||
y<!UNSAFE_CALL!>.<!>length
|
||||
z<!UNSAFE_CALL!>.<!>length
|
||||
}
|
||||
else {
|
||||
xx.length
|
||||
y.<!UNSAFE_CALL!>length<!>
|
||||
y<!UNSAFE_CALL!>.<!>length
|
||||
// condition is false => z!! after or is called
|
||||
z.length
|
||||
}
|
||||
@@ -35,16 +35,16 @@ fun foo(x: String?, y: String?, z: String?) {
|
||||
}
|
||||
else {
|
||||
xx.length
|
||||
y.<!UNSAFE_CALL!>length<!>
|
||||
z.<!UNSAFE_CALL!>length<!>
|
||||
y<!UNSAFE_CALL!>.<!>length
|
||||
z<!UNSAFE_CALL!>.<!>length
|
||||
}
|
||||
// First element is always analyzed
|
||||
x.length
|
||||
xx = y ?: z
|
||||
if (xx!!.hashCode() == 0 || y!!.hashCode() == 1 || z!!.hashCode() == 2) {
|
||||
xx.length
|
||||
y.<!UNSAFE_CALL!>length<!>
|
||||
z.<!UNSAFE_CALL!>length<!>
|
||||
y<!UNSAFE_CALL!>.<!>length
|
||||
z<!UNSAFE_CALL!>.<!>length
|
||||
}
|
||||
else {
|
||||
// all three are called
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
// !LANGUAGE: -BooleanElvisBoundSmartCasts
|
||||
|
||||
interface Order {
|
||||
val expired: Boolean?
|
||||
|
||||
fun notExpired(): Boolean
|
||||
|
||||
fun doSomething()
|
||||
}
|
||||
|
||||
fun foo(o: Any) {
|
||||
val order = o as? Order
|
||||
if (order?.expired ?: false) {
|
||||
order.<!UNSAFE_CALL!>doSomething<!>()
|
||||
}
|
||||
else {
|
||||
|
||||
}
|
||||
if (order?.notExpired() ?: false) {
|
||||
order.<!UNSAFE_CALL!>doSomething<!>()
|
||||
}
|
||||
}
|
||||
|
||||
fun bar(o: Any) {
|
||||
val order = o as? Order
|
||||
if (order?.expired ?: true) {
|
||||
|
||||
}
|
||||
else {
|
||||
order!!.doSomething()
|
||||
}
|
||||
if (order?.notExpired() ?: true) {
|
||||
|
||||
}
|
||||
else {
|
||||
order!!.doSomething()
|
||||
}
|
||||
}
|
||||
|
||||
fun baz(o: Boolean?) {
|
||||
if (o ?: false) {
|
||||
o.<!UNSAFE_CALL!>hashCode<!>()
|
||||
}
|
||||
if (o ?: true) {
|
||||
|
||||
}
|
||||
else {
|
||||
o.<!UNSAFE_CALL!>hashCode<!>()
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
// !LANGUAGE: -BooleanElvisBoundSmartCasts
|
||||
|
||||
interface Order {
|
||||
|
||||
@@ -11,13 +11,13 @@ interface Order {
|
||||
fun foo(o: Any) {
|
||||
val order = o as? Order
|
||||
if (order?.expired ?: false) {
|
||||
order.<!UNSAFE_CALL!>doSomething<!>()
|
||||
order<!UNSAFE_CALL!>.<!>doSomething()
|
||||
}
|
||||
else {
|
||||
|
||||
}
|
||||
if (order?.notExpired() ?: false) {
|
||||
order.<!UNSAFE_CALL!>doSomething<!>()
|
||||
order<!UNSAFE_CALL!>.<!>doSomething()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,12 +39,12 @@ fun bar(o: Any) {
|
||||
|
||||
fun baz(o: Boolean?) {
|
||||
if (o ?: false) {
|
||||
o.<!UNSAFE_CALL!>hashCode<!>()
|
||||
o<!UNSAFE_CALL!>.<!>hashCode()
|
||||
}
|
||||
if (o ?: true) {
|
||||
|
||||
}
|
||||
else {
|
||||
o.<!UNSAFE_CALL!>hashCode<!>()
|
||||
o<!UNSAFE_CALL!>.<!>hashCode()
|
||||
}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
// Based on KT-9100
|
||||
fun test(x: Any?, y: Any?): Any {
|
||||
val z = x ?: y!!
|
||||
y.<!UNSAFE_CALL!>hashCode<!>()
|
||||
// !! / ?. is necessary here, because y!! above may not be executed
|
||||
y?.hashCode()
|
||||
y!!.hashCode()
|
||||
return z
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
// Based on KT-9100
|
||||
fun test(x: Any?, y: Any?): Any {
|
||||
val z = x ?: y!!
|
||||
|
||||
@@ -4,7 +4,7 @@ class C {
|
||||
|
||||
fun test(a: C?, nn: () -> Nothing?) {
|
||||
a ?: nn()
|
||||
a.<!UNSAFE_CALL!>foo<!>()
|
||||
a<!UNSAFE_CALL!>.<!>foo()
|
||||
|
||||
a ?: return
|
||||
a.foo()
|
||||
|
||||
+1
-1
@@ -12,7 +12,7 @@ fun printMessages() {
|
||||
Message.HELLO.text!!
|
||||
Message.HELLO.text.length
|
||||
|
||||
Message.NOTHING.text.<!UNSAFE_CALL!>length<!>
|
||||
Message.NOTHING.text<!UNSAFE_CALL!>.<!>length
|
||||
|
||||
Message.NOTHING.text!!
|
||||
Message.NOTHING.text.length
|
||||
|
||||
+1
-1
@@ -12,7 +12,7 @@ fun printMessages() {
|
||||
Message.HELLO.text!!
|
||||
Message.HELLO.text.length
|
||||
|
||||
Message.NOTHING.text.<!UNSAFE_CALL!>length<!>
|
||||
Message.NOTHING.text<!UNSAFE_CALL!>.<!>length
|
||||
|
||||
Message.NOTHING.text!!
|
||||
Message.NOTHING.text.length
|
||||
|
||||
@@ -2,12 +2,12 @@ class D(val a: String, val b: Boolean)
|
||||
|
||||
fun foo(p: Boolean, v: D?): String {
|
||||
if (p && v!!.b) v.a
|
||||
else v.<!UNSAFE_CALL!>a<!>
|
||||
else v<!UNSAFE_CALL!>.<!>a
|
||||
if (p && v!! == D("?", false)) v.a
|
||||
else v.<!UNSAFE_CALL!>a<!>
|
||||
if (p || v!!.b) v.<!UNSAFE_CALL!>a<!>
|
||||
else v<!UNSAFE_CALL!>.<!>a
|
||||
if (p || v!!.b) v<!UNSAFE_CALL!>.<!>a
|
||||
else v.a
|
||||
if (p || v!! == D("?", false)) v.<!UNSAFE_CALL!>a<!>
|
||||
if (p || v!! == D("?", false)) v<!UNSAFE_CALL!>.<!>a
|
||||
else v.a
|
||||
return ""
|
||||
}
|
||||
|
||||
@@ -9,5 +9,5 @@ fun <T> T?.let(f: (T) -> Unit) {
|
||||
fun test(your: Your?) {
|
||||
(your?.foo() as? Any)?.let {}
|
||||
// strange smart cast to 'Your' at this point
|
||||
your.<!UNSAFE_CALL!>hashCode<!>()
|
||||
your<!UNSAFE_CALL!>.<!>hashCode()
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
// !DIAGNOSTICS: -UNNECESSARY_NOT_NULL_ASSERTION
|
||||
// See KT-9126: Variable change does not affect data flow info for its fields
|
||||
|
||||
class My(val x: Int?)
|
||||
|
||||
fun foo() {
|
||||
var y: My? = My(42)
|
||||
if (y!!.x != null) {
|
||||
y = My(null)
|
||||
y!!.x.<!UNSAFE_CALL!>hashCode<!>()
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
// !DIAGNOSTICS: -UNNECESSARY_NOT_NULL_ASSERTION
|
||||
// See KT-9126: Variable change does not affect data flow info for its fields
|
||||
|
||||
|
||||
@@ -9,6 +9,6 @@ fun foo() {
|
||||
var y: My? = My(42)
|
||||
if (y!!.x != null) {
|
||||
y = My(null)
|
||||
(y + My(0)).x.<!UNSAFE_CALL!>hashCode<!>()
|
||||
(y + My(0)).x<!UNSAFE_CALL!>.<!>hashCode()
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,7 @@ class A<E> {
|
||||
class B(var a: A<*>?) {
|
||||
fun bar() {
|
||||
if (a != null) {
|
||||
a.<!UNSAFE_CALL!>foo<!>()
|
||||
a<!UNSAFE_CALL!>.<!>foo()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ inline fun <R> callItContracted(fn: () -> R): R {
|
||||
|
||||
fun smartIt(p1: String?, p2: String?) {
|
||||
p1 ?: callIt { return }
|
||||
p1.<!UNSAFE_CALL!>length<!>
|
||||
p1<!UNSAFE_CALL!>.<!>length
|
||||
|
||||
p2 ?: callItContracted { return }
|
||||
p2.length
|
||||
|
||||
@@ -6,5 +6,5 @@ fun <R> callIt(fn: () -> R): R = TODO()
|
||||
|
||||
fun smartIt(p1: String?, p2: String?) {
|
||||
p1 ?: callIt { TODO() }
|
||||
p1.<!UNSAFE_CALL!>length<!> // smartcast
|
||||
p1<!UNSAFE_CALL!>.<!>length // smartcast
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ fun kt6840_2(s: String?) {
|
||||
|
||||
fun kt1635(s: String?) {
|
||||
s?.hashCode()!!
|
||||
s.<!UNSAFE_CALL!>hashCode<!>()
|
||||
s<!UNSAFE_CALL!>.<!>hashCode()
|
||||
}
|
||||
|
||||
fun kt2127() {
|
||||
|
||||
Vendored
+1
-1
@@ -9,5 +9,5 @@ fun checkJump(x: Int?, y: Int?) {
|
||||
y.hashCode()
|
||||
}
|
||||
// Smart cast here is erroneous: y is nullable
|
||||
y.<!UNSAFE_CALL!>hashCode<!>()
|
||||
y<!UNSAFE_CALL!>.<!>hashCode()
|
||||
}
|
||||
|
||||
Vendored
+2
-2
@@ -4,8 +4,8 @@ public fun foo(x: String?, y: String?): Int {
|
||||
// z is not null in both branches
|
||||
z.length
|
||||
// y is nullable if x != null
|
||||
y.<!UNSAFE_CALL!>length<!>
|
||||
y<!UNSAFE_CALL!>.<!>length
|
||||
}
|
||||
// y is null because of the break
|
||||
return y.<!UNSAFE_CALL!>length<!>
|
||||
return y<!UNSAFE_CALL!>.<!>length
|
||||
}
|
||||
+1
-1
@@ -13,5 +13,5 @@ public fun foo(x: String?): Int {
|
||||
checkSubtype<Int>(y)
|
||||
}
|
||||
// x is null because of the break
|
||||
return x.<!UNSAFE_CALL!>length<!>
|
||||
return x<!UNSAFE_CALL!>.<!>length
|
||||
}
|
||||
|
||||
+2
-2
@@ -10,7 +10,7 @@ public fun foo(x: String?, z: String?, w: String?): Int {
|
||||
// w is not null because of w!!
|
||||
w.length
|
||||
// z is nullable despite of z!!
|
||||
z.<!UNSAFE_CALL!>length<!>
|
||||
z<!UNSAFE_CALL!>.<!>length
|
||||
// x is null because of the break
|
||||
return x.<!UNSAFE_CALL!>length<!>
|
||||
return x<!UNSAFE_CALL!>.<!>length
|
||||
}
|
||||
|
||||
+2
-2
@@ -7,7 +7,7 @@ public fun foo(x: String?, z: String?): Int {
|
||||
gav(if (x == null) break else x, z!!)
|
||||
} while (bar())
|
||||
// z is nullable despite of z!!
|
||||
z.<!UNSAFE_CALL!>length<!>
|
||||
z<!UNSAFE_CALL!>.<!>length
|
||||
// x is null because of the break
|
||||
return x.<!UNSAFE_CALL!>length<!>
|
||||
return x<!UNSAFE_CALL!>.<!>length
|
||||
}
|
||||
|
||||
+1
-1
@@ -10,5 +10,5 @@ public fun foo(x: String?): Int {
|
||||
} while (bar())
|
||||
y.hashCode()
|
||||
// x is null because of the break
|
||||
return x.<!UNSAFE_CALL!>length<!>
|
||||
return x<!UNSAFE_CALL!>.<!>length
|
||||
}
|
||||
|
||||
+1
-1
@@ -9,5 +9,5 @@ public fun foo(x: String?, z: String?): Int {
|
||||
// z is not null because of z!!
|
||||
z.length
|
||||
// x is null because of the break
|
||||
return x.<!UNSAFE_CALL!>length<!>
|
||||
return x<!UNSAFE_CALL!>.<!>length
|
||||
}
|
||||
|
||||
+1
-1
@@ -12,5 +12,5 @@ public fun foo(x: String?, z: String?, w: String?): Int {
|
||||
// z is not null because of z!!
|
||||
z.length
|
||||
// x is null because of the break
|
||||
return x.<!UNSAFE_CALL!>length<!>
|
||||
return x<!UNSAFE_CALL!>.<!>length
|
||||
}
|
||||
|
||||
-13
@@ -1,13 +0,0 @@
|
||||
fun x(): Boolean { return true }
|
||||
|
||||
fun y(): Boolean { return false }
|
||||
|
||||
public fun foo(p: String?): Int {
|
||||
do {
|
||||
if (y()) break
|
||||
// We do not always reach this statement
|
||||
p!!.length
|
||||
} while (!x())
|
||||
// Here we have do while loop but p is still nullable due to break before
|
||||
return p.<!UNSAFE_CALL!>length<!>
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
fun x(): Boolean { return true }
|
||||
|
||||
fun y(): Boolean { return false }
|
||||
|
||||
-9
@@ -1,9 +0,0 @@
|
||||
fun bar(): Boolean { return true }
|
||||
|
||||
fun foo(s: String?): Int {
|
||||
do {
|
||||
if (bar()) break
|
||||
} while (s!!.length > 0)
|
||||
// This call is unsafe due to break
|
||||
return s.<!UNSAFE_CALL!>length<!>
|
||||
}
|
||||
+1
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
fun bar(): Boolean { return true }
|
||||
|
||||
fun foo(s: String?): Int {
|
||||
|
||||
-10
@@ -1,10 +0,0 @@
|
||||
fun x(): Boolean { return true }
|
||||
|
||||
public fun foo(p: String?): Int {
|
||||
// See KT-6283
|
||||
do {
|
||||
if (p != null) break
|
||||
} while (!x())
|
||||
// p can be null despite of the break
|
||||
return p.<!UNSAFE_CALL!>length<!>
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
fun x(): Boolean { return true }
|
||||
|
||||
public fun foo(p: String?): Int {
|
||||
|
||||
-9
@@ -1,9 +0,0 @@
|
||||
fun bar(): Boolean { return true }
|
||||
|
||||
fun foo(s: String?): Int {
|
||||
do {
|
||||
if (bar()) break
|
||||
} while (s==null)
|
||||
// This call is unsafe due to break
|
||||
return s.<!UNSAFE_CALL!>length<!>
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
fun bar(): Boolean { return true }
|
||||
|
||||
fun foo(s: String?): Int {
|
||||
|
||||
+1
-1
@@ -6,5 +6,5 @@ public fun foo(x: String?): Int {
|
||||
x.length
|
||||
} while (true)
|
||||
// x is null because of the break
|
||||
return x.<!UNSAFE_CALL!>length<!>
|
||||
return x<!UNSAFE_CALL!>.<!>length
|
||||
}
|
||||
-9
@@ -1,9 +0,0 @@
|
||||
public fun foo(x: String?, y: String?): Int {
|
||||
while (true) {
|
||||
x ?: if (y == null) break
|
||||
// y is nullable if x != null
|
||||
y.<!UNSAFE_CALL!>length<!>
|
||||
}
|
||||
// y is null because of the break
|
||||
return y.<!UNSAFE_CALL!>length<!>
|
||||
}
|
||||
+1
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
public fun foo(x: String?, y: String?): Int {
|
||||
while (true) {
|
||||
x ?: if (y == null) break
|
||||
|
||||
-9
@@ -1,9 +0,0 @@
|
||||
public fun foo(x: String?, y: String?): Int {
|
||||
while (true) {
|
||||
(if (x != null) break else y) ?: y!!
|
||||
// y is not null in both branches but it's hard to determine
|
||||
y.<!UNSAFE_CALL!>length<!>
|
||||
}
|
||||
// y can be null because of the break
|
||||
return y.<!UNSAFE_CALL!>length<!>
|
||||
}
|
||||
+1
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
public fun foo(x: String?, y: String?): Int {
|
||||
while (true) {
|
||||
(if (x != null) break else y) ?: y!!
|
||||
|
||||
+1
-1
@@ -10,5 +10,5 @@ public fun foo(x: String?): Int {
|
||||
} while (bar())
|
||||
y.hashCode()
|
||||
// x is null because of the break
|
||||
return x.<!UNSAFE_CALL!>length<!>
|
||||
return x<!UNSAFE_CALL!>.<!>length
|
||||
}
|
||||
|
||||
+1
-1
@@ -6,5 +6,5 @@ public fun foo(x: String?): Int {
|
||||
// In future we can infer this initialization
|
||||
<!UNINITIALIZED_VARIABLE!>y<!>.hashCode()
|
||||
// x is null because of the break
|
||||
return x.<!UNSAFE_CALL!>length<!>
|
||||
return x<!UNSAFE_CALL!>.<!>length
|
||||
}
|
||||
|
||||
+1
-1
@@ -6,5 +6,5 @@ public fun foo(x: String?): Int {
|
||||
y.length
|
||||
}
|
||||
// x is null because of the break
|
||||
return x.<!UNSAFE_CALL!>length<!>
|
||||
return x<!UNSAFE_CALL!>.<!>length
|
||||
}
|
||||
|
||||
+1
-1
@@ -7,5 +7,5 @@ public fun foo(x: String?, y: String?): Int {
|
||||
y.length
|
||||
}
|
||||
// y is null because of the break
|
||||
return y.<!UNSAFE_CALL!>length<!>
|
||||
return y<!UNSAFE_CALL!>.<!>length
|
||||
}
|
||||
+1
-1
@@ -13,7 +13,7 @@ public fun foo(p: String?, r: String?, q: String?): Int {
|
||||
if (!x(p)) break
|
||||
}
|
||||
// Long break allows r == null
|
||||
r.<!UNSAFE_CALL!>length<!>
|
||||
r<!UNSAFE_CALL!>.<!>length
|
||||
// Smart cast is possible
|
||||
q.length
|
||||
return p.length
|
||||
|
||||
+1
-1
@@ -18,5 +18,5 @@ public fun foo(x: String?): Int {
|
||||
// y is always Int even here
|
||||
checkSubtype<Int>(y)
|
||||
// x is null because of the break
|
||||
return x.<!UNSAFE_CALL!>length<!>
|
||||
return x<!UNSAFE_CALL!>.<!>length
|
||||
}
|
||||
|
||||
+1
-1
@@ -8,5 +8,5 @@ public fun foo(x: String?): Int {
|
||||
}
|
||||
}
|
||||
// x is null because of the break
|
||||
return x.<!UNSAFE_CALL!>length<!>
|
||||
return x<!UNSAFE_CALL!>.<!>length
|
||||
}
|
||||
|
||||
-9
@@ -1,9 +0,0 @@
|
||||
fun bar(): Boolean { return true }
|
||||
|
||||
fun foo(s: String?): Int {
|
||||
while (s==null) {
|
||||
if (bar()) break
|
||||
}
|
||||
// Call is unsafe due to break
|
||||
return s.<!UNSAFE_CALL!>length<!>
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
fun bar(): Boolean { return true }
|
||||
|
||||
fun foo(s: String?): Int {
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
fun x(): Boolean { return true }
|
||||
|
||||
public fun foo(p: String?): Int {
|
||||
while(x()) {
|
||||
p!!.length
|
||||
if (x()) break
|
||||
}
|
||||
// p is nullable because it's possible loop body is not executed at all
|
||||
return p.<!UNSAFE_CALL!>length<!>
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
fun x(): Boolean { return true }
|
||||
|
||||
public fun foo(p: String?): Int {
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
fun x(): Boolean { return true }
|
||||
|
||||
public fun foo(p: String?): Int {
|
||||
// Like whileTrue but 2 == 2 is in use
|
||||
while(2 == 2) {
|
||||
p!!.length
|
||||
if (x()) break
|
||||
}
|
||||
// Smart cast should not work in this case, see KT-6284
|
||||
return p.<!UNSAFE_CALL!>length<!>
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
fun x(): Boolean { return true }
|
||||
|
||||
public fun foo(p: String?): Int {
|
||||
|
||||
+1
-1
@@ -8,5 +8,5 @@ public fun foo(p: String?): Int {
|
||||
p.length
|
||||
}
|
||||
// p can be null because break is earlier than return
|
||||
return p.<!UNSAFE_CALL!>length<!>
|
||||
return p<!UNSAFE_CALL!>.<!>length
|
||||
}
|
||||
-11
@@ -1,11 +0,0 @@
|
||||
fun x(): Boolean { return true }
|
||||
|
||||
public fun foo(p: String?): Int {
|
||||
while(true) {
|
||||
if (x()) break
|
||||
// We do not always reach this statement
|
||||
p!!.length
|
||||
}
|
||||
// Here we have while (true) loop but p is nullable due to break before
|
||||
return p.<!UNSAFE_CALL!>length<!>
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
fun x(): Boolean { return true }
|
||||
|
||||
public fun foo(p: String?): Int {
|
||||
|
||||
Vendored
+2
-2
@@ -8,7 +8,7 @@ fun foo() {
|
||||
|
||||
}
|
||||
// TODO: this testdata fixates undesired behavior (it should be an unsafe call)
|
||||
x.<!UNSAFE_CALL!>length<!> // 'x' is unsoundly smartcasted here
|
||||
x<!UNSAFE_CALL!>.<!>length // 'x' is unsoundly smartcasted here
|
||||
}
|
||||
|
||||
fun bar() {
|
||||
@@ -19,5 +19,5 @@ fun bar() {
|
||||
|
||||
}
|
||||
// TODO: this testdata fixates undesired behavior (it should be an unsafe call)
|
||||
x.<!UNSAFE_CALL!>size<!> // 'x' is unsoundly smartcasted here
|
||||
x<!UNSAFE_CALL!>.<!>size // 'x' is unsoundly smartcasted here
|
||||
}
|
||||
compiler/testData/diagnostics/tests/smartCasts/loops/whileWithAssertInConditionAndBreakBefore.fir.kt
Vendored
+2
-2
@@ -7,7 +7,7 @@ fun foo() {
|
||||
break
|
||||
|
||||
}
|
||||
x.<!UNSAFE_CALL!>length<!> // 'x' is unsoundly smartcasted here
|
||||
x<!UNSAFE_CALL!>.<!>length // 'x' is unsoundly smartcasted here
|
||||
}
|
||||
|
||||
fun bar() {
|
||||
@@ -17,5 +17,5 @@ fun bar() {
|
||||
break
|
||||
|
||||
}
|
||||
x.<!UNSAFE_CALL!>size<!> // 'x' is unsoundly smartcasted here
|
||||
x<!UNSAFE_CALL!>.<!>size // 'x' is unsoundly smartcasted here
|
||||
}
|
||||
+1
-1
@@ -7,5 +7,5 @@ abstract class A(val s: String) {
|
||||
fun foo(o: String?): Int {
|
||||
val a = object : A(o!!){}
|
||||
a.bar()
|
||||
return o.<!UNSAFE_CALL!>length<!>
|
||||
return o<!UNSAFE_CALL!>.<!>length
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ sealed class My(open val x: Int?) {
|
||||
init {
|
||||
if (x != null) {
|
||||
// Should be error: property is open
|
||||
x.<!UNSAFE_CALL!>hashCode<!>()
|
||||
x<!UNSAFE_CALL!>.<!>hashCode()
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -9,5 +9,5 @@ fun foo(arg: Int?) {
|
||||
}
|
||||
if (x != null) x = 42
|
||||
// Unsafe because of lambda
|
||||
x.<!UNSAFE_CALL!>hashCode<!>()
|
||||
x<!UNSAFE_CALL!>.<!>hashCode()
|
||||
}
|
||||
+1
-1
@@ -5,7 +5,7 @@ public class X {
|
||||
public fun fn(): Int {
|
||||
if (y != null)
|
||||
// With non-default getter smartcast is not possible
|
||||
return y.<!UNSAFE_CALL!>length<!>
|
||||
return y<!UNSAFE_CALL!>.<!>length
|
||||
else
|
||||
return 0
|
||||
}
|
||||
|
||||
@@ -4,10 +4,10 @@ public class X {
|
||||
public fun fn(): Int {
|
||||
if (x != null)
|
||||
// Smartcast is not possible for variable properties
|
||||
return x.<!UNSAFE_CALL!>length<!>
|
||||
return x<!UNSAFE_CALL!>.<!>length
|
||||
else if (y != null)
|
||||
// Even if they are private
|
||||
return y.<!UNSAFE_CALL!>length<!>
|
||||
return y<!UNSAFE_CALL!>.<!>length
|
||||
else
|
||||
return 0
|
||||
}
|
||||
|
||||
@@ -2,5 +2,5 @@ fun calc(x: List<String>?): Int {
|
||||
// After KT-5840 fix !! assertion should become unnecessary here
|
||||
x?.get(x!!.size - 1)
|
||||
// x?. or x!! above should not provide smart cast here
|
||||
return x.<!UNSAFE_CALL!>size<!>
|
||||
return x<!UNSAFE_CALL!>.<!>size
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
fun calc(x: List<String>?): Int {
|
||||
// x is not-null only inside subList
|
||||
x?.subList(0, x.size - 1).<!UNSAFE_CALL!>get<!>(x.<!UNSAFE_CALL!>size<!>)
|
||||
x?.subList(0, x.size - 1)<!UNSAFE_CALL!>.<!>get(x<!UNSAFE_CALL!>.<!>size)
|
||||
return x!!.size
|
||||
}
|
||||
|
||||
@@ -2,5 +2,5 @@ fun calc(x: List<String>?): Int {
|
||||
// x should be non-null in arguments list, including inner call
|
||||
x?.get(x.get(x.size - 1).length)
|
||||
// but not also here!
|
||||
return x.<!UNSAFE_CALL!>size<!>
|
||||
return x<!UNSAFE_CALL!>.<!>size
|
||||
}
|
||||
|
||||
+1
-1
@@ -4,5 +4,5 @@ fun calc(x: String?, y: String?): Int {
|
||||
// Smart cast because of y!! in receiver
|
||||
x?.subSequence(y!!.subSequence(0, 1).length, y.length)
|
||||
// No smart cast possible
|
||||
return y.<!UNSAFE_CALL!>length<!>
|
||||
return y<!UNSAFE_CALL!>.<!>length
|
||||
}
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
// See KT-11007: Wrong smart cast to not-null type after safe calls in if / when expression
|
||||
|
||||
val String.copy: String
|
||||
get() = this
|
||||
|
||||
fun foo() {
|
||||
val s: String? = null
|
||||
val ss = if (true) {
|
||||
s?.length
|
||||
} else {
|
||||
s?.length
|
||||
}
|
||||
ss.<!UNSAFE_CALL!>hashCode<!>() // Smart-cast to Int, should be unsafe call
|
||||
val sss = if (true) {
|
||||
s?.copy
|
||||
}
|
||||
else {
|
||||
s?.copy
|
||||
}
|
||||
sss.<!UNSAFE_CALL!>length<!>
|
||||
}
|
||||
|
||||
class My {
|
||||
val String.copy2: String
|
||||
get() = this
|
||||
|
||||
fun foo() {
|
||||
val s: String? = null
|
||||
val ss = if (true) {
|
||||
s?.length
|
||||
} else {
|
||||
s?.length
|
||||
}
|
||||
ss.<!UNSAFE_CALL!>hashCode<!>()
|
||||
val sss = if (true) {
|
||||
s?.copy2
|
||||
}
|
||||
else {
|
||||
s?.copy2
|
||||
}
|
||||
sss.<!UNSAFE_CALL!>length<!>
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
// See KT-11007: Wrong smart cast to not-null type after safe calls in if / when expression
|
||||
|
||||
val String.copy: String
|
||||
|
||||
-13
@@ -1,13 +0,0 @@
|
||||
// See KT-10056
|
||||
class Foo(val bar: String)
|
||||
|
||||
fun test(foo: Foo?) {
|
||||
foo?.bar.let {
|
||||
// Error, foo?.bar is nullable
|
||||
it.<!UNSAFE_CALL!>length<!>
|
||||
// Error, foo is nullable
|
||||
foo.<!UNSAFE_CALL!>bar<!>.length
|
||||
// Correct
|
||||
foo?.bar?.length
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
// See KT-10056
|
||||
class Foo(val bar: String)
|
||||
|
||||
|
||||
Vendored
+6
-6
@@ -11,22 +11,22 @@ fun String.notNullLet(f: (String) -> Unit) = f(this)
|
||||
fun test(foo: Foo?) {
|
||||
foo?.bar?.gav.let {
|
||||
// Error, foo?.bar?.gav is nullable
|
||||
it.<!UNSAFE_CALL!>length<!>
|
||||
it<!UNSAFE_CALL!>.<!>length
|
||||
// Error, foo is nullable
|
||||
foo.<!UNSAFE_CALL!>bar<!>.gav.length
|
||||
foo<!UNSAFE_CALL!>.<!>bar.gav.length
|
||||
// Correct
|
||||
foo?.bar?.gav?.length
|
||||
}
|
||||
foo?.bar?.gav.call { it }?.notNullLet {
|
||||
foo.<!UNSAFE_CALL!>hashCode<!>()
|
||||
foo.<!UNSAFE_CALL!>bar<!>.hashCode()
|
||||
foo<!UNSAFE_CALL!>.<!>hashCode()
|
||||
foo<!UNSAFE_CALL!>.<!>bar.hashCode()
|
||||
}
|
||||
}
|
||||
|
||||
fun testNotNull(foo: Foo) {
|
||||
val s: String? = ""
|
||||
foo.baz(s!!)?.gav.let {
|
||||
it.<!UNSAFE_CALL!>length<!>
|
||||
it<!UNSAFE_CALL!>.<!>length
|
||||
// Ok because of foo.
|
||||
s.length.hashCode()
|
||||
}
|
||||
@@ -35,7 +35,7 @@ fun testNotNull(foo: Foo) {
|
||||
fun testNullable(foo: Foo?) {
|
||||
val s: String? = ""
|
||||
foo?.baz(s!!)?.gav.let {
|
||||
it.<!UNSAFE_CALL!>length<!>
|
||||
it<!UNSAFE_CALL!>.<!>length
|
||||
// Ok because of foo?.
|
||||
s?.length?.hashCode()
|
||||
}
|
||||
|
||||
Vendored
-25
@@ -1,25 +0,0 @@
|
||||
// FILE: Foo.java
|
||||
public class Foo {
|
||||
public String bar;
|
||||
|
||||
private Foo(String bar) {
|
||||
this.bar = bar;
|
||||
}
|
||||
|
||||
public static Foo create(String bar) {
|
||||
return new Foo(bar);
|
||||
}
|
||||
}
|
||||
|
||||
// FILE: Test.kt
|
||||
fun test() {
|
||||
val foo = Foo.create(null)
|
||||
foo?.bar.let {
|
||||
// Error, foo?.bar is nullable
|
||||
it.<!UNSAFE_CALL!>length<!>
|
||||
// Foo is nullable but flexible, so call is considered safe here
|
||||
foo.bar.length
|
||||
// Correct
|
||||
foo?.bar?.length
|
||||
}
|
||||
}
|
||||
+1
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
// FILE: Foo.java
|
||||
public class Foo {
|
||||
public String bar;
|
||||
|
||||
+4
-4
@@ -18,7 +18,7 @@ fun kt6840_2(s: String?) {
|
||||
|
||||
fun kt1635(s: String?) {
|
||||
s?.hashCode()!!
|
||||
s.<!UNSAFE_CALL!>hashCode<!>()
|
||||
s<!UNSAFE_CALL!>.<!>hashCode()
|
||||
}
|
||||
|
||||
fun kt2127() {
|
||||
@@ -80,7 +80,7 @@ fun useA(a: A): Int = a.hashCode()
|
||||
|
||||
fun kt7491_2() {
|
||||
val a = getA()
|
||||
(a?.let { useA(a) } ?: a.<!UNSAFE_CALL!>y<!> ).toString()
|
||||
(a?.let { useA(a) } ?: a<!UNSAFE_CALL!>.<!>y ).toString()
|
||||
}
|
||||
|
||||
fun String.correct() = true
|
||||
@@ -88,7 +88,7 @@ fun String.correct() = true
|
||||
fun kt8492(s: String?) {
|
||||
if (s?.correct() ?: false) {
|
||||
// To be supported
|
||||
s.<!UNSAFE_CALL!>length<!>
|
||||
s<!UNSAFE_CALL!>.<!>length
|
||||
}
|
||||
}
|
||||
|
||||
@@ -118,7 +118,7 @@ class Wrapper {
|
||||
fun falsePositive(w: Wrapper) {
|
||||
if (w.unwrap() != null) {
|
||||
// Here we should NOT have smart cast
|
||||
w.unwrap().<!UNSAFE_CALL!>length<!>
|
||||
w.unwrap()<!UNSAFE_CALL!>.<!>length
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,5 +2,5 @@ fun calc(x: List<String>?): Int {
|
||||
// x should be non-null in arguments list
|
||||
x?.get(x.size - 1)
|
||||
// but not also here!
|
||||
return x.<!UNSAFE_CALL!>size<!>
|
||||
return x<!UNSAFE_CALL!>.<!>size
|
||||
}
|
||||
|
||||
@@ -2,5 +2,5 @@ fun calc(x: List<String>?): Int {
|
||||
// x should be non-null in arguments list
|
||||
x?.subList(x.size - 1, x.size)
|
||||
// but not also here!
|
||||
return x.<!UNSAFE_CALL!>size<!>
|
||||
return x<!UNSAFE_CALL!>.<!>size
|
||||
}
|
||||
|
||||
@@ -15,6 +15,6 @@ fun bar(): Int {
|
||||
return when(ss) {
|
||||
"abc" -> ss
|
||||
else -> "xyz"
|
||||
}.<!UNSAFE_CALL!>length<!>
|
||||
}<!UNSAFE_CALL!>.<!>length
|
||||
}
|
||||
|
||||
|
||||
Vendored
-11
@@ -1,11 +0,0 @@
|
||||
// !DIAGNOSTICS: -UNUSED_EXPRESSION
|
||||
// See KT-27260
|
||||
|
||||
class A(val x: String?) {
|
||||
fun foo(other: A) {
|
||||
when {
|
||||
x == null && other.x == null -> "1"
|
||||
x.<!UNSAFE_CALL!>length<!> > 0 -> "2"
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
// !DIAGNOSTICS: -UNUSED_EXPRESSION
|
||||
// See KT-27260
|
||||
|
||||
|
||||
@@ -3,15 +3,15 @@ class Foo(var x: Int?) {
|
||||
if (x != null) {
|
||||
val y = x
|
||||
// Error: x is not stable, Type(y) = Int?
|
||||
x.<!UNSAFE_CALL!>hashCode<!>()
|
||||
y.<!UNSAFE_CALL!>hashCode<!>()
|
||||
x<!UNSAFE_CALL!>.<!>hashCode()
|
||||
y<!UNSAFE_CALL!>.<!>hashCode()
|
||||
if (y == x) {
|
||||
// Still error
|
||||
y.<!UNSAFE_CALL!>hashCode<!>()
|
||||
y<!UNSAFE_CALL!>.<!>hashCode()
|
||||
}
|
||||
if (x == null && y != x) {
|
||||
// Still error
|
||||
y.<!UNSAFE_CALL!>hashCode<!>()
|
||||
y<!UNSAFE_CALL!>.<!>hashCode()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -6,5 +6,5 @@ fun foo(x: Int, f: () -> Unit, y: Int) {}
|
||||
fun bar() {
|
||||
var x: Int?
|
||||
x = 4
|
||||
foo(x, { x = null; x.<!UNSAFE_CALL!>hashCode<!>() }, x)
|
||||
foo(x, { x = null; x<!UNSAFE_CALL!>.<!>hashCode() }, x)
|
||||
}
|
||||
|
||||
+2
-2
@@ -1,11 +1,11 @@
|
||||
// !WITH_NEW_INFERENCE
|
||||
fun foo() {
|
||||
var v: String? = null
|
||||
v.<!UNSAFE_CALL!>length<!>
|
||||
v<!UNSAFE_CALL!>.<!>length
|
||||
v = "abc"
|
||||
v.length
|
||||
v = null
|
||||
v.<!UNSAFE_CALL!>length<!>
|
||||
v<!UNSAFE_CALL!>.<!>length
|
||||
v = "abc"
|
||||
v.length
|
||||
}
|
||||
|
||||
+2
-2
@@ -23,7 +23,7 @@ fun bar(s: String?) {
|
||||
val hashCode = ss?.hashCode()
|
||||
ss = null
|
||||
if (hashCode != null) {
|
||||
ss.<!UNSAFE_CALL!>hashCode<!>()
|
||||
ss<!UNSAFE_CALL!>.<!>hashCode()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,6 +41,6 @@ fun baz(arg: Some?) {
|
||||
val ss = arg?.s
|
||||
if (ss != null) {
|
||||
arg.hashCode()
|
||||
arg.s.<!UNSAFE_CALL!>hashCode<!>()
|
||||
arg.s<!UNSAFE_CALL!>.<!>hashCode()
|
||||
}
|
||||
}
|
||||
|
||||
+3
-3
@@ -37,7 +37,7 @@ fun test3() {
|
||||
catch (e: B) {
|
||||
return
|
||||
}
|
||||
a.<!UNSAFE_CALL!>hashCode<!>() // a is nullable here
|
||||
a<!UNSAFE_CALL!>.<!>hashCode() // a is nullable here
|
||||
}
|
||||
fun test4() {
|
||||
var a: Int? = null
|
||||
@@ -50,7 +50,7 @@ fun test4() {
|
||||
catch (e: B) {
|
||||
return
|
||||
}
|
||||
a.<!UNSAFE_CALL!>hashCode<!>() // a is nullable here
|
||||
a<!UNSAFE_CALL!>.<!>hashCode() // a is nullable here
|
||||
}
|
||||
fun test5() {
|
||||
var a: Int?// = null
|
||||
@@ -76,5 +76,5 @@ fun test6() {
|
||||
finally {
|
||||
a = null
|
||||
}
|
||||
a.<!UNSAFE_CALL!>hashCode<!>() // a is null here
|
||||
a<!UNSAFE_CALL!>.<!>hashCode() // a is null here
|
||||
}
|
||||
|
||||
+2
-2
@@ -2,7 +2,7 @@
|
||||
fun foo() {
|
||||
var v: String? = "xyz"
|
||||
// It is possible in principle to provide smart cast here
|
||||
v.<!UNSAFE_CALL!>length<!>
|
||||
v<!UNSAFE_CALL!>.<!>length
|
||||
v = null
|
||||
v.<!UNSAFE_CALL!>length<!>
|
||||
v<!UNSAFE_CALL!>.<!>length
|
||||
}
|
||||
|
||||
+1
-1
@@ -12,7 +12,7 @@ fun foo(): Bar {
|
||||
var y: Bar? = Bar()
|
||||
while (x != null) {
|
||||
// Here call is unsafe because of initialization and also inner loop
|
||||
y.<!UNSAFE_CALL!>next<!>()
|
||||
y<!UNSAFE_CALL!>.<!>next()
|
||||
while (y != null) {
|
||||
if (x == y)
|
||||
// x is not null because of outer while
|
||||
|
||||
-8
@@ -1,8 +0,0 @@
|
||||
operator fun Int?.inc(): Int? { return this }
|
||||
|
||||
public fun box(arg: Int?) : Int? {
|
||||
var i : Int? = arg
|
||||
var j = i++
|
||||
j.<!UNSAFE_CALL!>toInt<!>()
|
||||
return i
|
||||
}
|
||||
+1
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
operator fun Int?.inc(): Int? { return this }
|
||||
|
||||
public fun box(arg: Int?) : Int? {
|
||||
|
||||
Vendored
-13
@@ -1,13 +0,0 @@
|
||||
class MyClass
|
||||
|
||||
// Correct at compile time but wrong at run-time
|
||||
operator fun MyClass?.inc(): MyClass? { return null }
|
||||
|
||||
public fun box() {
|
||||
var i : MyClass?
|
||||
i = MyClass()
|
||||
// type of j should be MyClass?
|
||||
var j = ++i
|
||||
// j is null so call should be unsafe
|
||||
j.<!UNSAFE_CALL!>hashCode<!>()
|
||||
}
|
||||
+1
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
class MyClass
|
||||
|
||||
// Correct at compile time but wrong at run-time
|
||||
|
||||
-8
@@ -1,8 +0,0 @@
|
||||
operator fun Int?.inc(): Int? { return this }
|
||||
|
||||
public fun box(arg: Int?) : Int? {
|
||||
var i = arg
|
||||
var j = ++i
|
||||
j.<!UNSAFE_CALL!>toInt<!>()
|
||||
return ++j
|
||||
}
|
||||
+1
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
operator fun Int?.inc(): Int? { return this }
|
||||
|
||||
public fun box(arg: Int?) : Int? {
|
||||
|
||||
-14
@@ -1,14 +0,0 @@
|
||||
// !LANGUAGE: +SoundSmartCastsAfterTry
|
||||
|
||||
fun bar(arg: Any?) = arg
|
||||
|
||||
fun foo() {
|
||||
var s: String?
|
||||
s = null
|
||||
try {
|
||||
s = "Test"
|
||||
} catch (ex: Exception) {}
|
||||
bar(s)
|
||||
if (s != null) { }
|
||||
s.<!UNSAFE_CALL!>hashCode<!>()
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
// !LANGUAGE: +SoundSmartCastsAfterTry
|
||||
|
||||
fun bar(arg: Any?) = arg
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user