Fix unsound smartcast from loop condition on assigned vars
^KT-22379 Fixed
This commit is contained in:
committed by
Dmitry Savvinov
parent
a7d706f693
commit
447c127036
+14
-2
@@ -286,9 +286,16 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor {
|
|||||||
dataFlowInfo = dataFlowInfo.and(loopVisitor.clearDataFlowInfoForAssignedLocalVariables(bodyTypeInfo.getJumpFlowInfo(),
|
dataFlowInfo = dataFlowInfo.and(loopVisitor.clearDataFlowInfoForAssignedLocalVariables(bodyTypeInfo.getJumpFlowInfo(),
|
||||||
components.languageVersionSettings));
|
components.languageVersionSettings));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DataFlowInfo conservativeInfoAfterLoop =
|
||||||
|
components.languageVersionSettings.supportsFeature(LanguageFeature.SoundSmartcastFromLoopConditionForLoopAssignedVariables)
|
||||||
|
? loopVisitor.clearDataFlowInfoForAssignedLocalVariables(dataFlowInfo, components.languageVersionSettings)
|
||||||
|
: dataFlowInfo;
|
||||||
|
|
||||||
|
|
||||||
return components.dataFlowAnalyzer
|
return components.dataFlowAnalyzer
|
||||||
.checkType(bodyTypeInfo.replaceType(components.builtIns.getUnitType()), expression, contextWithExpectedType)
|
.checkType(bodyTypeInfo.replaceType(components.builtIns.getUnitType()), expression, contextWithExpectedType)
|
||||||
.replaceDataFlowInfo(dataFlowInfo);
|
.replaceDataFlowInfo(conservativeInfoAfterLoop);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean containsJumpOutOfLoop(@NotNull KtExpression expression, ExpressionTypingContext context) {
|
private boolean containsJumpOutOfLoop(@NotNull KtExpression expression, ExpressionTypingContext context) {
|
||||||
@@ -459,9 +466,14 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor {
|
|||||||
bodyTypeInfo = loopRangeInfo;
|
bodyTypeInfo = loopRangeInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DataFlowInfo conservativeInfoAfterLoop =
|
||||||
|
components.languageVersionSettings.supportsFeature(LanguageFeature.SoundSmartcastFromLoopConditionForLoopAssignedVariables)
|
||||||
|
? loopVisitor.clearDataFlowInfoForAssignedLocalVariables(loopRangeInfo.getDataFlowInfo(), components.languageVersionSettings)
|
||||||
|
: loopRangeInfo.getDataFlowInfo();
|
||||||
|
|
||||||
return components.dataFlowAnalyzer
|
return components.dataFlowAnalyzer
|
||||||
.checkType(bodyTypeInfo.replaceType(components.builtIns.getUnitType()), expression, contextWithExpectedType)
|
.checkType(bodyTypeInfo.replaceType(components.builtIns.getUnitType()), expression, contextWithExpectedType)
|
||||||
.replaceDataFlowInfo(loopRangeInfo.getDataFlowInfo());
|
.replaceDataFlowInfo(conservativeInfoAfterLoop);
|
||||||
}
|
}
|
||||||
|
|
||||||
private VariableDescriptor createLoopParameterDescriptor(
|
private VariableDescriptor createLoopParameterDescriptor(
|
||||||
|
|||||||
Vendored
+21
@@ -0,0 +1,21 @@
|
|||||||
|
// !LANGUAGE: +SoundSmartcastFromLoopConditionForLoopAssignedVariables
|
||||||
|
|
||||||
|
fun foo() {
|
||||||
|
var x: String? = "123"
|
||||||
|
while (x!!.length < 42) {
|
||||||
|
x = null
|
||||||
|
break
|
||||||
|
|
||||||
|
}
|
||||||
|
x<!UNSAFE_CALL!>.<!>length // 'x' is unsoundly smartcasted here
|
||||||
|
}
|
||||||
|
|
||||||
|
fun bar() {
|
||||||
|
var x: List<Int>? = ArrayList<Int>(1)
|
||||||
|
for (i in x!!) {
|
||||||
|
x = null
|
||||||
|
break
|
||||||
|
|
||||||
|
}
|
||||||
|
x<!UNSAFE_CALL!>.<!>size // 'x' is unsoundly smartcasted here
|
||||||
|
}
|
||||||
Vendored
+4
@@ -0,0 +1,4 @@
|
|||||||
|
package
|
||||||
|
|
||||||
|
public fun bar(): kotlin.Unit
|
||||||
|
public fun foo(): kotlin.Unit
|
||||||
Vendored
+21
@@ -0,0 +1,21 @@
|
|||||||
|
// !LANGUAGE: -SoundSmartcastFromLoopConditionForLoopAssignedVariables
|
||||||
|
|
||||||
|
fun foo() {
|
||||||
|
var x: String? = "123"
|
||||||
|
while (x!!.length < 42) {
|
||||||
|
x = null
|
||||||
|
break
|
||||||
|
|
||||||
|
}
|
||||||
|
<!DEBUG_INFO_SMARTCAST!>x<!>.length // 'x' is unsoundly smartcasted here
|
||||||
|
}
|
||||||
|
|
||||||
|
fun bar() {
|
||||||
|
var x: List<Int>? = ArrayList<Int>(1)
|
||||||
|
for (i in x!!) {
|
||||||
|
x = null
|
||||||
|
break
|
||||||
|
|
||||||
|
}
|
||||||
|
<!DEBUG_INFO_SMARTCAST!>x<!>.size // 'x' is unsoundly smartcasted here
|
||||||
|
}
|
||||||
Vendored
+4
@@ -0,0 +1,4 @@
|
|||||||
|
package
|
||||||
|
|
||||||
|
public fun bar(): kotlin.Unit
|
||||||
|
public fun foo(): kotlin.Unit
|
||||||
@@ -19822,6 +19822,16 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
|
|||||||
public void testWhileTrueWithBreakInIfCondition() throws Exception {
|
public void testWhileTrueWithBreakInIfCondition() throws Exception {
|
||||||
runTest("compiler/testData/diagnostics/tests/smartCasts/loops/WhileTrueWithBreakInIfCondition.kt");
|
runTest("compiler/testData/diagnostics/tests/smartCasts/loops/WhileTrueWithBreakInIfCondition.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("whileWithAssertInConditionAndBreakAfter.kt")
|
||||||
|
public void testWhileWithAssertInConditionAndBreakAfter() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/tests/smartCasts/loops/whileWithAssertInConditionAndBreakAfter.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("whileWithAssertInConditionAndBreakBefore.kt")
|
||||||
|
public void testWhileWithAssertInConditionAndBreakBefore() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/tests/smartCasts/loops/whileWithAssertInConditionAndBreakBefore.kt");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("compiler/testData/diagnostics/tests/smartCasts/objectLiterals")
|
@TestMetadata("compiler/testData/diagnostics/tests/smartCasts/objectLiterals")
|
||||||
|
|||||||
Generated
+10
@@ -19822,6 +19822,16 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing
|
|||||||
public void testWhileTrueWithBreakInIfCondition() throws Exception {
|
public void testWhileTrueWithBreakInIfCondition() throws Exception {
|
||||||
runTest("compiler/testData/diagnostics/tests/smartCasts/loops/WhileTrueWithBreakInIfCondition.kt");
|
runTest("compiler/testData/diagnostics/tests/smartCasts/loops/WhileTrueWithBreakInIfCondition.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("whileWithAssertInConditionAndBreakAfter.kt")
|
||||||
|
public void testWhileWithAssertInConditionAndBreakAfter() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/tests/smartCasts/loops/whileWithAssertInConditionAndBreakAfter.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("whileWithAssertInConditionAndBreakBefore.kt")
|
||||||
|
public void testWhileWithAssertInConditionAndBreakBefore() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/tests/smartCasts/loops/whileWithAssertInConditionAndBreakBefore.kt");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("compiler/testData/diagnostics/tests/smartCasts/objectLiterals")
|
@TestMetadata("compiler/testData/diagnostics/tests/smartCasts/objectLiterals")
|
||||||
|
|||||||
@@ -85,6 +85,7 @@ enum class LanguageFeature(
|
|||||||
NormalizeConstructorCalls(KOTLIN_1_3),
|
NormalizeConstructorCalls(KOTLIN_1_3),
|
||||||
StrictJavaNullabilityAssertions(KOTLIN_1_3, kind = BUG_FIX),
|
StrictJavaNullabilityAssertions(KOTLIN_1_3, kind = BUG_FIX),
|
||||||
SoundSmartcastForEnumEntries(KOTLIN_1_3, kind = BUG_FIX),
|
SoundSmartcastForEnumEntries(KOTLIN_1_3, kind = BUG_FIX),
|
||||||
|
SoundSmartcastFromLoopConditionForLoopAssignedVariables(KOTLIN_1_3, kind = BUG_FIX),
|
||||||
|
|
||||||
RestrictReturnStatementTarget(KOTLIN_1_4, kind = BUG_FIX),
|
RestrictReturnStatementTarget(KOTLIN_1_4, kind = BUG_FIX),
|
||||||
ProperIeee754Comparisons(sinceVersion = null, defaultState = State.DISABLED, kind = BUG_FIX),
|
ProperIeee754Comparisons(sinceVersion = null, defaultState = State.DISABLED, kind = BUG_FIX),
|
||||||
|
|||||||
Reference in New Issue
Block a user