Don't register safe cast type info for unstable values
Important: to be removed in 1.3 So #KT-20752 Fixed
This commit is contained in:
committed by
Mikhail Glukhikh
parent
8ae3dbdcfc
commit
a55c6f0c95
+14
-6
@@ -96,9 +96,12 @@ internal class DelegatingDataFlowInfo private constructor(
|
|||||||
nullability: Nullability,
|
nullability: Nullability,
|
||||||
languageVersionSettings: LanguageVersionSettings,
|
languageVersionSettings: LanguageVersionSettings,
|
||||||
typeInfo: SetMultimap<DataFlowValue, KotlinType>? = null,
|
typeInfo: SetMultimap<DataFlowValue, KotlinType>? = null,
|
||||||
affectReceiver: Boolean = true
|
affectReceiver: Boolean = true,
|
||||||
|
recordUnstable: Boolean = true
|
||||||
): Boolean {
|
): Boolean {
|
||||||
map.put(value, nullability)
|
if (value.isStable || recordUnstable) {
|
||||||
|
map.put(value, nullability)
|
||||||
|
}
|
||||||
|
|
||||||
val identifierInfo = value.identifierInfo
|
val identifierInfo = value.identifierInfo
|
||||||
if (affectReceiver && !nullability.canBeNull() &&
|
if (affectReceiver && !nullability.canBeNull() &&
|
||||||
@@ -108,7 +111,8 @@ internal class DelegatingDataFlowInfo private constructor(
|
|||||||
val receiverType = identifierInfo.receiverType
|
val receiverType = identifierInfo.receiverType
|
||||||
if (identifierInfo.safe && receiverType != null) {
|
if (identifierInfo.safe && receiverType != null) {
|
||||||
val receiverValue = DataFlowValue(identifierInfo.receiverInfo, receiverType)
|
val receiverValue = DataFlowValue(identifierInfo.receiverInfo, receiverType)
|
||||||
putNullabilityAndTypeInfo(map, receiverValue, nullability, languageVersionSettings, typeInfo)
|
putNullabilityAndTypeInfo(map, receiverValue, nullability,
|
||||||
|
languageVersionSettings, typeInfo, recordUnstable = recordUnstable)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is IdentifierInfo.SafeCast -> {
|
is IdentifierInfo.SafeCast -> {
|
||||||
@@ -118,12 +122,16 @@ internal class DelegatingDataFlowInfo private constructor(
|
|||||||
languageVersionSettings.supportsFeature(LanguageFeature.SafeCastCheckBoundSmartCasts)) {
|
languageVersionSettings.supportsFeature(LanguageFeature.SafeCastCheckBoundSmartCasts)) {
|
||||||
|
|
||||||
val subjectValue = DataFlowValue(identifierInfo.subjectInfo, subjectType)
|
val subjectValue = DataFlowValue(identifierInfo.subjectInfo, subjectType)
|
||||||
putNullabilityAndTypeInfo(map, subjectValue, nullability, languageVersionSettings, typeInfo)
|
putNullabilityAndTypeInfo(map, subjectValue, nullability,
|
||||||
typeInfo?.put(subjectValue, targetType)
|
languageVersionSettings, typeInfo, recordUnstable = false)
|
||||||
|
if (subjectValue.isStable) {
|
||||||
|
typeInfo?.put(subjectValue, targetType)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is IdentifierInfo.Variable -> identifierInfo.bound?.let {
|
is IdentifierInfo.Variable -> identifierInfo.bound?.let {
|
||||||
putNullabilityAndTypeInfo(map, it, nullability, languageVersionSettings, typeInfo)
|
putNullabilityAndTypeInfo(map, it, nullability,
|
||||||
|
languageVersionSettings, typeInfo, recordUnstable = recordUnstable)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
// !LANGUAGE: +SafeCastCheckBoundSmartCasts
|
||||||
|
// See KT-20752
|
||||||
|
|
||||||
|
class Unstable {
|
||||||
|
val first: String? get() = null
|
||||||
|
}
|
||||||
|
|
||||||
|
class StringList {
|
||||||
|
fun remove(s: String) = s
|
||||||
|
}
|
||||||
|
|
||||||
|
fun StringList.remove(s: String?) = s ?: ""
|
||||||
|
|
||||||
|
fun foo(list: StringList, arg: Unstable) {
|
||||||
|
list.remove(arg.first)
|
||||||
|
if (arg.first <!USELESS_CAST!>as? String<!> != null) {
|
||||||
|
// Ideally should have smart cast impossible here
|
||||||
|
list.remove(arg.first)
|
||||||
|
}
|
||||||
|
val s = arg.first <!USELESS_CAST!>as? String<!>
|
||||||
|
if (s != null) {
|
||||||
|
// Ideally should have smart cast impossible here
|
||||||
|
list.remove(arg.first)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
package
|
||||||
|
|
||||||
|
public fun foo(/*0*/ list: StringList, /*1*/ arg: Unstable): kotlin.Unit
|
||||||
|
public fun StringList.remove(/*0*/ s: kotlin.String?): kotlin.String
|
||||||
|
|
||||||
|
public final class StringList {
|
||||||
|
public constructor StringList()
|
||||||
|
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||||
|
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||||
|
public final fun remove(/*0*/ s: kotlin.String): kotlin.String
|
||||||
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class Unstable {
|
||||||
|
public constructor Unstable()
|
||||||
|
public final val first: kotlin.String?
|
||||||
|
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||||
|
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||||
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
// !LANGUAGE: +BooleanElvisBoundSmartCasts
|
||||||
|
// See KT-20752
|
||||||
|
|
||||||
|
class Unstable {
|
||||||
|
val first: String? get() = null
|
||||||
|
}
|
||||||
|
|
||||||
|
class StringList {
|
||||||
|
fun remove(s: String) = s
|
||||||
|
}
|
||||||
|
|
||||||
|
fun StringList.remove(s: String?) = s ?: ""
|
||||||
|
|
||||||
|
fun String.isEmpty() = this == ""
|
||||||
|
|
||||||
|
fun foo(list: StringList, arg: Unstable) {
|
||||||
|
list.remove(arg.first)
|
||||||
|
if (arg.first?.isEmpty() ?: false) {
|
||||||
|
// Ideally should have smart cast impossible here
|
||||||
|
list.remove(<!SMARTCAST_IMPOSSIBLE!>arg.first<!>)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class UnstableBoolean {
|
||||||
|
val first: Boolean? get() = null
|
||||||
|
}
|
||||||
|
|
||||||
|
class BooleanList {
|
||||||
|
fun remove(b: Boolean) = b
|
||||||
|
}
|
||||||
|
|
||||||
|
fun BooleanList.remove(b: Boolean?) = b ?: false
|
||||||
|
|
||||||
|
fun bar(list: BooleanList, arg: UnstableBoolean) {
|
||||||
|
list.remove(arg.first)
|
||||||
|
if (arg.first ?: false) {
|
||||||
|
// Ideally should have smart cast impossible here
|
||||||
|
list.remove(<!SMARTCAST_IMPOSSIBLE!>arg.first<!>)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
package
|
||||||
|
|
||||||
|
public fun bar(/*0*/ list: BooleanList, /*1*/ arg: UnstableBoolean): kotlin.Unit
|
||||||
|
public fun foo(/*0*/ list: StringList, /*1*/ arg: Unstable): kotlin.Unit
|
||||||
|
public fun kotlin.String.isEmpty(): kotlin.Boolean
|
||||||
|
public fun BooleanList.remove(/*0*/ b: kotlin.Boolean?): kotlin.Boolean
|
||||||
|
public fun StringList.remove(/*0*/ s: kotlin.String?): kotlin.String
|
||||||
|
|
||||||
|
public final class BooleanList {
|
||||||
|
public constructor BooleanList()
|
||||||
|
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||||
|
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||||
|
public final fun remove(/*0*/ b: kotlin.Boolean): kotlin.Boolean
|
||||||
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class StringList {
|
||||||
|
public constructor StringList()
|
||||||
|
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||||
|
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||||
|
public final fun remove(/*0*/ s: kotlin.String): kotlin.String
|
||||||
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class Unstable {
|
||||||
|
public constructor Unstable()
|
||||||
|
public final val first: kotlin.String?
|
||||||
|
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||||
|
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||||
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class UnstableBoolean {
|
||||||
|
public constructor UnstableBoolean()
|
||||||
|
public final val first: kotlin.Boolean?
|
||||||
|
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||||
|
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||||
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
|
}
|
||||||
@@ -20910,6 +20910,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("impossible.kt")
|
||||||
|
public void testImpossible() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/smartCasts/castchecks/impossible.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("insideCall.kt")
|
@TestMetadata("insideCall.kt")
|
||||||
public void testInsideCall() throws Exception {
|
public void testInsideCall() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/smartCasts/castchecks/insideCall.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/smartCasts/castchecks/insideCall.kt");
|
||||||
@@ -20942,6 +20948,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
|
|||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/smartCasts/elvis/basicOn.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/smartCasts/elvis/basicOn.kt");
|
||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("impossible.kt")
|
||||||
|
public void testImpossible() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/smartCasts/elvis/impossible.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("compiler/testData/diagnostics/tests/smartCasts/inference")
|
@TestMetadata("compiler/testData/diagnostics/tests/smartCasts/inference")
|
||||||
|
|||||||
+12
@@ -20910,6 +20910,12 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("impossible.kt")
|
||||||
|
public void testImpossible() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/smartCasts/castchecks/impossible.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("insideCall.kt")
|
@TestMetadata("insideCall.kt")
|
||||||
public void testInsideCall() throws Exception {
|
public void testInsideCall() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/smartCasts/castchecks/insideCall.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/smartCasts/castchecks/insideCall.kt");
|
||||||
@@ -20942,6 +20948,12 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing
|
|||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/smartCasts/elvis/basicOn.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/smartCasts/elvis/basicOn.kt");
|
||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("impossible.kt")
|
||||||
|
public void testImpossible() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/smartCasts/elvis/impossible.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("compiler/testData/diagnostics/tests/smartCasts/inference")
|
@TestMetadata("compiler/testData/diagnostics/tests/smartCasts/inference")
|
||||||
|
|||||||
Reference in New Issue
Block a user