[FIR] Support PreliminaryLoopVisitor in FIR DFA

This commit is contained in:
Dmitriy Novozhilov
2021-02-11 17:42:30 +03:00
parent 0e46a961a3
commit 5711a8d610
34 changed files with 294 additions and 106 deletions
@@ -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 {
@@ -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<FLOW : Flow>(
val graphBuilder: ControlFlowGraphBuilder,
variableStorage: VariableStorage,
flowOnNodes: MutableMap<CFGNode<*>, FLOW>,
val variablesForWhenConditions: MutableMap<WhenBranchConditionExitNode, DataFlowVariable>
val variablesForWhenConditions: MutableMap<WhenBranchConditionExitNode, DataFlowVariable>,
val preliminaryLoopVisitor: PreliminaryLoopVisitor
) {
var flowOnNodes = flowOnNodes
private set
@@ -54,13 +55,15 @@ class DataFlowAnalyzerContext<FLOW : Flow>(
variableStorage = variableStorage.clear()
flowOnNodes = mutableMapOf()
preliminaryLoopVisitor.resetState()
}
companion object {
fun <FLOW : Flow> empty(session: FirSession) =
fun <FLOW : Flow> empty(session: FirSession): DataFlowAnalyzerContext<FLOW> =
DataFlowAnalyzerContext<FLOW>(
ControlFlowGraphBuilder(), VariableStorage(session),
mutableMapOf(), mutableMapOf()
mutableMapOf(), mutableMapOf(), PreliminaryLoopVisitor()
)
}
}
@@ -210,12 +213,14 @@ abstract class FirDataFlowAnalyzer<FLOW : Flow>(
// 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<FLOW : Flow>(
}
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<FLOW : Flow>(
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<FLOW : Flow>(
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()
}
@@ -36,6 +36,7 @@ abstract class LogicSystem<FLOW : Flow>(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,
@@ -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,
@@ -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<FirStatement, Name> = setMultimapOf()
fun enterCapturingStatement(statement: FirStatement): Set<Name> {
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<Unit, FirStatement?>() {
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 <F : FirFunction<F>> visitFunction(function: FirFunction<F>, 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])
}
}
}
}
@@ -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<Identifier, RealVariable> = HashMap()
private val _realVariables: MutableMap<Identifier, RealVariable> = HashMap()
val realVariables: Map<Identifier, RealVariable>
get() = _realVariables
private val syntheticVariables: MutableMap<FirElement, SyntheticVariable> = 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) {
+1 -2
View File
@@ -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"
}
}
+43
View File
@@ -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<out Any?>): 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"
}
@@ -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<!UNSAFE_CALL!>.<!>hashCode())
}
@@ -4,10 +4,10 @@ fun foo(arg: Int?) {
if (x == null) return
run {
// Unsafe because of owner modification
x.hashCode()
x<!UNSAFE_CALL!>.<!>hashCode()
x = null
}
if (x != null) x = 42
// Unsafe because of lambda
x<!UNSAFE_CALL!>.<!>hashCode()
}
}
@@ -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)
<!INAPPLICABLE_CANDIDATE!>foo<!>(x, { x = null; x<!UNSAFE_CALL!>.<!>hashCode() }, x)
}
@@ -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<!UNRESOLVED_REFERENCE!>++<!> // Here smart cast should not be performed due to a successor
i = ""
}
}
}
}
@@ -2,7 +2,7 @@ public fun foo() {
var i: Any = 1
if (i is Int) {
while (i != 10) {
i++
i<!UNRESOLVED_REFERENCE!>++<!>
}
}
}
}
@@ -13,5 +13,5 @@ fun list(start: String) {
e = e.next()
}
// e can never be null but we do not know it
e.hashCode()
}
e<!UNSAFE_CALL!>.<!>hashCode()
}
@@ -13,7 +13,7 @@ fun foo(): Bar {
y = Bar()
while (x != null) {
// Here call is unsafe because of inner loop
y.next()
y<!UNSAFE_CALL!>.<!>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()
}
}
@@ -30,7 +30,7 @@ fun baz(s: String?) {
x.hashCode()
}
run {
x.hashCode()
x<!UNSAFE_CALL!>.<!>hashCode()
x = null
}
}
@@ -40,11 +40,11 @@ fun gaz(s: String?) {
var x = s
if (x != null) {
run {
x.hashCode()
x<!UNSAFE_CALL!>.<!>hashCode()
x = null
}
run {
x.hashCode()
x<!UNSAFE_CALL!>.<!>hashCode()
}
}
}
@@ -57,4 +57,4 @@ fun gav(s: String?) {
}
x = 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()
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
data class SomeObject(val n: SomeObject?) {
fun doSomething(): Boolean = true
fun next(): SomeObject? = n
@@ -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
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
fun x(): Boolean { return true }
public fun foo(pp: String?): Int {
@@ -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<!UNSAFE_CALL!>.<!>doSomething()
e = e<!UNSAFE_CALL!>.<!>next()
}
// Smart cast is not possible here due to next()
return e
}
}
@@ -16,5 +16,5 @@ fun list(start: SomeObject) {
e = e.next()
}
// e can be null because of next()
e.doSomething()
}
e<!UNSAFE_CALL!>.<!>doSomething()
}
@@ -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<!UNSAFE_CALL!>++<!> // Here smart cast should not be performed due to a successor
i = null
}
}
}
}
@@ -2,7 +2,7 @@ public fun foo() {
var i: Int? = 1
if (i != null) {
while (i != 10) {
i++
i<!UNSAFE_CALL!>++<!>
}
}
}
}
@@ -13,5 +13,5 @@ fun list(start: SomeObject) {
e = e.next()
}
// e can be null because of next()
e.doSomething()
}
e<!UNSAFE_CALL!>.<!>doSomething()
}
@@ -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 {
@@ -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 {
@@ -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");
@@ -19,8 +19,8 @@ fun case_1() {
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.String & kotlin.String")!>b<!>.length
}
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.String & kotlin.String")!>b<!>
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.String & kotlin.String")!>b<!>.length
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.String")!>b<!>
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.String")!>b<!>.length
}
}
@@ -41,8 +41,8 @@ fun case_2() {
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.String & kotlin.String")!>b<!>.length
}
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.String & kotlin.String")!>b<!>
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.String & kotlin.String")!>b<!>.length
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.String")!>b<!>
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.String")!>b<!>.length
}
}
@@ -107,8 +107,8 @@ fun case_5() {
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.String & kotlin.String")!>b<!>.length
}
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.String & kotlin.String")!>b<!>
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.String & kotlin.String")!>b<!>.length
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.String")!>b<!>
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.String")!>b<!>.length
}
}
@@ -240,12 +240,12 @@ fun case_12() {
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.String & kotlin.String")!>b<!>
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.String & kotlin.String")!>b<!>.length
while (if (true) { b = a; true } else true) {
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.String & kotlin.String")!>b<!>
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.String & kotlin.String")!>b<!>.length
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.String")!>b<!>
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.String")!>b<!>.length
}
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.String & kotlin.String")!>b<!>
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.String & kotlin.String")!>b<!>.length
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.String")!>b<!>
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.String")!>b<!>.length
}
}
@@ -276,8 +276,8 @@ fun case_14() {
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.String & kotlin.String")!>b<!>.length
while (true) {
if (true) { b = a; } else 3
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.String & kotlin.String")!>b<!>
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.String & kotlin.String")!>b<!>.length
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.String")!>b<!>
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.String")!>b<!>.length
}
}
}
@@ -11,8 +11,8 @@ fun case_1() {
var x: Any? = null
if (x == null) return
do {
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Any & kotlin.Any?")!>x<!>
x = x.equals(10)
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Any?")!>x<!>
x = x<!UNSAFE_CALL!>.<!>equals(10)
} while (x != null)
}
@@ -25,8 +25,8 @@ fun case_2() {
var x: Any? = null
if (x === null) return
do {
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Any & kotlin.Any?")!>x<!>
x = x.equals(10)
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Any?")!>x<!>
x = x<!UNSAFE_CALL!>.<!>equals(10)
} while (x !== null)
}
@@ -57,8 +57,8 @@ fun case_5() {
var x: Any? = null
if (x == null) return
do {
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Any & kotlin.Any?")!>x<!>
x = x.equals(10)
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Any?")!>x<!>
x = x<!UNSAFE_CALL!>.<!>equals(10)
} while (x !== null)
}
@@ -71,8 +71,8 @@ fun case_6() {
var x: Any? = null
if (x === null) return
do {
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Any & kotlin.Any?")!>x<!>
x = x.equals(10)
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Any?")!>x<!>
x = x<!UNSAFE_CALL!>.<!>equals(10)
} while (x != null)
}
@@ -85,8 +85,8 @@ fun case_7() {
var x: Any? = null
x ?: return
do {
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Any & kotlin.Any?")!>x<!>
x = x.equals(10)
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Any?")!>x<!>
x = x<!UNSAFE_CALL!>.<!>equals(10)
} while (x !== null)
}
@@ -99,8 +99,8 @@ fun case_8() {
var x: Any? = null
if (x == null) throw Exception()
do {
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Any & kotlin.Any?")!>x<!>
x = x.equals(10)
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Any?")!>x<!>
x = x<!UNSAFE_CALL!>.<!>equals(10)
} while (x != null)
}
@@ -113,8 +113,8 @@ fun case_9() {
var x: Any? = null
x ?: throw Exception()
do {
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Any & kotlin.Any?")!>x<!>
x = x.equals(10)
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Any?")!>x<!>
x = x<!UNSAFE_CALL!>.<!>equals(10)
} while (x !== null)
}
@@ -127,8 +127,8 @@ fun case_10() {
var x: Any? = null
x as Any
do {
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Any & kotlin.Any?")!>x<!>
x = x.equals(10)
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Any?")!>x<!>
x = x<!UNSAFE_CALL!>.<!>equals(10)
} while (x != null)
}
@@ -155,8 +155,8 @@ fun case_12() {
var x: Any? = null
if (x is Any) {
do {
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Any & kotlin.Any?")!>x<!>
x = x .equals(10)
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Any?")!>x<!>
x = x <!UNSAFE_CALL!>.<!>equals(10)
} while (x != null)
}
}
@@ -170,8 +170,8 @@ fun case_13() {
var x: Any? = null
if (x != null) {
do {
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Any & kotlin.Any?")!>x<!>
x = x .equals(10)
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Any?")!>x<!>
x = x <!UNSAFE_CALL!>.<!>equals(10)
} while (x != null)
}
}
@@ -185,8 +185,8 @@ fun case_14() {
var x: Any? = null
if (x == null) return
do {
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Any & kotlin.Any?")!>x<!>
x = x.equals(10)
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Any?")!>x<!>
x = x<!UNSAFE_CALL!>.<!>equals(10)
} while (x is Any)
}
@@ -199,8 +199,8 @@ fun case_15() {
var x: Any? = null
if (x is Any) {
do {
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Any & kotlin.Any?")!>x<!>
x = x .equals(10)
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Any?")!>x<!>
x = x <!UNSAFE_CALL!>.<!>equals(10)
} while (x is Any)
}
}
@@ -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");
@@ -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");
@@ -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");
@@ -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");