From 5711a8d610083466738e9bf236202a3bad34aa2f Mon Sep 17 00:00:00 2001 From: Dmitriy Novozhilov Date: Thu, 11 Feb 2021 17:42:30 +0300 Subject: [PATCH] [FIR] Support PreliminaryLoopVisitor in FIR DFA --- .../FirBlackBoxCodegenTestGenerated.java | 6 ++ .../fir/resolve/dfa/FirDataFlowAnalyzer.kt | 36 +++++++- .../kotlin/fir/resolve/dfa/LogicSystem.kt | 1 + .../fir/resolve/dfa/PersistentLogicSystem.kt | 15 ++++ .../fir/resolve/dfa/PreliminaryLoopVisitor.kt | 87 +++++++++++++++++++ .../kotlin/fir/resolve/dfa/VariableStorage.kt | 11 ++- .../codegen/box/regressions/kt41806.kt | 3 +- .../codegen/box/smartCasts/kt44804.kt | 43 +++++++++ .../smartCasts/lambdaAndArgumentFun.fir.kt | 2 +- .../ownerDeclaresBothModifies.fir.kt | 4 +- .../variables/lambdaBetweenArguments.fir.kt | 2 +- .../variables/varChangedInLoop.fir.kt | 4 +- .../variables/varNotChangedInLoop.fir.kt | 4 +- .../variables/whileWithBreak.fir.kt | 4 +- .../varnotnull/assignNestedWhile.fir.kt | 4 +- .../capturedInClosureModifiedBefore.fir.kt | 8 +- .../varnotnull/doWhileWithBreak.fir.kt | 21 ----- .../smartCasts/varnotnull/doWhileWithBreak.kt | 1 + .../varnotnull/doWhileWithMiddleBreak.fir.kt | 12 --- .../varnotnull/doWhileWithMiddleBreak.kt | 1 + .../smartCasts/varnotnull/forEach.fir.kt | 6 +- .../varnotnull/infiniteWhileWithBreak.fir.kt | 4 +- .../varnotnull/varChangedInLoop.fir.kt | 4 +- .../varnotnull/varNotChangedInLoop.fir.kt | 4 +- .../varnotnull/whileWithBreak.fir.kt | 4 +- .../codegen/BlackBoxCodegenTestGenerated.java | 6 ++ .../IrBlackBoxCodegenTestGenerated.java | 6 ++ .../LightAnalysisModeTestGenerated.java | 5 ++ .../diagnostics/notLinked/dfa/pos/54.fir.kt | 24 ++--- .../diagnostics/notLinked/dfa/pos/59.fir.kt | 48 +++++----- .../IrJsCodegenBoxES6TestGenerated.java | 5 ++ .../IrJsCodegenBoxTestGenerated.java | 5 ++ .../semantics/JsCodegenBoxTestGenerated.java | 5 ++ .../IrCodegenBoxWasmTestGenerated.java | 5 ++ 34 files changed, 294 insertions(+), 106 deletions(-) create mode 100644 compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/PreliminaryLoopVisitor.kt create mode 100644 compiler/testData/codegen/box/smartCasts/kt44804.kt delete mode 100644 compiler/testData/diagnostics/tests/smartCasts/varnotnull/doWhileWithBreak.fir.kt delete mode 100644 compiler/testData/diagnostics/tests/smartCasts/varnotnull/doWhileWithMiddleBreak.fir.kt diff --git a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java index 31f405e06f1..944a693285d 100644 --- a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java +++ b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java @@ -37516,6 +37516,12 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT runTest("compiler/testData/codegen/box/smartCasts/kt42517.kt"); } + @Test + @TestMetadata("kt44804.kt") + public void testKt44804() throws Exception { + runTest("compiler/testData/codegen/box/smartCasts/kt44804.kt"); + } + @Test @TestMetadata("lambdaArgumentWithoutType.kt") public void testLambdaArgumentWithoutType() throws Exception { diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/FirDataFlowAnalyzer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/FirDataFlowAnalyzer.kt index 84b0db2b66d..260f375901e 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/FirDataFlowAnalyzer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/FirDataFlowAnalyzer.kt @@ -29,19 +29,20 @@ import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.resultType import org.jetbrains.kotlin.fir.symbols.AbstractFirBasedSymbol import org.jetbrains.kotlin.fir.symbols.CallableId import org.jetbrains.kotlin.fir.symbols.StandardClassIds +import org.jetbrains.kotlin.fir.symbols.impl.FirVariableSymbol import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.fir.visitors.transformSingle import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.types.ConstantValueKind import org.jetbrains.kotlin.utils.addIfNotNull -import org.jetbrains.kotlin.utils.addToStdlib.runIf class DataFlowAnalyzerContext( val graphBuilder: ControlFlowGraphBuilder, variableStorage: VariableStorage, flowOnNodes: MutableMap, FLOW>, - val variablesForWhenConditions: MutableMap + val variablesForWhenConditions: MutableMap, + val preliminaryLoopVisitor: PreliminaryLoopVisitor ) { var flowOnNodes = flowOnNodes private set @@ -54,13 +55,15 @@ class DataFlowAnalyzerContext( variableStorage = variableStorage.clear() flowOnNodes = mutableMapOf() + + preliminaryLoopVisitor.resetState() } companion object { - fun empty(session: FirSession) = + fun empty(session: FirSession): DataFlowAnalyzerContext = DataFlowAnalyzerContext( ControlFlowGraphBuilder(), VariableStorage(session), - mutableMapOf(), mutableMapOf() + mutableMapOf(), mutableMapOf(), PreliminaryLoopVisitor() ) } } @@ -210,12 +213,14 @@ abstract class FirDataFlowAnalyzer( // TODO: questionable postponedLambdaExitNode?.mergeIncomingFlow() functionExitNode.mergeIncomingFlow() + exitCapturingStatement(anonymousFunction) return FirControlFlowGraphReferenceImpl(graph) } fun visitPostponedAnonymousFunction(anonymousFunction: FirAnonymousFunction) { val (enterNode, exitNode) = graphBuilder.visitPostponedAnonymousFunction(anonymousFunction) enterNode.mergeIncomingFlow() + enterCapturingStatement(enterNode, anonymousFunction) exitNode.mergeIncomingFlow() enterNode.flow = enterNode.flow.fork() } @@ -236,12 +241,14 @@ abstract class FirDataFlowAnalyzer( } private fun exitLocalClass(klass: FirRegularClass): ControlFlowGraph { + // TODO: support capturing of mutable properties, KT-44877 val (node, controlFlowGraph) = graphBuilder.exitLocalClass(klass) node.mergeIncomingFlow() return controlFlowGraph } fun exitAnonymousObject(anonymousObject: FirAnonymousObject): ControlFlowGraph { + // TODO: support capturing of mutable properties, KT-44877 val (node, controlFlowGraph) = graphBuilder.exitAnonymousObject(anonymousObject) node.mergeIncomingFlow() return controlFlowGraph @@ -601,11 +608,13 @@ abstract class FirDataFlowAnalyzer( shouldRemoveSynthetics = true ) } + exitCapturingStatement(exitNode.fir) } fun enterWhileLoop(loop: FirLoop) { val (loopEnterNode, loopConditionEnterNode) = graphBuilder.enterWhileLoop(loop) loopEnterNode.mergeIncomingFlow() + enterCapturingStatement(loopEnterNode, loop) loopConditionEnterNode.mergeIncomingFlow() } @@ -630,11 +639,30 @@ abstract class FirDataFlowAnalyzer( exitCommonLoop(exitNode) } + private fun enterCapturingStatement(node: CFGNode<*>, statement: FirStatement) { + val reassignedNames = context.preliminaryLoopVisitor.enterCapturingStatement(statement) + if (reassignedNames.isEmpty()) return + val possiblyChangedVariables = variableStorage.realVariables.filterKeys { + val fir = (it.symbol as? FirVariableSymbol<*>)?.fir ?: return@filterKeys false + fir.isVar && fir.name in reassignedNames + }.values + if (possiblyChangedVariables.isEmpty()) return + val flow = node.flow + for (variable in possiblyChangedVariables) { + logicSystem.removeAllAboutVariableIncludingAliasInformation(flow, variable) + } + } + + private fun exitCapturingStatement(statement: FirStatement) { + context.preliminaryLoopVisitor.exitCapturingStatement(statement) + } + // ----------------------------------- Do while Loop ----------------------------------- fun enterDoWhileLoop(loop: FirLoop) { val (loopEnterNode, loopBlockEnterNode) = graphBuilder.enterDoWhileLoop(loop) loopEnterNode.mergeIncomingFlow() + enterCapturingStatement(loopEnterNode, loop) loopBlockEnterNode.mergeIncomingFlow() } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/LogicSystem.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/LogicSystem.kt index 6e11d2ed8cf..5b3b04c16a3 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/LogicSystem.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/LogicSystem.kt @@ -36,6 +36,7 @@ abstract class LogicSystem(protected val context: ConeInferenceCont abstract fun addImplication(flow: FLOW, implication: Implication) abstract fun removeAllAboutVariable(flow: FLOW, variable: RealVariable) + abstract fun removeAllAboutVariableIncludingAliasInformation(flow: FLOW, variable: RealVariable) abstract fun translateVariableFromConditionInStatements( flow: FLOW, diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/PersistentLogicSystem.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/PersistentLogicSystem.kt index 61aaa618a76..20ab32e00cb 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/PersistentLogicSystem.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/PersistentLogicSystem.kt @@ -254,6 +254,21 @@ abstract class PersistentLogicSystem(context: ConeInferenceContext) : LogicSyste // TODO: should we search variable in all logic statements? } + override fun removeAllAboutVariableIncludingAliasInformation(flow: PersistentFlow, variable: RealVariable) { + removeAllAboutVariable(flow, variable) + val existedAlias = flow.directAliasMap[variable]?.variable + if (existedAlias != null) { + flow.directAliasMap = flow.directAliasMap.remove(variable) + val updatedBackwardsAliasList = flow.backwardsAliasMap.getValue(existedAlias).remove(variable) + flow.backwardsAliasMap = if (updatedBackwardsAliasList.isEmpty()) { + flow.backwardsAliasMap.remove(existedAlias) + } else { + flow.backwardsAliasMap.put(existedAlias, updatedBackwardsAliasList) + } + flow.updatedAliasDiff = flow.updatedAliasDiff.add(variable) + } + } + override fun translateVariableFromConditionInStatements( flow: PersistentFlow, originalVariable: DataFlowVariable, diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/PreliminaryLoopVisitor.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/PreliminaryLoopVisitor.kt new file mode 100644 index 00000000000..f1384d2e6ce --- /dev/null +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/PreliminaryLoopVisitor.kt @@ -0,0 +1,87 @@ +/* + * Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.fir.resolve.dfa + +import org.jetbrains.kotlin.fir.FirElement +import org.jetbrains.kotlin.fir.declarations.* +import org.jetbrains.kotlin.fir.expressions.* +import org.jetbrains.kotlin.fir.references.FirNamedReference +import org.jetbrains.kotlin.fir.util.SetMultimap +import org.jetbrains.kotlin.fir.util.setMultimapOf +import org.jetbrains.kotlin.fir.visitors.FirVisitor +import org.jetbrains.kotlin.name.Name + +class PreliminaryLoopVisitor { + private val reassignedVariablesPerElement: SetMultimap = setMultimapOf() + + fun enterCapturingStatement(statement: FirStatement): Set { + assert(statement is FirLoop || statement is FirClass<*> || statement is FirFunction<*>) + if (statement !in reassignedVariablesPerElement) { + statement.accept(visitor, null) + } + return reassignedVariablesPerElement[statement] + } + + fun exitCapturingStatement(statement: FirStatement) { + assert(statement is FirLoop || statement is FirClass<*> || statement is FirFunction<*>) + reassignedVariablesPerElement.removeKey(statement) + } + + fun resetState() { + reassignedVariablesPerElement.clear() + } + + // FirStatement -- closest statement (loop/lambda/local declaration) which may contain reassignments + private val visitor = object : FirVisitor() { + override fun visitElement(element: FirElement, data: FirStatement?) { + element.acceptChildren(this, data) + } + + override fun visitVariableAssignment(variableAssignment: FirVariableAssignment, data: FirStatement?) { + val reference = variableAssignment.lValue as? FirNamedReference + if (reference != null) { + requireNotNull(data) + reassignedVariablesPerElement.put(data, reference.name) + } + visitElement(variableAssignment, data) + } + + override fun visitWhileLoop(whileLoop: FirWhileLoop, data: FirStatement?) { + visitCapturingStatement(whileLoop, data) + } + + override fun visitDoWhileLoop(doWhileLoop: FirDoWhileLoop, data: FirStatement?) { + visitCapturingStatement(doWhileLoop, data) + } + + override fun visitAnonymousFunction(anonymousFunction: FirAnonymousFunction, data: FirStatement?) { + visitCapturingStatement(anonymousFunction, data) + } + + override fun visitSimpleFunction(simpleFunction: FirSimpleFunction, data: FirStatement?) { + visitCapturingStatement(simpleFunction, data) + } + + override fun > visitFunction(function: FirFunction, data: FirStatement?) { + visitCapturingStatement(function, data) + } + + override fun visitRegularClass(regularClass: FirRegularClass, data: FirStatement?) { + visitCapturingStatement(regularClass, data) + } + + override fun visitAnonymousObject(anonymousObject: FirAnonymousObject, data: FirStatement?) { + visitCapturingStatement(anonymousObject, data) + } + + private fun visitCapturingStatement(statement: FirStatement, parent: FirStatement?) { + visitElement(statement, statement) + if (parent != null) { + reassignedVariablesPerElement.putAll(parent, reassignedVariablesPerElement[statement]) + } + } + } +} diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/VariableStorage.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/VariableStorage.kt index be162b7cc8a..1d33225ba4a 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/VariableStorage.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/VariableStorage.kt @@ -26,7 +26,10 @@ import kotlin.contracts.contract @OptIn(DfaInternals::class) class VariableStorage(private val session: FirSession) { private var counter = 1 - private val realVariables: MutableMap = HashMap() + private val _realVariables: MutableMap = HashMap() + val realVariables: Map + get() = _realVariables + private val syntheticVariables: MutableMap = HashMap() fun clear(): VariableStorage = VariableStorage(session) @@ -34,7 +37,7 @@ class VariableStorage(private val session: FirSession) { fun getOrCreateRealVariableWithoutUnwrappingAlias(flow: Flow, symbol: AbstractFirBasedSymbol<*>, fir: FirElement): RealVariable { val realFir = fir.unwrapElement() val identifier = getIdentifierBySymbol(flow, symbol, realFir) - return realVariables.getOrPut(identifier) { createRealVariableInternal(flow, identifier, realFir) } + return _realVariables.getOrPut(identifier) { createRealVariableInternal(flow, identifier, realFir) } } private fun getOrCreateRealVariable(flow: Flow, symbol: AbstractFirBasedSymbol<*>, fir: FirElement): RealVariable { @@ -108,7 +111,7 @@ class VariableStorage(private val session: FirSession) { fun getRealVariableWithoutUnwrappingAlias(symbol: AbstractFirBasedSymbol<*>?, fir: FirElement, flow: Flow): RealVariable? { val realFir = fir.unwrapElement() return symbol.takeIf { it.isStable(realFir) }?.let { - realVariables[getIdentifierBySymbol(flow, it, realFir.unwrapElement())] + _realVariables[getIdentifierBySymbol(flow, it, realFir.unwrapElement())] } } @@ -131,7 +134,7 @@ class VariableStorage(private val session: FirSession) { } fun removeRealVariable(symbol: AbstractFirBasedSymbol<*>) { - realVariables.remove(Identifier(symbol, null, null)) + _realVariables.remove(Identifier(symbol, null, null)) } fun removeSyntheticVariable(variable: DataFlowVariable) { diff --git a/compiler/testData/codegen/box/regressions/kt41806.kt b/compiler/testData/codegen/box/regressions/kt41806.kt index 5e3435df41b..cc28f1a25e1 100644 --- a/compiler/testData/codegen/box/regressions/kt41806.kt +++ b/compiler/testData/codegen/box/regressions/kt41806.kt @@ -1,6 +1,5 @@ // TARGET_BACKEND: JVM // WITH_RUNTIME -// IGNORE_BACKEND_FIR: JVM_IR open class A { fun Foo() { @@ -23,4 +22,4 @@ fun box(): String { test.Foo() return "OK" -} \ No newline at end of file +} diff --git a/compiler/testData/codegen/box/smartCasts/kt44804.kt b/compiler/testData/codegen/box/smartCasts/kt44804.kt new file mode 100644 index 00000000000..54d169ab7b9 --- /dev/null +++ b/compiler/testData/codegen/box/smartCasts/kt44804.kt @@ -0,0 +1,43 @@ +// ISSUE: KT-44804 +// WITH_STDLIB + +abstract class AbstractInsnNode(val next: AbstractInsnNode? = null) + +class LineNumberNode(next: AbstractInsnNode? = null) : AbstractInsnNode(next) { + val line: Int = 1 +} + +class LabelNode() : AbstractInsnNode(null) + +fun isDeadLineNumber(insn: LineNumberNode, index: Int, frames: Array): Boolean { + // Line number node is "dead" if the corresponding line number interval + // contains at least one "dead" meaningful instruction and no "live" meaningful instructions. + var finger: AbstractInsnNode = insn + var fingerIndex = index + var hasDeadInsn = false + loop@ while (true) { + finger = finger.next ?: break + fingerIndex++ + when (finger) { + is LabelNode -> + continue@loop + is LineNumberNode -> + if (finger.line != insn.line) return hasDeadInsn + else -> { + if (frames[fingerIndex] != null) return false + hasDeadInsn = true + } + } + } + return true +} + +fun box(): String { + val node = LineNumberNode( + LineNumberNode( + LabelNode() + ) + ) + val result = isDeadLineNumber(node, 0, arrayOf(null, null, "aaa", "bbb")) + return if (result) "OK" else "fail" +} diff --git a/compiler/testData/diagnostics/tests/smartCasts/lambdaAndArgumentFun.fir.kt b/compiler/testData/diagnostics/tests/smartCasts/lambdaAndArgumentFun.fir.kt index 393424290e4..49b404f34d6 100644 --- a/compiler/testData/diagnostics/tests/smartCasts/lambdaAndArgumentFun.fir.kt +++ b/compiler/testData/diagnostics/tests/smartCasts/lambdaAndArgumentFun.fir.kt @@ -10,5 +10,5 @@ fun use() { // Write to x is AFTER x.hashCode() // No smart cast should be here! - foo(bar { x = null }, x.hashCode()) + foo(bar { x = null }, x.hashCode()) } diff --git a/compiler/testData/diagnostics/tests/smartCasts/ownerDeclaresBothModifies.fir.kt b/compiler/testData/diagnostics/tests/smartCasts/ownerDeclaresBothModifies.fir.kt index a51ccd9e472..f9f45f3e355 100644 --- a/compiler/testData/diagnostics/tests/smartCasts/ownerDeclaresBothModifies.fir.kt +++ b/compiler/testData/diagnostics/tests/smartCasts/ownerDeclaresBothModifies.fir.kt @@ -4,10 +4,10 @@ fun foo(arg: Int?) { if (x == null) return run { // Unsafe because of owner modification - x.hashCode() + x.hashCode() x = null } if (x != null) x = 42 // Unsafe because of lambda x.hashCode() -} \ No newline at end of file +} diff --git a/compiler/testData/diagnostics/tests/smartCasts/variables/lambdaBetweenArguments.fir.kt b/compiler/testData/diagnostics/tests/smartCasts/variables/lambdaBetweenArguments.fir.kt index 1c423e36f0d..3d667d5f787 100644 --- a/compiler/testData/diagnostics/tests/smartCasts/variables/lambdaBetweenArguments.fir.kt +++ b/compiler/testData/diagnostics/tests/smartCasts/variables/lambdaBetweenArguments.fir.kt @@ -6,5 +6,5 @@ fun foo(x: Int, f: () -> Unit, y: Int) {} fun bar() { var x: Int? x = 4 - foo(x, { x = null; x.hashCode() }, x) + foo(x, { x = null; x.hashCode() }, x) } diff --git a/compiler/testData/diagnostics/tests/smartCasts/variables/varChangedInLoop.fir.kt b/compiler/testData/diagnostics/tests/smartCasts/variables/varChangedInLoop.fir.kt index 3146821521a..c9ac93066a6 100644 --- a/compiler/testData/diagnostics/tests/smartCasts/variables/varChangedInLoop.fir.kt +++ b/compiler/testData/diagnostics/tests/smartCasts/variables/varChangedInLoop.fir.kt @@ -2,8 +2,8 @@ public fun foo() { var i: Any = 1 if (i is Int) { while (i != 10) { - i++ // Here smart cast should not be performed due to a successor + i++ // Here smart cast should not be performed due to a successor i = "" } } -} \ No newline at end of file +} diff --git a/compiler/testData/diagnostics/tests/smartCasts/variables/varNotChangedInLoop.fir.kt b/compiler/testData/diagnostics/tests/smartCasts/variables/varNotChangedInLoop.fir.kt index 1a2eee01965..4c61f334a5c 100644 --- a/compiler/testData/diagnostics/tests/smartCasts/variables/varNotChangedInLoop.fir.kt +++ b/compiler/testData/diagnostics/tests/smartCasts/variables/varNotChangedInLoop.fir.kt @@ -2,7 +2,7 @@ public fun foo() { var i: Any = 1 if (i is Int) { while (i != 10) { - i++ + i++ } } -} \ No newline at end of file +} diff --git a/compiler/testData/diagnostics/tests/smartCasts/variables/whileWithBreak.fir.kt b/compiler/testData/diagnostics/tests/smartCasts/variables/whileWithBreak.fir.kt index b34bb73ed5e..05f04ba2fba 100644 --- a/compiler/testData/diagnostics/tests/smartCasts/variables/whileWithBreak.fir.kt +++ b/compiler/testData/diagnostics/tests/smartCasts/variables/whileWithBreak.fir.kt @@ -13,5 +13,5 @@ fun list(start: String) { e = e.next() } // e can never be null but we do not know it - e.hashCode() -} \ No newline at end of file + e.hashCode() +} diff --git a/compiler/testData/diagnostics/tests/smartCasts/varnotnull/assignNestedWhile.fir.kt b/compiler/testData/diagnostics/tests/smartCasts/varnotnull/assignNestedWhile.fir.kt index 58a8a768091..a1b3f87954b 100644 --- a/compiler/testData/diagnostics/tests/smartCasts/varnotnull/assignNestedWhile.fir.kt +++ b/compiler/testData/diagnostics/tests/smartCasts/varnotnull/assignNestedWhile.fir.kt @@ -13,7 +13,7 @@ fun foo(): Bar { y = Bar() while (x != null) { // Here call is unsafe because of inner loop - y.next() + y.next() while (y != null) { if (x == y) // x is not null because of outer while @@ -25,4 +25,4 @@ fun foo(): Bar { x = x.next() } return Bar() -} \ No newline at end of file +} diff --git a/compiler/testData/diagnostics/tests/smartCasts/varnotnull/capturedInClosureModifiedBefore.fir.kt b/compiler/testData/diagnostics/tests/smartCasts/varnotnull/capturedInClosureModifiedBefore.fir.kt index 5a017f5d5b1..3998cb0d6ed 100644 --- a/compiler/testData/diagnostics/tests/smartCasts/varnotnull/capturedInClosureModifiedBefore.fir.kt +++ b/compiler/testData/diagnostics/tests/smartCasts/varnotnull/capturedInClosureModifiedBefore.fir.kt @@ -30,7 +30,7 @@ fun baz(s: String?) { x.hashCode() } run { - x.hashCode() + x.hashCode() x = null } } @@ -40,11 +40,11 @@ fun gaz(s: String?) { var x = s if (x != null) { run { - x.hashCode() + x.hashCode() x = null } run { - x.hashCode() + x.hashCode() } } } @@ -57,4 +57,4 @@ fun gav(s: String?) { } x = null } -} \ No newline at end of file +} diff --git a/compiler/testData/diagnostics/tests/smartCasts/varnotnull/doWhileWithBreak.fir.kt b/compiler/testData/diagnostics/tests/smartCasts/varnotnull/doWhileWithBreak.fir.kt deleted file mode 100644 index 3b1b5feabe3..00000000000 --- a/compiler/testData/diagnostics/tests/smartCasts/varnotnull/doWhileWithBreak.fir.kt +++ /dev/null @@ -1,21 +0,0 @@ -data class SomeObject(val n: SomeObject?) { - fun doSomething(): Boolean = true - fun next(): SomeObject? = n -} - - -fun list(start: SomeObject) { - var e: SomeObject? - e = start - do { - // In theory smart cast is possible here - // But in practice we have a loop with changing e - // ?: should we "or" entrance type info with condition type info? - if (!e.doSomething()) - break - // Smart cast here is still not possible - e = e.next() - } while (e != null) - // e can be null because of next() - e.doSomething() -} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/smartCasts/varnotnull/doWhileWithBreak.kt b/compiler/testData/diagnostics/tests/smartCasts/varnotnull/doWhileWithBreak.kt index aab92ac48e5..78d39b82449 100644 --- a/compiler/testData/diagnostics/tests/smartCasts/varnotnull/doWhileWithBreak.kt +++ b/compiler/testData/diagnostics/tests/smartCasts/varnotnull/doWhileWithBreak.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL data class SomeObject(val n: SomeObject?) { fun doSomething(): Boolean = true fun next(): SomeObject? = n diff --git a/compiler/testData/diagnostics/tests/smartCasts/varnotnull/doWhileWithMiddleBreak.fir.kt b/compiler/testData/diagnostics/tests/smartCasts/varnotnull/doWhileWithMiddleBreak.fir.kt deleted file mode 100644 index 2b916f90fb0..00000000000 --- a/compiler/testData/diagnostics/tests/smartCasts/varnotnull/doWhileWithMiddleBreak.fir.kt +++ /dev/null @@ -1,12 +0,0 @@ -fun x(): Boolean { return true } - -public fun foo(pp: String?): Int { - var p = pp - do { - p!!.length - if (p == "abc") break - p = null - } while (!x()) - // Smart cast is NOT possible here - return p.length -} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/smartCasts/varnotnull/doWhileWithMiddleBreak.kt b/compiler/testData/diagnostics/tests/smartCasts/varnotnull/doWhileWithMiddleBreak.kt index acb36871a81..b569d40edcf 100644 --- a/compiler/testData/diagnostics/tests/smartCasts/varnotnull/doWhileWithMiddleBreak.kt +++ b/compiler/testData/diagnostics/tests/smartCasts/varnotnull/doWhileWithMiddleBreak.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL fun x(): Boolean { return true } public fun foo(pp: String?): Int { diff --git a/compiler/testData/diagnostics/tests/smartCasts/varnotnull/forEach.fir.kt b/compiler/testData/diagnostics/tests/smartCasts/varnotnull/forEach.fir.kt index fe84aec9785..db4f2975016 100644 --- a/compiler/testData/diagnostics/tests/smartCasts/varnotnull/forEach.fir.kt +++ b/compiler/testData/diagnostics/tests/smartCasts/varnotnull/forEach.fir.kt @@ -9,9 +9,9 @@ fun list(start: SomeObject): SomeObject { var e: SomeObject? = start for (i in 0..42) { // Unsafe calls because of nullable e at the beginning - e.doSomething() - e = e.next() + e.doSomething() + e = e.next() } // Smart cast is not possible here due to next() return e -} \ No newline at end of file +} diff --git a/compiler/testData/diagnostics/tests/smartCasts/varnotnull/infiniteWhileWithBreak.fir.kt b/compiler/testData/diagnostics/tests/smartCasts/varnotnull/infiniteWhileWithBreak.fir.kt index f13e2013809..40cda33aff1 100644 --- a/compiler/testData/diagnostics/tests/smartCasts/varnotnull/infiniteWhileWithBreak.fir.kt +++ b/compiler/testData/diagnostics/tests/smartCasts/varnotnull/infiniteWhileWithBreak.fir.kt @@ -16,5 +16,5 @@ fun list(start: SomeObject) { e = e.next() } // e can be null because of next() - e.doSomething() -} \ No newline at end of file + e.doSomething() +} diff --git a/compiler/testData/diagnostics/tests/smartCasts/varnotnull/varChangedInLoop.fir.kt b/compiler/testData/diagnostics/tests/smartCasts/varnotnull/varChangedInLoop.fir.kt index b0e56a1b8bc..80e56ac8127 100644 --- a/compiler/testData/diagnostics/tests/smartCasts/varnotnull/varChangedInLoop.fir.kt +++ b/compiler/testData/diagnostics/tests/smartCasts/varnotnull/varChangedInLoop.fir.kt @@ -2,8 +2,8 @@ public fun foo() { var i: Int? = 1 if (i != null) { while (i != 10) { - i++ // Here smart cast should not be performed due to a successor + i++ // Here smart cast should not be performed due to a successor i = null } } -} \ No newline at end of file +} diff --git a/compiler/testData/diagnostics/tests/smartCasts/varnotnull/varNotChangedInLoop.fir.kt b/compiler/testData/diagnostics/tests/smartCasts/varnotnull/varNotChangedInLoop.fir.kt index b36be19bf86..30698d4327c 100644 --- a/compiler/testData/diagnostics/tests/smartCasts/varnotnull/varNotChangedInLoop.fir.kt +++ b/compiler/testData/diagnostics/tests/smartCasts/varnotnull/varNotChangedInLoop.fir.kt @@ -2,7 +2,7 @@ public fun foo() { var i: Int? = 1 if (i != null) { while (i != 10) { - i++ + i++ } } -} \ No newline at end of file +} diff --git a/compiler/testData/diagnostics/tests/smartCasts/varnotnull/whileWithBreak.fir.kt b/compiler/testData/diagnostics/tests/smartCasts/varnotnull/whileWithBreak.fir.kt index 0d5e3c38d9f..47a0f063662 100644 --- a/compiler/testData/diagnostics/tests/smartCasts/varnotnull/whileWithBreak.fir.kt +++ b/compiler/testData/diagnostics/tests/smartCasts/varnotnull/whileWithBreak.fir.kt @@ -13,5 +13,5 @@ fun list(start: SomeObject) { e = e.next() } // e can be null because of next() - e.doSomething() -} \ No newline at end of file + e.doSomething() +} diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java index f9792f9344b..8c084859b75 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java @@ -37516,6 +37516,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { runTest("compiler/testData/codegen/box/smartCasts/kt42517.kt"); } + @Test + @TestMetadata("kt44804.kt") + public void testKt44804() throws Exception { + runTest("compiler/testData/codegen/box/smartCasts/kt44804.kt"); + } + @Test @TestMetadata("lambdaArgumentWithoutType.kt") public void testLambdaArgumentWithoutType() throws Exception { diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java index 1bcf3e61bc8..f2f1b23d1b9 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java @@ -37516,6 +37516,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes runTest("compiler/testData/codegen/box/smartCasts/kt42517.kt"); } + @Test + @TestMetadata("kt44804.kt") + public void testKt44804() throws Exception { + runTest("compiler/testData/codegen/box/smartCasts/kt44804.kt"); + } + @Test @TestMetadata("lambdaArgumentWithoutType.kt") public void testLambdaArgumentWithoutType() throws Exception { diff --git a/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index c11e3dbe4f7..9b5bc96fc69 100644 --- a/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -29984,6 +29984,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes runTest("compiler/testData/codegen/box/smartCasts/kt42517.kt"); } + @TestMetadata("kt44804.kt") + public void testKt44804() throws Exception { + runTest("compiler/testData/codegen/box/smartCasts/kt44804.kt"); + } + @TestMetadata("lambdaArgumentWithoutType.kt") public void testLambdaArgumentWithoutType() throws Exception { runTest("compiler/testData/codegen/box/smartCasts/lambdaArgumentWithoutType.kt"); diff --git a/compiler/tests-spec/testData/diagnostics/notLinked/dfa/pos/54.fir.kt b/compiler/tests-spec/testData/diagnostics/notLinked/dfa/pos/54.fir.kt index 4ee5892aa53..4523827f58f 100644 --- a/compiler/tests-spec/testData/diagnostics/notLinked/dfa/pos/54.fir.kt +++ b/compiler/tests-spec/testData/diagnostics/notLinked/dfa/pos/54.fir.kt @@ -19,8 +19,8 @@ fun case_1() { b.length } - b - b.length + b + b.length } } @@ -41,8 +41,8 @@ fun case_2() { b.length } - b - b.length + b + b.length } } @@ -107,8 +107,8 @@ fun case_5() { b.length } - b - b.length + b + b.length } } @@ -240,12 +240,12 @@ fun case_12() { b b.length while (if (true) { b = a; true } else true) { - b - b.length + b + b.length } - b - b.length + b + b.length } } @@ -276,8 +276,8 @@ fun case_14() { b.length while (true) { if (true) { b = a; } else 3 - b - b.length + b + b.length } } } diff --git a/compiler/tests-spec/testData/diagnostics/notLinked/dfa/pos/59.fir.kt b/compiler/tests-spec/testData/diagnostics/notLinked/dfa/pos/59.fir.kt index d33a0d0e271..794488afdde 100644 --- a/compiler/tests-spec/testData/diagnostics/notLinked/dfa/pos/59.fir.kt +++ b/compiler/tests-spec/testData/diagnostics/notLinked/dfa/pos/59.fir.kt @@ -11,8 +11,8 @@ fun case_1() { var x: Any? = null if (x == null) return do { - x - x = x.equals(10) + x + x = x.equals(10) } while (x != null) } @@ -25,8 +25,8 @@ fun case_2() { var x: Any? = null if (x === null) return do { - x - x = x.equals(10) + x + x = x.equals(10) } while (x !== null) } @@ -57,8 +57,8 @@ fun case_5() { var x: Any? = null if (x == null) return do { - x - x = x.equals(10) + x + x = x.equals(10) } while (x !== null) } @@ -71,8 +71,8 @@ fun case_6() { var x: Any? = null if (x === null) return do { - x - x = x.equals(10) + x + x = x.equals(10) } while (x != null) } @@ -85,8 +85,8 @@ fun case_7() { var x: Any? = null x ?: return do { - x - x = x.equals(10) + x + x = x.equals(10) } while (x !== null) } @@ -99,8 +99,8 @@ fun case_8() { var x: Any? = null if (x == null) throw Exception() do { - x - x = x.equals(10) + x + x = x.equals(10) } while (x != null) } @@ -113,8 +113,8 @@ fun case_9() { var x: Any? = null x ?: throw Exception() do { - x - x = x.equals(10) + x + x = x.equals(10) } while (x !== null) } @@ -127,8 +127,8 @@ fun case_10() { var x: Any? = null x as Any do { - x - x = x.equals(10) + x + x = x.equals(10) } while (x != null) } @@ -155,8 +155,8 @@ fun case_12() { var x: Any? = null if (x is Any) { do { - x - x = x .equals(10) + x + x = x .equals(10) } while (x != null) } } @@ -170,8 +170,8 @@ fun case_13() { var x: Any? = null if (x != null) { do { - x - x = x .equals(10) + x + x = x .equals(10) } while (x != null) } } @@ -185,8 +185,8 @@ fun case_14() { var x: Any? = null if (x == null) return do { - x - x = x.equals(10) + x + x = x.equals(10) } while (x is Any) } @@ -199,8 +199,8 @@ fun case_15() { var x: Any? = null if (x is Any) { do { - x - x = x .equals(10) + x + x = x .equals(10) } while (x is Any) } } diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/es6/semantics/IrJsCodegenBoxES6TestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/es6/semantics/IrJsCodegenBoxES6TestGenerated.java index 2b135ba7a92..02f3332bfe2 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/es6/semantics/IrJsCodegenBoxES6TestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/es6/semantics/IrJsCodegenBoxES6TestGenerated.java @@ -25530,6 +25530,11 @@ public class IrJsCodegenBoxES6TestGenerated extends AbstractIrJsCodegenBoxES6Tes runTest("compiler/testData/codegen/box/smartCasts/kt42517.kt"); } + @TestMetadata("kt44804.kt") + public void testKt44804() throws Exception { + runTest("compiler/testData/codegen/box/smartCasts/kt44804.kt"); + } + @TestMetadata("lambdaArgumentWithoutType.kt") public void testLambdaArgumentWithoutType() throws Exception { runTest("compiler/testData/codegen/box/smartCasts/lambdaArgumentWithoutType.kt"); diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java index 4eb495a5214..d9037c6bf6b 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java @@ -25015,6 +25015,11 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest { runTest("compiler/testData/codegen/box/smartCasts/kt42517.kt"); } + @TestMetadata("kt44804.kt") + public void testKt44804() throws Exception { + runTest("compiler/testData/codegen/box/smartCasts/kt44804.kt"); + } + @TestMetadata("lambdaArgumentWithoutType.kt") public void testLambdaArgumentWithoutType() throws Exception { runTest("compiler/testData/codegen/box/smartCasts/lambdaArgumentWithoutType.kt"); diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java index 58e05ec3fd8..9493d37b40d 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java @@ -24975,6 +24975,11 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { runTest("compiler/testData/codegen/box/smartCasts/kt42517.kt"); } + @TestMetadata("kt44804.kt") + public void testKt44804() throws Exception { + runTest("compiler/testData/codegen/box/smartCasts/kt44804.kt"); + } + @TestMetadata("lambdaArgumentWithoutType.kt") public void testLambdaArgumentWithoutType() throws Exception { runTest("compiler/testData/codegen/box/smartCasts/lambdaArgumentWithoutType.kt"); diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/wasm/semantics/IrCodegenBoxWasmTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/wasm/semantics/IrCodegenBoxWasmTestGenerated.java index bbbb9fe5456..7123c292b71 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/wasm/semantics/IrCodegenBoxWasmTestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/wasm/semantics/IrCodegenBoxWasmTestGenerated.java @@ -13597,6 +13597,11 @@ public class IrCodegenBoxWasmTestGenerated extends AbstractIrCodegenBoxWasmTest runTest("compiler/testData/codegen/box/smartCasts/kt19100.kt"); } + @TestMetadata("kt44804.kt") + public void testKt44804() throws Exception { + runTest("compiler/testData/codegen/box/smartCasts/kt44804.kt"); + } + @TestMetadata("multipleSmartCast.kt") public void testMultipleSmartCast() throws Exception { runTest("compiler/testData/codegen/box/smartCasts/multipleSmartCast.kt");