Deprecate smart cast on alien derived property #KT-48101 Fixed
This commit is contained in:
+6
@@ -28094,6 +28094,12 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
|
|||||||
runTest("compiler/testData/diagnostics/tests/smartCasts/publicVals/otherModuleInheritance.kt");
|
runTest("compiler/testData/diagnostics/tests/smartCasts/publicVals/otherModuleInheritance.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("otherModuleInheritance_after.kt")
|
||||||
|
public void testOtherModuleInheritance_after() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/tests/smartCasts/publicVals/otherModuleInheritance_after.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("protected.kt")
|
@TestMetadata("protected.kt")
|
||||||
public void testProtected() throws Exception {
|
public void testProtected() throws Exception {
|
||||||
|
|||||||
+6
@@ -28094,6 +28094,12 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac
|
|||||||
runTest("compiler/testData/diagnostics/tests/smartCasts/publicVals/otherModuleInheritance.kt");
|
runTest("compiler/testData/diagnostics/tests/smartCasts/publicVals/otherModuleInheritance.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("otherModuleInheritance_after.kt")
|
||||||
|
public void testOtherModuleInheritance_after() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/tests/smartCasts/publicVals/otherModuleInheritance_after.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("protected.kt")
|
@TestMetadata("protected.kt")
|
||||||
public void testProtected() throws Exception {
|
public void testProtected() throws Exception {
|
||||||
|
|||||||
+14
-1
@@ -41,25 +41,37 @@ class DataFlowValue(
|
|||||||
// or protected / public member value from the same module without open / custom getter
|
// or protected / public member value from the same module without open / custom getter
|
||||||
// Smart casts are completely safe
|
// Smart casts are completely safe
|
||||||
STABLE_VALUE("stable val"),
|
STABLE_VALUE("stable val"),
|
||||||
|
|
||||||
// Block, or if / else, or when
|
// Block, or if / else, or when
|
||||||
STABLE_COMPLEX_EXPRESSION("complex expression", ""),
|
STABLE_COMPLEX_EXPRESSION("complex expression", ""),
|
||||||
|
|
||||||
// Should be unstable, but can be used as stable with deprecation warning
|
// Should be unstable, but can be used as stable with deprecation warning
|
||||||
LEGACY_STABLE_LOCAL_DELEGATED_PROPERTY("local delegated property"),
|
LEGACY_STABLE_LOCAL_DELEGATED_PROPERTY("local delegated property"),
|
||||||
|
|
||||||
// Member value with open / custom getter
|
// Member value with open / custom getter
|
||||||
// Smart casts are not safe
|
// Smart casts are not safe
|
||||||
PROPERTY_WITH_GETTER("custom getter", "property that has open or custom getter"),
|
PROPERTY_WITH_GETTER("custom getter", "property that has open or custom getter"),
|
||||||
|
|
||||||
|
// Protected / public member value from derived class from another module
|
||||||
|
// Should be unstable, but can be used as stable with deprecation warning
|
||||||
|
LEGACY_ALIEN_BASE_PROPERTY("alien derived", "property declared in base class from different module"),
|
||||||
|
|
||||||
// Protected / public member value from another module
|
// Protected / public member value from another module
|
||||||
// Smart casts are not safe
|
// Smart casts are not safe
|
||||||
ALIEN_PUBLIC_PROPERTY("alien public", "public API property declared in different module"),
|
ALIEN_PUBLIC_PROPERTY("alien public", "public API property declared in different module"),
|
||||||
|
|
||||||
// Local variable not yet captured by a changing closure
|
// Local variable not yet captured by a changing closure
|
||||||
// Smart casts are safe but possible changes in loops / closures ahead must be taken into account
|
// Smart casts are safe but possible changes in loops / closures ahead must be taken into account
|
||||||
STABLE_VARIABLE("stable var", "local variable that can be changed since the check in a loop"),
|
STABLE_VARIABLE("stable var", "local variable that can be changed since the check in a loop"),
|
||||||
|
|
||||||
// Local variable already captured by a changing closure
|
// Local variable already captured by a changing closure
|
||||||
// Smart casts are not safe
|
// Smart casts are not safe
|
||||||
CAPTURED_VARIABLE("captured var", "local variable that is captured by a changing closure"),
|
CAPTURED_VARIABLE("captured var", "local variable that is captured by a changing closure"),
|
||||||
|
|
||||||
// Member variable regardless of its visibility
|
// Member variable regardless of its visibility
|
||||||
// Smart casts are not safe
|
// Smart casts are not safe
|
||||||
MUTABLE_PROPERTY("member", "mutable property that could have been changed by this time"),
|
MUTABLE_PROPERTY("member", "mutable property that could have been changed by this time"),
|
||||||
|
|
||||||
// Some complex expression
|
// Some complex expression
|
||||||
// Smart casts are not safe
|
// Smart casts are not safe
|
||||||
OTHER("other", "complex expression");
|
OTHER("other", "complex expression");
|
||||||
@@ -74,7 +86,8 @@ class DataFlowValue(
|
|||||||
val isStable = kind == Kind.STABLE_VALUE ||
|
val isStable = kind == Kind.STABLE_VALUE ||
|
||||||
kind == Kind.STABLE_VARIABLE ||
|
kind == Kind.STABLE_VARIABLE ||
|
||||||
kind == Kind.STABLE_COMPLEX_EXPRESSION ||
|
kind == Kind.STABLE_COMPLEX_EXPRESSION ||
|
||||||
kind == Kind.LEGACY_STABLE_LOCAL_DELEGATED_PROPERTY
|
kind == Kind.LEGACY_STABLE_LOCAL_DELEGATED_PROPERTY ||
|
||||||
|
kind == Kind.LEGACY_ALIEN_BASE_PROPERTY
|
||||||
|
|
||||||
val canBeBound get() = identifierInfo.canBeBound
|
val canBeBound get() = identifierInfo.canBeBound
|
||||||
|
|
||||||
|
|||||||
+25
-3
@@ -19,7 +19,10 @@ import org.jetbrains.kotlin.resolve.DescriptorUtils
|
|||||||
import org.jetbrains.kotlin.types.expressions.AssignedVariablesSearcher
|
import org.jetbrains.kotlin.types.expressions.AssignedVariablesSearcher
|
||||||
import org.jetbrains.kotlin.types.expressions.PreliminaryDeclarationVisitor
|
import org.jetbrains.kotlin.types.expressions.PreliminaryDeclarationVisitor
|
||||||
|
|
||||||
internal fun PropertyDescriptor.propertyKind(usageModule: ModuleDescriptor?): DataFlowValue.Kind {
|
internal fun PropertyDescriptor.propertyKind(
|
||||||
|
usageModule: ModuleDescriptor?,
|
||||||
|
languageVersionSettings: LanguageVersionSettings
|
||||||
|
): DataFlowValue.Kind {
|
||||||
if (isVar) return DataFlowValue.Kind.MUTABLE_PROPERTY
|
if (isVar) return DataFlowValue.Kind.MUTABLE_PROPERTY
|
||||||
if (isOverridable) return DataFlowValue.Kind.PROPERTY_WITH_GETTER
|
if (isOverridable) return DataFlowValue.Kind.PROPERTY_WITH_GETTER
|
||||||
if (!hasDefaultGetter()) return DataFlowValue.Kind.PROPERTY_WITH_GETTER
|
if (!hasDefaultGetter()) return DataFlowValue.Kind.PROPERTY_WITH_GETTER
|
||||||
@@ -28,11 +31,30 @@ internal fun PropertyDescriptor.propertyKind(usageModule: ModuleDescriptor?): Da
|
|||||||
if (!areCompiledTogether(usageModule, declarationModule)) {
|
if (!areCompiledTogether(usageModule, declarationModule)) {
|
||||||
return DataFlowValue.Kind.ALIEN_PUBLIC_PROPERTY
|
return DataFlowValue.Kind.ALIEN_PUBLIC_PROPERTY
|
||||||
}
|
}
|
||||||
|
if (kind == CallableMemberDescriptor.Kind.FAKE_OVERRIDE) {
|
||||||
|
if (overriddenDescriptors.any { isDeclaredInAnotherModule(usageModule) }) {
|
||||||
|
return if (!languageVersionSettings.supportsFeature(LanguageFeature.ProhibitSmartcastsOnPropertyFromAlienBaseClass)) {
|
||||||
|
DataFlowValue.Kind.LEGACY_ALIEN_BASE_PROPERTY
|
||||||
|
} else {
|
||||||
|
DataFlowValue.Kind.ALIEN_PUBLIC_PROPERTY
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return DataFlowValue.Kind.STABLE_VALUE
|
return DataFlowValue.Kind.STABLE_VALUE
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun areCompiledTogether(
|
private fun PropertyDescriptor.isDeclaredInAnotherModule(usageModule: ModuleDescriptor?): Boolean {
|
||||||
|
if (!areCompiledTogether(usageModule, DescriptorUtils.getContainingModule(this))) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if (kind == CallableMemberDescriptor.Kind.FAKE_OVERRIDE) {
|
||||||
|
return overriddenDescriptors.any { it.isDeclaredInAnotherModule(usageModule) }
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun areCompiledTogether(
|
||||||
usageModule: ModuleDescriptor?,
|
usageModule: ModuleDescriptor?,
|
||||||
declarationModule: ModuleDescriptor,
|
declarationModule: ModuleDescriptor,
|
||||||
): Boolean {
|
): Boolean {
|
||||||
@@ -49,7 +71,7 @@ internal fun VariableDescriptor.variableKind(
|
|||||||
languageVersionSettings: LanguageVersionSettings
|
languageVersionSettings: LanguageVersionSettings
|
||||||
): DataFlowValue.Kind {
|
): DataFlowValue.Kind {
|
||||||
if (this is PropertyDescriptor) {
|
if (this is PropertyDescriptor) {
|
||||||
return propertyKind(usageModule)
|
return propertyKind(usageModule, languageVersionSettings)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this is LocalVariableDescriptor && this.isDelegated) {
|
if (this is LocalVariableDescriptor && this.isDelegated) {
|
||||||
|
|||||||
+3
-1
@@ -226,7 +226,9 @@ class SmartCastManager(private val argumentTypeResolver: ArgumentTypeResolver) {
|
|||||||
) {
|
) {
|
||||||
if (KotlinBuiltIns.isNullableNothing(type)) return
|
if (KotlinBuiltIns.isNullableNothing(type)) return
|
||||||
if (dataFlowValue.isStable) {
|
if (dataFlowValue.isStable) {
|
||||||
if (dataFlowValue.kind == DataFlowValue.Kind.LEGACY_STABLE_LOCAL_DELEGATED_PROPERTY) {
|
if (dataFlowValue.kind == DataFlowValue.Kind.LEGACY_ALIEN_BASE_PROPERTY ||
|
||||||
|
dataFlowValue.kind == DataFlowValue.Kind.LEGACY_STABLE_LOCAL_DELEGATED_PROPERTY
|
||||||
|
) {
|
||||||
trace.report(Errors.DEPRECATED_SMARTCAST.on(expression, type, expression.text, dataFlowValue.kind.description))
|
trace.report(Errors.DEPRECATED_SMARTCAST.on(expression, type, expression.text, dataFlowValue.kind.description))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
@@ -1,3 +1,4 @@
|
|||||||
|
// !LANGUAGE: -ProhibitSmartcastsOnPropertyFromAlienBaseClass
|
||||||
// MODULE: m1
|
// MODULE: m1
|
||||||
// FILE: A.kt
|
// FILE: A.kt
|
||||||
|
|
||||||
|
|||||||
+3
-2
@@ -1,3 +1,4 @@
|
|||||||
|
// !LANGUAGE: -ProhibitSmartcastsOnPropertyFromAlienBaseClass
|
||||||
// MODULE: m1
|
// MODULE: m1
|
||||||
// FILE: A.kt
|
// FILE: A.kt
|
||||||
|
|
||||||
@@ -10,7 +11,7 @@ open class Generic<T>(val y: T)
|
|||||||
class Derived : Base("123") {
|
class Derived : Base("123") {
|
||||||
fun foo() {
|
fun foo() {
|
||||||
if (x is String) {
|
if (x is String) {
|
||||||
<!DEBUG_INFO_SMARTCAST!>x<!>.length // impossible since `x` is in another module. FE1.0 allows this due to KT-47225
|
<!DEBUG_INFO_SMARTCAST, DEPRECATED_SMARTCAST!>x<!>.length // impossible since `x` is in another module. FE1.0 allows this due to KT-47225
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -19,7 +20,7 @@ class MyGeneric : Generic<Number>(42) {
|
|||||||
private fun baz(arg: Int) {}
|
private fun baz(arg: Int) {}
|
||||||
fun bar() {
|
fun bar() {
|
||||||
if (y is Int) {
|
if (y is Int) {
|
||||||
baz(<!DEBUG_INFO_SMARTCAST!>y<!>) // impossible since `y` is in another module. FE1.0 allows this due to KT-47225
|
baz(<!DEBUG_INFO_SMARTCAST, DEPRECATED_SMARTCAST!>y<!>) // impossible since `y` is in another module. FE1.0 allows this due to KT-47225
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+27
@@ -0,0 +1,27 @@
|
|||||||
|
// FIR_IDENTICAL
|
||||||
|
// !LANGUAGE: +ProhibitSmartcastsOnPropertyFromAlienBaseClass
|
||||||
|
// MODULE: m1
|
||||||
|
// FILE: A.kt
|
||||||
|
|
||||||
|
open class Base(val x: Any)
|
||||||
|
open class Generic<T>(val y: T)
|
||||||
|
|
||||||
|
// MODULE: m2(m1)
|
||||||
|
// FILE: B.kt
|
||||||
|
|
||||||
|
class Derived : Base("123") {
|
||||||
|
fun foo() {
|
||||||
|
if (x is String) {
|
||||||
|
<!SMARTCAST_IMPOSSIBLE!>x<!>.length // impossible since `x` is in another module. FE1.0 allows this due to KT-47225
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class MyGeneric : Generic<Number>(42) {
|
||||||
|
private fun baz(arg: Int) {}
|
||||||
|
fun bar() {
|
||||||
|
if (y is Int) {
|
||||||
|
baz(<!SMARTCAST_IMPOSSIBLE!>y<!>) // impossible since `y` is in another module. FE1.0 allows this due to KT-47225
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+40
@@ -0,0 +1,40 @@
|
|||||||
|
// -- Module: <m1> --
|
||||||
|
package
|
||||||
|
|
||||||
|
public open class Base {
|
||||||
|
public constructor Base(/*0*/ x: kotlin.Any)
|
||||||
|
public final val x: kotlin.Any
|
||||||
|
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 open class Generic</*0*/ T> {
|
||||||
|
public constructor Generic</*0*/ T>(/*0*/ y: T)
|
||||||
|
public final val y: T
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
// -- Module: <m2> --
|
||||||
|
package
|
||||||
|
|
||||||
|
public final class Derived : Base {
|
||||||
|
public constructor Derived()
|
||||||
|
public final override /*1*/ /*fake_override*/ val x: kotlin.Any
|
||||||
|
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||||
|
public final fun foo(): kotlin.Unit
|
||||||
|
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||||
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class MyGeneric : Generic<kotlin.Number> {
|
||||||
|
public constructor MyGeneric()
|
||||||
|
public final override /*1*/ /*fake_override*/ val y: kotlin.Number
|
||||||
|
public final fun bar(): kotlin.Unit
|
||||||
|
private final fun baz(/*0*/ arg: kotlin.Int): kotlin.Unit
|
||||||
|
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
|
||||||
|
}
|
||||||
Generated
+6
@@ -28184,6 +28184,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest {
|
|||||||
runTest("compiler/testData/diagnostics/tests/smartCasts/publicVals/otherModuleInheritance.kt");
|
runTest("compiler/testData/diagnostics/tests/smartCasts/publicVals/otherModuleInheritance.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("otherModuleInheritance_after.kt")
|
||||||
|
public void testOtherModuleInheritance_after() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/tests/smartCasts/publicVals/otherModuleInheritance_after.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("protected.kt")
|
@TestMetadata("protected.kt")
|
||||||
public void testProtected() throws Exception {
|
public void testProtected() throws Exception {
|
||||||
|
|||||||
@@ -227,6 +227,7 @@ enum class LanguageFeature(
|
|||||||
OptInRelease(KOTLIN_1_7),
|
OptInRelease(KOTLIN_1_7),
|
||||||
ProhibitNonExhaustiveWhenOnAlgebraicTypes(KOTLIN_1_7, kind = BUG_FIX),
|
ProhibitNonExhaustiveWhenOnAlgebraicTypes(KOTLIN_1_7, kind = BUG_FIX),
|
||||||
UseBuilderInferenceWithoutAnnotation(KOTLIN_1_7),
|
UseBuilderInferenceWithoutAnnotation(KOTLIN_1_7),
|
||||||
|
ProhibitSmartcastsOnPropertyFromAlienBaseClass(KOTLIN_1_7, kind = BUG_FIX),
|
||||||
|
|
||||||
// Temporarily disabled, see KT-27084/KT-22379
|
// Temporarily disabled, see KT-27084/KT-22379
|
||||||
SoundSmartcastFromLoopConditionForLoopAssignedVariables(sinceVersion = null, kind = BUG_FIX),
|
SoundSmartcastFromLoopConditionForLoopAssignedVariables(sinceVersion = null, kind = BUG_FIX),
|
||||||
|
|||||||
+6
@@ -28094,6 +28094,12 @@ public class DiagnosisCompilerTestFE10TestdataTestGenerated extends AbstractDiag
|
|||||||
runTest("compiler/testData/diagnostics/tests/smartCasts/publicVals/otherModuleInheritance.kt");
|
runTest("compiler/testData/diagnostics/tests/smartCasts/publicVals/otherModuleInheritance.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("otherModuleInheritance_after.kt")
|
||||||
|
public void testOtherModuleInheritance_after() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/tests/smartCasts/publicVals/otherModuleInheritance_after.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("protected.kt")
|
@TestMetadata("protected.kt")
|
||||||
public void testProtected() throws Exception {
|
public void testProtected() throws Exception {
|
||||||
|
|||||||
Reference in New Issue
Block a user