[FIR] Fix clearing info about DF variable after reassignment
This commit is contained in:
+5
@@ -3141,6 +3141,11 @@ public class LazyBodyIsNotTouchedTilContractsPhaseTestGenerated extends Abstract
|
|||||||
runTest("compiler/fir/analysis-tests/testData/resolve/smartcasts/safeCalls/boundSafeCallAndIsCheck.kt");
|
runTest("compiler/fir/analysis-tests/testData/resolve/smartcasts/safeCalls/boundSafeCallAndIsCheck.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("complexIfWithOr.kt")
|
||||||
|
public void testComplexIfWithOr() throws Exception {
|
||||||
|
runTest("compiler/fir/analysis-tests/testData/resolve/smartcasts/safeCalls/complexIfWithOr.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("safeCallAndEqualityToBool.kt")
|
@TestMetadata("safeCallAndEqualityToBool.kt")
|
||||||
public void testSafeCallAndEqualityToBool() throws Exception {
|
public void testSafeCallAndEqualityToBool() throws Exception {
|
||||||
runTest("compiler/fir/analysis-tests/testData/resolve/smartcasts/safeCalls/safeCallAndEqualityToBool.kt");
|
runTest("compiler/fir/analysis-tests/testData/resolve/smartcasts/safeCalls/safeCallAndEqualityToBool.kt");
|
||||||
|
|||||||
+19
@@ -0,0 +1,19 @@
|
|||||||
|
FILE: complexIfWithOr.kt
|
||||||
|
public abstract interface State : R|kotlin/Any| {
|
||||||
|
}
|
||||||
|
public abstract interface Complex : R|kotlin/Any| {
|
||||||
|
public abstract val superClass: R|Complex?|
|
||||||
|
public get(): R|Complex?|
|
||||||
|
|
||||||
|
}
|
||||||
|
public abstract interface ExceptionState : R|State| {
|
||||||
|
}
|
||||||
|
public final fun test(qualifier: R|State?|): R|kotlin/Unit| {
|
||||||
|
when () {
|
||||||
|
==(R|<local>/qualifier|, Null(null)) || (R|<local>/qualifier| is R|ExceptionState|) || ==((R|<local>/qualifier| as? R|Complex|)?.{ $subj$.R|/Complex.superClass| }, Null(null)) -> {
|
||||||
|
^test Unit
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
R|<local>/qualifier|.R|/Complex.superClass|
|
||||||
|
}
|
||||||
+13
@@ -0,0 +1,13 @@
|
|||||||
|
interface State
|
||||||
|
interface Complex {
|
||||||
|
val superClass: Complex?
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ExceptionState : State
|
||||||
|
|
||||||
|
fun test(qualifier: State?) {
|
||||||
|
if (qualifier == null || qualifier is ExceptionState || (qualifier as? Complex)?.superClass == null) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
qualifier.superClass
|
||||||
|
}
|
||||||
+6
@@ -3520,6 +3520,12 @@ public class FirDiagnosticTestGenerated extends AbstractFirDiagnosticTest {
|
|||||||
runTest("compiler/fir/analysis-tests/testData/resolve/smartcasts/safeCalls/boundSafeCallAndIsCheck.kt");
|
runTest("compiler/fir/analysis-tests/testData/resolve/smartcasts/safeCalls/boundSafeCallAndIsCheck.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("complexIfWithOr.kt")
|
||||||
|
public void testComplexIfWithOr() throws Exception {
|
||||||
|
runTest("compiler/fir/analysis-tests/testData/resolve/smartcasts/safeCalls/complexIfWithOr.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("safeCallAndEqualityToBool.kt")
|
@TestMetadata("safeCallAndEqualityToBool.kt")
|
||||||
public void testSafeCallAndEqualityToBool() throws Exception {
|
public void testSafeCallAndEqualityToBool() throws Exception {
|
||||||
|
|||||||
+6
@@ -3566,6 +3566,12 @@ public class FirDiagnosticsWithLightTreeTestGenerated extends AbstractFirDiagnos
|
|||||||
runTest("compiler/fir/analysis-tests/testData/resolve/smartcasts/safeCalls/boundSafeCallAndIsCheck.kt");
|
runTest("compiler/fir/analysis-tests/testData/resolve/smartcasts/safeCalls/boundSafeCallAndIsCheck.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("complexIfWithOr.kt")
|
||||||
|
public void testComplexIfWithOr() throws Exception {
|
||||||
|
runTest("compiler/fir/analysis-tests/testData/resolve/smartcasts/safeCalls/complexIfWithOr.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("safeCallAndEqualityToBool.kt")
|
@TestMetadata("safeCallAndEqualityToBool.kt")
|
||||||
public void testSafeCallAndEqualityToBool() throws Exception {
|
public void testSafeCallAndEqualityToBool() throws Exception {
|
||||||
|
|||||||
+6
@@ -14946,6 +14946,12 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
|
|||||||
runTest("compiler/testData/codegen/box/fir/FakeOverrideBuilder.kt");
|
runTest("compiler/testData/codegen/box/fir/FakeOverrideBuilder.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("falsePositiveBoundSmartcast.kt")
|
||||||
|
public void testFalsePositiveBoundSmartcast() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/fir/falsePositiveBoundSmartcast.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("Fir2IrClassifierStorage.kt")
|
@TestMetadata("Fir2IrClassifierStorage.kt")
|
||||||
public void testFir2IrClassifierStorage() throws Exception {
|
public void testFir2IrClassifierStorage() throws Exception {
|
||||||
|
|||||||
+11
-3
@@ -49,6 +49,12 @@ class DataFlowAnalyzerContext<FLOW : Flow>(
|
|||||||
var variableStorage = variableStorage
|
var variableStorage = variableStorage
|
||||||
private set
|
private set
|
||||||
|
|
||||||
|
private var assignmentCounter = 0
|
||||||
|
|
||||||
|
fun newAssignmentIndex(): Int {
|
||||||
|
return assignmentCounter++
|
||||||
|
}
|
||||||
|
|
||||||
fun reset() {
|
fun reset() {
|
||||||
graphBuilder.reset()
|
graphBuilder.reset()
|
||||||
variablesForWhenConditions.clear()
|
variablesForWhenConditions.clear()
|
||||||
@@ -84,7 +90,6 @@ abstract class FirDataFlowAnalyzer<FLOW : Flow>(
|
|||||||
private val receiverStack: PersistentImplicitReceiverStack
|
private val receiverStack: PersistentImplicitReceiverStack
|
||||||
get() = components.implicitReceiverStack as PersistentImplicitReceiverStack
|
get() = components.implicitReceiverStack as PersistentImplicitReceiverStack
|
||||||
|
|
||||||
private val symbolProvider = components.session.symbolProvider
|
|
||||||
private val visibilityChecker = components.session.visibilityChecker
|
private val visibilityChecker = components.session.visibilityChecker
|
||||||
|
|
||||||
override val logicSystem: PersistentLogicSystem =
|
override val logicSystem: PersistentLogicSystem =
|
||||||
@@ -673,7 +678,7 @@ abstract class FirDataFlowAnalyzer<FLOW : Flow>(
|
|||||||
if (possiblyChangedVariables.isEmpty()) return
|
if (possiblyChangedVariables.isEmpty()) return
|
||||||
val flow = node.flow
|
val flow = node.flow
|
||||||
for (variable in possiblyChangedVariables) {
|
for (variable in possiblyChangedVariables) {
|
||||||
logicSystem.removeAllAboutVariableIncludingAliasInformation(flow, variable)
|
flow.removeAllAboutVariable(variable)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -946,6 +951,7 @@ abstract class FirDataFlowAnalyzer<FLOW : Flow>(
|
|||||||
if (isAssignment) {
|
if (isAssignment) {
|
||||||
logicSystem.removeLocalVariableAlias(flow, propertyVariable)
|
logicSystem.removeLocalVariableAlias(flow, propertyVariable)
|
||||||
flow.removeAllAboutVariable(propertyVariable)
|
flow.removeAllAboutVariable(propertyVariable)
|
||||||
|
logicSystem.recordNewAssignment(flow, propertyVariable, context.newAssignmentIndex())
|
||||||
}
|
}
|
||||||
|
|
||||||
variableStorage.getOrCreateRealVariable(flow, initializer.symbol, initializer)?.let { initializerVariable ->
|
variableStorage.getOrCreateRealVariable(flow, initializer.symbol, initializer)?.let { initializerVariable ->
|
||||||
@@ -1256,7 +1262,9 @@ abstract class FirDataFlowAnalyzer<FLOW : Flow>(
|
|||||||
|
|
||||||
private fun FLOW.removeAllAboutVariable(variable: RealVariable?) {
|
private fun FLOW.removeAllAboutVariable(variable: RealVariable?) {
|
||||||
if (variable == null) return
|
if (variable == null) return
|
||||||
logicSystem.removeAllAboutVariable(this, variable)
|
logicSystem.removeTypeStatementsAboutVariable(this, variable)
|
||||||
|
logicSystem.removeLogicStatementsAboutVariable(this, variable)
|
||||||
|
logicSystem.removeAliasInformationAboutVariable(this, variable)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun FLOW.fork(): FLOW {
|
private fun FLOW.fork(): FLOW {
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ abstract class Flow {
|
|||||||
|
|
||||||
abstract val directAliasMap: Map<RealVariable, RealVariableAndType>
|
abstract val directAliasMap: Map<RealVariable, RealVariableAndType>
|
||||||
abstract val backwardsAliasMap: Map<RealVariable, List<RealVariable>>
|
abstract val backwardsAliasMap: Map<RealVariable, List<RealVariable>>
|
||||||
|
abstract val assignmentIndex: Map<RealVariable, Int>
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Flow.unwrapVariable(variable: RealVariable): RealVariable {
|
fun Flow.unwrapVariable(variable: RealVariable): RealVariable {
|
||||||
@@ -36,8 +37,9 @@ abstract class LogicSystem<FLOW : Flow>(protected val context: ConeInferenceCont
|
|||||||
|
|
||||||
abstract fun addImplication(flow: FLOW, implication: Implication)
|
abstract fun addImplication(flow: FLOW, implication: Implication)
|
||||||
|
|
||||||
abstract fun removeAllAboutVariable(flow: FLOW, variable: RealVariable)
|
abstract fun removeTypeStatementsAboutVariable(flow: FLOW, variable: RealVariable)
|
||||||
abstract fun removeAllAboutVariableIncludingAliasInformation(flow: FLOW, variable: RealVariable)
|
abstract fun removeLogicStatementsAboutVariable(flow: FLOW, variable: DataFlowVariable)
|
||||||
|
abstract fun removeAliasInformationAboutVariable(flow: FLOW, variable: RealVariable)
|
||||||
|
|
||||||
abstract fun translateVariableFromConditionInStatements(
|
abstract fun translateVariableFromConditionInStatements(
|
||||||
flow: FLOW,
|
flow: FLOW,
|
||||||
@@ -58,6 +60,8 @@ abstract class LogicSystem<FLOW : Flow>(protected val context: ConeInferenceCont
|
|||||||
abstract fun addLocalVariableAlias(flow: FLOW, alias: RealVariable, underlyingVariable: RealVariableAndType)
|
abstract fun addLocalVariableAlias(flow: FLOW, alias: RealVariable, underlyingVariable: RealVariableAndType)
|
||||||
abstract fun removeLocalVariableAlias(flow: FLOW, alias: RealVariable)
|
abstract fun removeLocalVariableAlias(flow: FLOW, alias: RealVariable)
|
||||||
|
|
||||||
|
abstract fun recordNewAssignment(flow: FLOW, variable: RealVariable, index: Int)
|
||||||
|
|
||||||
protected abstract fun getImplicationsWithVariable(flow: FLOW, variable: DataFlowVariable): Collection<Implication>
|
protected abstract fun getImplicationsWithVariable(flow: FLOW, variable: DataFlowVariable): Collection<Implication>
|
||||||
|
|
||||||
protected abstract fun ConeKotlinType.isAcceptableForSmartcast(): Boolean
|
protected abstract fun ConeKotlinType.isAcceptableForSmartcast(): Boolean
|
||||||
|
|||||||
+46
-7
@@ -11,7 +11,6 @@ import org.jetbrains.kotlin.fir.types.ConeInferenceContext
|
|||||||
import org.jetbrains.kotlin.fir.types.ConeKotlinType
|
import org.jetbrains.kotlin.fir.types.ConeKotlinType
|
||||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import kotlin.NoSuchElementException
|
|
||||||
|
|
||||||
data class PersistentTypeStatement(
|
data class PersistentTypeStatement(
|
||||||
override val variable: RealVariable,
|
override val variable: RealVariable,
|
||||||
@@ -55,6 +54,8 @@ class PersistentFlow : Flow {
|
|||||||
override var directAliasMap: PersistentMap<RealVariable, RealVariableAndType>
|
override var directAliasMap: PersistentMap<RealVariable, RealVariableAndType>
|
||||||
override var backwardsAliasMap: PersistentMap<RealVariable, PersistentList<RealVariable>>
|
override var backwardsAliasMap: PersistentMap<RealVariable, PersistentList<RealVariable>>
|
||||||
|
|
||||||
|
override var assignmentIndex: PersistentMap<RealVariable, Int>
|
||||||
|
|
||||||
constructor(previousFlow: PersistentFlow) {
|
constructor(previousFlow: PersistentFlow) {
|
||||||
this.previousFlow = previousFlow
|
this.previousFlow = previousFlow
|
||||||
approvedTypeStatements = previousFlow.approvedTypeStatements
|
approvedTypeStatements = previousFlow.approvedTypeStatements
|
||||||
@@ -63,6 +64,7 @@ class PersistentFlow : Flow {
|
|||||||
|
|
||||||
directAliasMap = previousFlow.directAliasMap
|
directAliasMap = previousFlow.directAliasMap
|
||||||
backwardsAliasMap = previousFlow.backwardsAliasMap
|
backwardsAliasMap = previousFlow.backwardsAliasMap
|
||||||
|
assignmentIndex = previousFlow.assignmentIndex
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
@@ -73,6 +75,7 @@ class PersistentFlow : Flow {
|
|||||||
|
|
||||||
directAliasMap = persistentMapOf()
|
directAliasMap = persistentMapOf()
|
||||||
backwardsAliasMap = persistentMapOf()
|
backwardsAliasMap = persistentMapOf()
|
||||||
|
assignmentIndex = persistentMapOf()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getTypeStatement(variable: RealVariable): TypeStatement? {
|
override fun getTypeStatement(variable: RealVariable): TypeStatement? {
|
||||||
@@ -133,7 +136,12 @@ abstract class PersistentLogicSystem(context: ConeInferenceContext) : LogicSyste
|
|||||||
val variables = flows.flatMap { it.approvedTypeStatements.keys }.toSet()
|
val variables = flows.flatMap { it.approvedTypeStatements.keys }.toSet()
|
||||||
for (variable in variables) {
|
for (variable in variables) {
|
||||||
val info = mergeOperation(flows.map { it.getApprovedTypeStatements(variable, commonFlow) }) ?: continue
|
val info = mergeOperation(flows.map { it.getApprovedTypeStatements(variable, commonFlow) }) ?: continue
|
||||||
removeAllAboutVariable(commonFlow, variable)
|
removeTypeStatementsAboutVariable(commonFlow, variable)
|
||||||
|
val thereWereReassignments = variable.hasDifferentReassignments(flows)
|
||||||
|
if (thereWereReassignments) {
|
||||||
|
removeLogicStatementsAboutVariable(commonFlow, variable)
|
||||||
|
removeAliasInformationAboutVariable(commonFlow, variable)
|
||||||
|
}
|
||||||
commonFlow.addApprovedStatements(info)
|
commonFlow.addApprovedStatements(info)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -141,6 +149,15 @@ abstract class PersistentLogicSystem(context: ConeInferenceContext) : LogicSyste
|
|||||||
return commonFlow
|
return commonFlow
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun RealVariable.hasDifferentReassignments(flows: Collection<PersistentFlow>): Boolean {
|
||||||
|
val firstIndex = flows.first().assignmentIndex[this] ?: -1
|
||||||
|
for (flow in flows) {
|
||||||
|
val index = flow.assignmentIndex[this] ?: -1
|
||||||
|
if (index != firstIndex) return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
private fun computeAliasesThatDontChange(
|
private fun computeAliasesThatDontChange(
|
||||||
flows: Collection<PersistentFlow>
|
flows: Collection<PersistentFlow>
|
||||||
): MutableMap<RealVariable, RealVariableAndType> {
|
): MutableMap<RealVariable, RealVariableAndType> {
|
||||||
@@ -247,15 +264,33 @@ abstract class PersistentLogicSystem(context: ConeInferenceContext) : LogicSyste
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun removeAllAboutVariable(flow: PersistentFlow, variable: RealVariable) {
|
override fun removeTypeStatementsAboutVariable(flow: PersistentFlow, variable: RealVariable) {
|
||||||
flow.logicStatements -= variable
|
|
||||||
flow.approvedTypeStatements -= variable
|
flow.approvedTypeStatements -= variable
|
||||||
flow.approvedTypeStatementsDiff -= variable
|
flow.approvedTypeStatementsDiff -= variable
|
||||||
// TODO: should we search variable in all logic statements?
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun removeAllAboutVariableIncludingAliasInformation(flow: PersistentFlow, variable: RealVariable) {
|
override fun removeLogicStatementsAboutVariable(flow: PersistentFlow, variable: DataFlowVariable) {
|
||||||
removeAllAboutVariable(flow, variable)
|
flow.logicStatements -= variable
|
||||||
|
var newLogicStatements = flow.logicStatements
|
||||||
|
for ((key, implications) in flow.logicStatements) {
|
||||||
|
val implicationsToDelete = mutableListOf<Implication>()
|
||||||
|
implications.forEach { implication ->
|
||||||
|
if (implication.effect.variable == variable) {
|
||||||
|
implicationsToDelete += implication
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (implicationsToDelete.isEmpty()) continue
|
||||||
|
val newImplications = implications.removeAll(implicationsToDelete)
|
||||||
|
newLogicStatements = if (newImplications.isNotEmpty()) {
|
||||||
|
newLogicStatements.put(key, newImplications)
|
||||||
|
} else {
|
||||||
|
newLogicStatements.remove(key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
flow.logicStatements = newLogicStatements
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun removeAliasInformationAboutVariable(flow: PersistentFlow, variable: RealVariable) {
|
||||||
val existedAlias = flow.directAliasMap[variable]?.variable
|
val existedAlias = flow.directAliasMap[variable]?.variable
|
||||||
if (existedAlias != null) {
|
if (existedAlias != null) {
|
||||||
flow.directAliasMap = flow.directAliasMap.remove(variable)
|
flow.directAliasMap = flow.directAliasMap.remove(variable)
|
||||||
@@ -408,6 +443,10 @@ abstract class PersistentLogicSystem(context: ConeInferenceContext) : LogicSyste
|
|||||||
return flow.logicStatements[variable] ?: emptyList()
|
return flow.logicStatements[variable] ?: emptyList()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun recordNewAssignment(flow: PersistentFlow, variable: RealVariable, index: Int) {
|
||||||
|
flow.assignmentIndex = flow.assignmentIndex.put(variable, index)
|
||||||
|
}
|
||||||
|
|
||||||
// --------------------------------------------------------------------\
|
// --------------------------------------------------------------------\
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -128,6 +128,7 @@ private infix fun FirElement.isEqualsTo(other: FirElement): Boolean {
|
|||||||
|
|
||||||
sealed class Statement<T : Statement<T>> {
|
sealed class Statement<T : Statement<T>> {
|
||||||
abstract fun invert(): T
|
abstract fun invert(): T
|
||||||
|
abstract val variable: DataFlowVariable
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -137,7 +138,7 @@ sealed class Statement<T : Statement<T>> {
|
|||||||
* d == True
|
* d == True
|
||||||
* d == False
|
* d == False
|
||||||
*/
|
*/
|
||||||
data class OperationStatement(val variable: DataFlowVariable, val operation: Operation) : Statement<OperationStatement>() {
|
data class OperationStatement(override val variable: DataFlowVariable, val operation: Operation) : Statement<OperationStatement>() {
|
||||||
override fun invert(): OperationStatement {
|
override fun invert(): OperationStatement {
|
||||||
return OperationStatement(variable, operation.invert())
|
return OperationStatement(variable, operation.invert())
|
||||||
}
|
}
|
||||||
@@ -148,7 +149,7 @@ data class OperationStatement(val variable: DataFlowVariable, val operation: Ope
|
|||||||
}
|
}
|
||||||
|
|
||||||
abstract class TypeStatement : Statement<TypeStatement>() {
|
abstract class TypeStatement : Statement<TypeStatement>() {
|
||||||
abstract val variable: RealVariable
|
abstract override val variable: RealVariable
|
||||||
abstract val exactType: Set<ConeKotlinType>
|
abstract val exactType: Set<ConeKotlinType>
|
||||||
abstract val exactNotType: Set<ConeKotlinType>
|
abstract val exactNotType: Set<ConeKotlinType>
|
||||||
|
|
||||||
@@ -209,6 +210,8 @@ fun Implication.invertCondition(): Implication = Implication(condition.invert(),
|
|||||||
typealias TypeStatements = Map<RealVariable, TypeStatement>
|
typealias TypeStatements = Map<RealVariable, TypeStatement>
|
||||||
typealias MutableTypeStatements = MutableMap<RealVariable, MutableTypeStatement>
|
typealias MutableTypeStatements = MutableMap<RealVariable, MutableTypeStatement>
|
||||||
|
|
||||||
|
typealias MutableOperationStatements = MutableMap<RealVariable, MutableTypeStatement>
|
||||||
|
|
||||||
fun MutableTypeStatements.addStatement(variable: RealVariable, statement: TypeStatement) {
|
fun MutableTypeStatements.addStatement(variable: RealVariable, statement: TypeStatement) {
|
||||||
put(variable, statement.asMutableStatement()) { it.apply { this += statement } }
|
put(variable, statement.asMutableStatement()) { it.apply { this += statement } }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
abstract class A {
|
||||||
|
abstract fun foo(): String
|
||||||
|
}
|
||||||
|
|
||||||
|
class B : A() {
|
||||||
|
override fun foo() = "OK"
|
||||||
|
}
|
||||||
|
|
||||||
|
class C : A() {
|
||||||
|
override fun foo() = "fail"
|
||||||
|
}
|
||||||
|
|
||||||
|
fun test(c: C, cond: Boolean): String {
|
||||||
|
var x: A = c
|
||||||
|
if (cond) {
|
||||||
|
x = B()
|
||||||
|
}
|
||||||
|
return x.foo()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun box(): String = test(C(), true)
|
||||||
-1
@@ -1,4 +1,3 @@
|
|||||||
// IGNORE_BACKEND_FIR: JVM_IR
|
|
||||||
// FILE: 1.kt
|
// FILE: 1.kt
|
||||||
|
|
||||||
package test
|
package test
|
||||||
|
|||||||
+6
@@ -14946,6 +14946,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
|||||||
runTest("compiler/testData/codegen/box/fir/FakeOverrideBuilder.kt");
|
runTest("compiler/testData/codegen/box/fir/FakeOverrideBuilder.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("falsePositiveBoundSmartcast.kt")
|
||||||
|
public void testFalsePositiveBoundSmartcast() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/fir/falsePositiveBoundSmartcast.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("Fir2IrClassifierStorage.kt")
|
@TestMetadata("Fir2IrClassifierStorage.kt")
|
||||||
public void testFir2IrClassifierStorage() throws Exception {
|
public void testFir2IrClassifierStorage() throws Exception {
|
||||||
|
|||||||
+6
@@ -14946,6 +14946,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
|||||||
runTest("compiler/testData/codegen/box/fir/FakeOverrideBuilder.kt");
|
runTest("compiler/testData/codegen/box/fir/FakeOverrideBuilder.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("falsePositiveBoundSmartcast.kt")
|
||||||
|
public void testFalsePositiveBoundSmartcast() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/fir/falsePositiveBoundSmartcast.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("Fir2IrClassifierStorage.kt")
|
@TestMetadata("Fir2IrClassifierStorage.kt")
|
||||||
public void testFir2IrClassifierStorage() throws Exception {
|
public void testFir2IrClassifierStorage() throws Exception {
|
||||||
|
|||||||
+5
@@ -12338,6 +12338,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
|||||||
runTest("compiler/testData/codegen/box/fir/FakeOverrideBuilder.kt");
|
runTest("compiler/testData/codegen/box/fir/FakeOverrideBuilder.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("falsePositiveBoundSmartcast.kt")
|
||||||
|
public void testFalsePositiveBoundSmartcast() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/fir/falsePositiveBoundSmartcast.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("Fir2IrClassifierStorage.kt")
|
@TestMetadata("Fir2IrClassifierStorage.kt")
|
||||||
public void testFir2IrClassifierStorage() throws Exception {
|
public void testFir2IrClassifierStorage() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/fir/Fir2IrClassifierStorage.kt");
|
runTest("compiler/testData/codegen/box/fir/Fir2IrClassifierStorage.kt");
|
||||||
|
|||||||
js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/es6/semantics/IrJsCodegenBoxES6TestGenerated.java
Generated
+5
@@ -10945,6 +10945,11 @@ public class IrJsCodegenBoxES6TestGenerated extends AbstractIrJsCodegenBoxES6Tes
|
|||||||
public void testClassCanNotBeCastedToVoid() throws Exception {
|
public void testClassCanNotBeCastedToVoid() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/fir/classCanNotBeCastedToVoid.kt");
|
runTest("compiler/testData/codegen/box/fir/classCanNotBeCastedToVoid.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("falsePositiveBoundSmartcast.kt")
|
||||||
|
public void testFalsePositiveBoundSmartcast() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/fir/falsePositiveBoundSmartcast.kt");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("compiler/testData/codegen/box/fullJdk")
|
@TestMetadata("compiler/testData/codegen/box/fullJdk")
|
||||||
|
|||||||
Generated
+5
@@ -10402,6 +10402,11 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest {
|
|||||||
public void testClassCanNotBeCastedToVoid() throws Exception {
|
public void testClassCanNotBeCastedToVoid() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/fir/classCanNotBeCastedToVoid.kt");
|
runTest("compiler/testData/codegen/box/fir/classCanNotBeCastedToVoid.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("falsePositiveBoundSmartcast.kt")
|
||||||
|
public void testFalsePositiveBoundSmartcast() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/fir/falsePositiveBoundSmartcast.kt");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("compiler/testData/codegen/box/fullJdk")
|
@TestMetadata("compiler/testData/codegen/box/fullJdk")
|
||||||
|
|||||||
Generated
+5
@@ -10402,6 +10402,11 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
|
|||||||
public void testClassCanNotBeCastedToVoid() throws Exception {
|
public void testClassCanNotBeCastedToVoid() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/fir/classCanNotBeCastedToVoid.kt");
|
runTest("compiler/testData/codegen/box/fir/classCanNotBeCastedToVoid.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("falsePositiveBoundSmartcast.kt")
|
||||||
|
public void testFalsePositiveBoundSmartcast() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/fir/falsePositiveBoundSmartcast.kt");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("compiler/testData/codegen/box/fullJdk")
|
@TestMetadata("compiler/testData/codegen/box/fullJdk")
|
||||||
|
|||||||
js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/wasm/semantics/IrCodegenBoxWasmTestGenerated.java
Generated
+5
@@ -5233,6 +5233,11 @@ public class IrCodegenBoxWasmTestGenerated extends AbstractIrCodegenBoxWasmTest
|
|||||||
public void testClassCanNotBeCastedToVoid() throws Exception {
|
public void testClassCanNotBeCastedToVoid() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/fir/classCanNotBeCastedToVoid.kt");
|
runTest("compiler/testData/codegen/box/fir/classCanNotBeCastedToVoid.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("falsePositiveBoundSmartcast.kt")
|
||||||
|
public void testFalsePositiveBoundSmartcast() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/fir/falsePositiveBoundSmartcast.kt");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("compiler/testData/codegen/box/fullJdk")
|
@TestMetadata("compiler/testData/codegen/box/fullJdk")
|
||||||
|
|||||||
Reference in New Issue
Block a user