FIR DFA: remove RealVariableAndType
This commit is contained in:
+26
-20
@@ -1286,32 +1286,35 @@ digraph boundSmartcastsInBranches_kt {
|
|||||||
506 [label="Exit when branch result"];
|
506 [label="Exit when branch result"];
|
||||||
507 [label="Exit when"];
|
507 [label="Exit when"];
|
||||||
}
|
}
|
||||||
|
508 [label="Access variable R|<local>/b|"];
|
||||||
|
509 [label="Access variable <Inapplicable(UNSAFE_CALL): kotlin/String.length>#"];
|
||||||
subgraph cluster_97 {
|
subgraph cluster_97 {
|
||||||
color=blue
|
color=blue
|
||||||
508 [label="Enter when"];
|
510 [label="Enter when"];
|
||||||
subgraph cluster_98 {
|
subgraph cluster_98 {
|
||||||
color=blue
|
color=blue
|
||||||
509 [label="Enter when branch condition "];
|
511 [label="Enter when branch condition "];
|
||||||
510 [label="Access variable R|<local>/a|"];
|
512 [label="Access variable R|<local>/a|"];
|
||||||
511 [label="Const: Null(null)"];
|
513 [label="Const: Null(null)"];
|
||||||
512 [label="Equality operator !="];
|
514 [label="Equality operator !="];
|
||||||
513 [label="Exit when branch condition"];
|
515 [label="Exit when branch condition"];
|
||||||
}
|
}
|
||||||
514 [label="Synthetic else branch"];
|
516 [label="Synthetic else branch"];
|
||||||
515 [label="Enter when branch result"];
|
517 [label="Enter when branch result"];
|
||||||
subgraph cluster_99 {
|
subgraph cluster_99 {
|
||||||
color=blue
|
color=blue
|
||||||
516 [label="Enter block"];
|
518 [label="Enter block"];
|
||||||
517 [label="Access variable R|<local>/b|"];
|
519 [label="Access variable R|<local>/b|"];
|
||||||
518 [label="Access variable <Inapplicable(UNSAFE_CALL): kotlin/String.length>#"];
|
520 [label="Smart cast: R|<local>/b|"];
|
||||||
519 [label="Exit block"];
|
521 [label="Access variable R|kotlin/String.length|"];
|
||||||
|
522 [label="Exit block"];
|
||||||
}
|
}
|
||||||
520 [label="Exit when branch result"];
|
523 [label="Exit when branch result"];
|
||||||
521 [label="Exit when"];
|
524 [label="Exit when"];
|
||||||
}
|
}
|
||||||
522 [label="Exit block"];
|
525 [label="Exit block"];
|
||||||
}
|
}
|
||||||
523 [label="Exit function test_9" style="filled" fillcolor=red];
|
526 [label="Exit function test_9" style="filled" fillcolor=red];
|
||||||
}
|
}
|
||||||
480 -> {481};
|
480 -> {481};
|
||||||
481 -> {482};
|
481 -> {482};
|
||||||
@@ -1346,15 +1349,18 @@ digraph boundSmartcastsInBranches_kt {
|
|||||||
510 -> {511};
|
510 -> {511};
|
||||||
511 -> {512};
|
511 -> {512};
|
||||||
512 -> {513};
|
512 -> {513};
|
||||||
513 -> {515 514};
|
513 -> {514};
|
||||||
514 -> {521};
|
514 -> {515};
|
||||||
515 -> {516};
|
515 -> {517 516};
|
||||||
516 -> {517};
|
516 -> {524};
|
||||||
517 -> {518};
|
517 -> {518};
|
||||||
518 -> {519};
|
518 -> {519};
|
||||||
519 -> {520};
|
519 -> {520};
|
||||||
520 -> {521};
|
520 -> {521};
|
||||||
521 -> {522};
|
521 -> {522};
|
||||||
522 -> {523};
|
522 -> {523};
|
||||||
|
523 -> {524};
|
||||||
|
524 -> {525};
|
||||||
|
525 -> {526};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-1
@@ -223,9 +223,10 @@ FILE: boundSmartcastsInBranches.kt
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
R|<local>/b|.<Inapplicable(UNSAFE_CALL): kotlin/String.length>#
|
||||||
when () {
|
when () {
|
||||||
!=(R|<local>/a|, Null(null)) -> {
|
!=(R|<local>/a|, Null(null)) -> {
|
||||||
R|<local>/b|.<Inapplicable(UNSAFE_CALL): kotlin/String.length>#
|
R|<local>/b|.R|kotlin/String.length|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
compiler/fir/analysis-tests/testData/resolve/smartcasts/boundSmartcasts/boundSmartcastsInBranches.kt
Vendored
+2
-1
@@ -170,7 +170,8 @@ fun test_9() {
|
|||||||
} else {
|
} else {
|
||||||
b = a
|
b = a
|
||||||
}
|
}
|
||||||
|
b<!UNSAFE_CALL!>.<!>length // bad
|
||||||
if (a != null) {
|
if (a != null) {
|
||||||
b<!UNSAFE_CALL!>.<!>length // ok
|
b.length // ok
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+9
-23
@@ -39,7 +39,6 @@ import org.jetbrains.kotlin.fir.visitors.transformSingle
|
|||||||
import org.jetbrains.kotlin.name.StandardClassIds
|
import org.jetbrains.kotlin.name.StandardClassIds
|
||||||
import org.jetbrains.kotlin.types.ConstantValueKind
|
import org.jetbrains.kotlin.types.ConstantValueKind
|
||||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
|
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
|
||||||
|
|
||||||
class DataFlowAnalyzerContext<FLOW : Flow>(
|
class DataFlowAnalyzerContext<FLOW : Flow>(
|
||||||
@@ -104,15 +103,13 @@ abstract class FirDataFlowAnalyzer<FLOW : Flow>(
|
|||||||
val symbol = variable.identifier.symbol
|
val symbol = variable.identifier.symbol
|
||||||
|
|
||||||
val index = receiverStack.getReceiverIndex(symbol) ?: return
|
val index = receiverStack.getReceiverIndex(symbol) ?: return
|
||||||
val info = flow.getTypeStatement(variable)
|
val info = flow.getType(variable)
|
||||||
|
val type = if (info.isNotEmpty()) {
|
||||||
val type = if (info == null) {
|
val types = info.toMutableList()
|
||||||
receiverStack.getOriginalType(index)
|
types += receiverStack.getOriginalType(index)
|
||||||
} else {
|
|
||||||
val types = info.exactType.toMutableList().also {
|
|
||||||
it += receiverStack.getOriginalType(index)
|
|
||||||
}
|
|
||||||
context.intersectTypesOrNull(types)!!
|
context.intersectTypesOrNull(types)!!
|
||||||
|
} else {
|
||||||
|
receiverStack.getOriginalType(index)
|
||||||
}
|
}
|
||||||
receiverStack.replaceReceiverType(index, type)
|
receiverStack.replaceReceiverType(index, type)
|
||||||
}
|
}
|
||||||
@@ -200,15 +197,8 @@ abstract class FirDataFlowAnalyzer<FLOW : Flow>(
|
|||||||
expression: FirExpression
|
expression: FirExpression
|
||||||
): Pair<PropertyStability, MutableList<ConeKotlinType>>? {
|
): Pair<PropertyStability, MutableList<ConeKotlinType>>? {
|
||||||
val flow = graphBuilder.lastNode.flow
|
val flow = graphBuilder.lastNode.flow
|
||||||
var variable = variableStorage.getRealVariableWithoutUnwrappingAlias(flow, symbol, expression) ?: return null
|
val variable = variableStorage.getRealVariableWithoutUnwrappingAlias(flow, symbol, expression) ?: return null
|
||||||
val stability = variable.stability
|
return flow.getType(variable)?.takeIf { it.isNotEmpty() }?.let { variable.stability to it.toMutableList() }
|
||||||
val result = mutableListOf<ConeKotlinType>()
|
|
||||||
flow.directAliasMap[variable]?.let {
|
|
||||||
result.addIfNotNull(it.originalType)
|
|
||||||
variable = it.variable
|
|
||||||
}
|
|
||||||
flow.getTypeStatement(variable)?.exactType?.let { result += it }
|
|
||||||
return result.takeIf { it.isNotEmpty() }?.let { stability to it }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun returnExpressionsOfAnonymousFunction(function: FirAnonymousFunction): Collection<FirStatement> {
|
fun returnExpressionsOfAnonymousFunction(function: FirAnonymousFunction): Collection<FirStatement> {
|
||||||
@@ -1251,11 +1241,7 @@ abstract class FirDataFlowAnalyzer<FLOW : Flow>(
|
|||||||
initializerVariable.isStable || (initializerVariable.hasLocalStability && initializer.isAccessToStableVariable())
|
initializerVariable.isStable || (initializerVariable.hasLocalStability && initializer.isAccessToStableVariable())
|
||||||
|
|
||||||
if (!hasExplicitType && isInitializerStable && (propertyVariable.hasLocalStability || propertyVariable.isStable)) {
|
if (!hasExplicitType && isInitializerStable && (propertyVariable.hasLocalStability || propertyVariable.isStable)) {
|
||||||
logicSystem.addLocalVariableAlias(
|
logicSystem.addLocalVariableAlias(flow, propertyVariable, initializerVariable)
|
||||||
flow, propertyVariable,
|
|
||||||
RealVariableAndType(initializerVariable, initializer.coneType)
|
|
||||||
)
|
|
||||||
// node.flow.addImplication((propertyVariable notEq null) implies (initializerVariable notEq null))
|
|
||||||
} else {
|
} else {
|
||||||
logicSystem.replaceVariableFromConditionInStatements(flow, initializerVariable, propertyVariable)
|
logicSystem.replaceVariableFromConditionInStatements(flow, initializerVariable, propertyVariable)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -76,26 +76,6 @@ class RealVariable(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class RealVariableAndType(val variable: RealVariable, val originalType: ConeKotlinType?) {
|
|
||||||
override fun equals(other: Any?): Boolean {
|
|
||||||
if (this === other) return true
|
|
||||||
if (javaClass != other?.javaClass) return false
|
|
||||||
|
|
||||||
other as RealVariableAndType
|
|
||||||
|
|
||||||
if (variable != other.variable) return false
|
|
||||||
if (originalType != other.originalType) return false
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun hashCode(): Int {
|
|
||||||
var result = variable.hashCode()
|
|
||||||
result = 31 * result + originalType.hashCode()
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class SyntheticVariable(val fir: FirElement, variableIndexForDebug: Int) : DataFlowVariable(variableIndexForDebug) {
|
class SyntheticVariable(val fir: FirElement, variableIndexForDebug: Int) : DataFlowVariable(variableIndexForDebug) {
|
||||||
override fun equals(other: Any?): Boolean {
|
override fun equals(other: Any?): Boolean {
|
||||||
if (this === other) return true
|
if (this === other) return true
|
||||||
|
|||||||
@@ -5,17 +5,9 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.fir.resolve.dfa
|
package org.jetbrains.kotlin.fir.resolve.dfa
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.fir.types.ConeKotlinType
|
||||||
|
|
||||||
abstract class Flow {
|
abstract class Flow {
|
||||||
abstract fun getTypeStatement(variable: RealVariable): TypeStatement?
|
abstract fun unwrapVariable(variable: RealVariable): RealVariable
|
||||||
abstract fun getImplications(variable: DataFlowVariable): Collection<Implication>
|
abstract fun getType(variable: RealVariable): Set<ConeKotlinType>?
|
||||||
abstract fun getVariablesInTypeStatements(): Collection<RealVariable>
|
|
||||||
abstract fun removeOperations(variable: DataFlowVariable): Collection<Implication>
|
|
||||||
|
|
||||||
abstract val directAliasMap: Map<RealVariable, RealVariableAndType>
|
|
||||||
abstract val backwardsAliasMap: Map<RealVariable, List<RealVariable>>
|
|
||||||
abstract val assignmentIndex: Map<RealVariable, Int>
|
|
||||||
}
|
|
||||||
|
|
||||||
fun Flow.unwrapVariable(variable: RealVariable): RealVariable {
|
|
||||||
return directAliasMap[variable]?.variable ?: variable
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ abstract class LogicSystem<FLOW : Flow>(protected val context: ConeInferenceCont
|
|||||||
shouldRemoveSynthetics: Boolean,
|
shouldRemoveSynthetics: Boolean,
|
||||||
): FLOW
|
): FLOW
|
||||||
|
|
||||||
abstract fun addLocalVariableAlias(flow: FLOW, alias: RealVariable, underlyingVariable: RealVariableAndType)
|
abstract fun addLocalVariableAlias(flow: FLOW, alias: RealVariable, underlyingVariable: RealVariable)
|
||||||
abstract fun removeLocalVariableAlias(flow: FLOW, alias: RealVariable)
|
abstract fun removeLocalVariableAlias(flow: FLOW, alias: RealVariable)
|
||||||
|
|
||||||
abstract fun recordNewAssignment(flow: FLOW, variable: RealVariable, index: Int)
|
abstract fun recordNewAssignment(flow: FLOW, variable: RealVariable, index: Int)
|
||||||
@@ -126,7 +126,7 @@ abstract class LogicSystem<FLOW : Flow>(protected val context: ConeInferenceCont
|
|||||||
op: (Collection<Set<ConeKotlinType>>) -> MutableSet<ConeKotlinType>
|
op: (Collection<Set<ConeKotlinType>>) -> MutableSet<ConeKotlinType>
|
||||||
): MutableTypeStatement {
|
): MutableTypeStatement {
|
||||||
require(statements.isNotEmpty())
|
require(statements.isNotEmpty())
|
||||||
statements.singleOrNull()?.let { return it as MutableTypeStatement }
|
statements.singleOrNull()?.let { return it.asMutableStatement() }
|
||||||
val variable = statements.first().variable
|
val variable = statements.first().variable
|
||||||
assert(statements.all { it.variable == variable })
|
assert(statements.all { it.variable == variable })
|
||||||
val exactType = op.invoke(statements.map { it.exactType })
|
val exactType = op.invoke(statements.map { it.exactType })
|
||||||
|
|||||||
+22
-42
@@ -9,7 +9,6 @@ import com.google.common.collect.ArrayListMultimap
|
|||||||
import kotlinx.collections.immutable.*
|
import kotlinx.collections.immutable.*
|
||||||
import org.jetbrains.kotlin.fir.types.ConeInferenceContext
|
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 java.util.*
|
import java.util.*
|
||||||
import kotlin.math.max
|
import kotlin.math.max
|
||||||
|
|
||||||
@@ -51,10 +50,10 @@ class PersistentFlow : Flow {
|
|||||||
* directAliasMap: { x -> a, y -> a}
|
* directAliasMap: { x -> a, y -> a}
|
||||||
* backwardsAliasMap: { a -> [x, y] }
|
* backwardsAliasMap: { a -> [x, y] }
|
||||||
*/
|
*/
|
||||||
override var directAliasMap: PersistentMap<RealVariable, RealVariableAndType>
|
var directAliasMap: PersistentMap<RealVariable, RealVariable>
|
||||||
override var backwardsAliasMap: PersistentMap<RealVariable, PersistentList<RealVariable>>
|
var backwardsAliasMap: PersistentMap<RealVariable, PersistentList<RealVariable>>
|
||||||
|
|
||||||
override var assignmentIndex: PersistentMap<RealVariable, Int>
|
var assignmentIndex: PersistentMap<RealVariable, Int>
|
||||||
|
|
||||||
constructor(previousFlow: PersistentFlow) {
|
constructor(previousFlow: PersistentFlow) {
|
||||||
this.previousFlow = previousFlow
|
this.previousFlow = previousFlow
|
||||||
@@ -78,24 +77,22 @@ class PersistentFlow : Flow {
|
|||||||
assignmentIndex = persistentMapOf()
|
assignmentIndex = persistentMapOf()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getTypeStatement(variable: RealVariable): TypeStatement? {
|
override fun unwrapVariable(variable: RealVariable): RealVariable {
|
||||||
return approvedTypeStatements[variable]
|
return directAliasMap[variable] ?: variable
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getImplications(variable: DataFlowVariable): Collection<Implication> {
|
fun getTypeStatement(variable: RealVariable): TypeStatement {
|
||||||
return logicStatements[variable] ?: emptyList()
|
val result = MutableTypeStatement(variable)
|
||||||
}
|
approvedTypeStatements[variable]?.let { result += it }
|
||||||
|
val variableUnderAlias = directAliasMap[variable]
|
||||||
override fun getVariablesInTypeStatements(): Collection<RealVariable> {
|
if (variableUnderAlias != null) {
|
||||||
return approvedTypeStatements.keys
|
approvedTypeStatements[variableUnderAlias]?.let { result += it }
|
||||||
}
|
|
||||||
|
|
||||||
override fun removeOperations(variable: DataFlowVariable): Collection<Implication> {
|
|
||||||
return getImplications(variable).also {
|
|
||||||
if (it.isNotEmpty()) {
|
|
||||||
logicStatements -= variable
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getType(variable: RealVariable): Set<ConeKotlinType> {
|
||||||
|
return getTypeStatement(variable).exactType
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -110,7 +107,7 @@ abstract class PersistentLogicSystem(context: ConeInferenceContext) : LogicSyste
|
|||||||
|
|
||||||
override fun joinFlow(flows: Collection<PersistentFlow>): PersistentFlow {
|
override fun joinFlow(flows: Collection<PersistentFlow>): PersistentFlow {
|
||||||
// One input flow executes - one set of statements is true, others might be false.
|
// One input flow executes - one set of statements is true, others might be false.
|
||||||
return foldFlow(flows) { variable -> or(flows.map { it.getApprovedTypeStatements(variable) }).takeIf { it.isNotEmpty } }
|
return foldFlow(flows) { variable -> or(flows.map { it.getTypeStatement(variable) }).takeIf { it.isNotEmpty } }
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun unionFlow(flows: Collection<PersistentFlow>): PersistentFlow {
|
override fun unionFlow(flows: Collection<PersistentFlow>): PersistentFlow {
|
||||||
@@ -120,7 +117,7 @@ abstract class PersistentLogicSystem(context: ConeInferenceContext) : LogicSyste
|
|||||||
// happened last (and the flows that don't reassign may or may not have executed after that).
|
// happened last (and the flows that don't reassign may or may not have executed after that).
|
||||||
return foldFlow(flows) { variable ->
|
return foldFlow(flows) { variable ->
|
||||||
or(flows.groupBy { it.assignmentIndex[variable] ?: -1 }.values.map { flowSubset ->
|
or(flows.groupBy { it.assignmentIndex[variable] ?: -1 }.values.map { flowSubset ->
|
||||||
and(flowSubset.map { it.getApprovedTypeStatements(variable) })
|
and(flowSubset.map { it.getTypeStatement(variable) })
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -166,16 +163,16 @@ abstract class PersistentLogicSystem(context: ConeInferenceContext) : LogicSyste
|
|||||||
return commonFlow
|
return commonFlow
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun computeCommonAliases(flows: Collection<PersistentFlow>): Map<RealVariable, RealVariableAndType> =
|
private fun computeCommonAliases(flows: Collection<PersistentFlow>): Map<RealVariable, RealVariable> =
|
||||||
flows.first().directAliasMap.filterTo(mutableMapOf()) { (variable, alias) ->
|
flows.first().directAliasMap.filterTo(mutableMapOf()) { (variable, alias) ->
|
||||||
flows.all { it.directAliasMap[variable] == alias }
|
flows.all { it.directAliasMap[variable] == alias }
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun addLocalVariableAlias(flow: PersistentFlow, alias: RealVariable, underlyingVariable: RealVariableAndType) {
|
override fun addLocalVariableAlias(flow: PersistentFlow, alias: RealVariable, underlyingVariable: RealVariable) {
|
||||||
removeLocalVariableAlias(flow, alias)
|
removeLocalVariableAlias(flow, alias)
|
||||||
flow.directAliasMap = flow.directAliasMap.put(alias, underlyingVariable)
|
flow.directAliasMap = flow.directAliasMap.put(alias, underlyingVariable)
|
||||||
flow.backwardsAliasMap = flow.backwardsAliasMap.put(
|
flow.backwardsAliasMap = flow.backwardsAliasMap.put(
|
||||||
underlyingVariable.variable,
|
underlyingVariable,
|
||||||
{ persistentListOf(alias) },
|
{ persistentListOf(alias) },
|
||||||
{ variables -> variables + alias }
|
{ variables -> variables + alias }
|
||||||
)
|
)
|
||||||
@@ -221,7 +218,7 @@ abstract class PersistentLogicSystem(context: ConeInferenceContext) : LogicSyste
|
|||||||
processApprovedStatements(isDiff = true)
|
processApprovedStatements(isDiff = true)
|
||||||
}
|
}
|
||||||
|
|
||||||
val original = flow.directAliasMap[alias]?.variable
|
val original = flow.directAliasMap[alias]
|
||||||
if (original != null) {
|
if (original != null) {
|
||||||
flow.directAliasMap = flow.directAliasMap.remove(alias)
|
flow.directAliasMap = flow.directAliasMap.remove(alias)
|
||||||
val updatedBackwardsAliasList = flow.backwardsAliasMap.getValue(original).remove(alias)
|
val updatedBackwardsAliasList = flow.backwardsAliasMap.getValue(original).remove(alias)
|
||||||
@@ -252,23 +249,6 @@ abstract class PersistentLogicSystem(context: ConeInferenceContext) : LogicSyste
|
|||||||
return statement as T
|
return statement as T
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@OptIn(DfaInternals::class)
|
|
||||||
private fun PersistentFlow.getApprovedTypeStatements(variable: RealVariable): MutableTypeStatement {
|
|
||||||
var flow = this
|
|
||||||
val result = MutableTypeStatement(variable)
|
|
||||||
val variableUnderAlias = directAliasMap[variable]
|
|
||||||
if (variableUnderAlias == null) {
|
|
||||||
flow.approvedTypeStatements[variable]?.let {
|
|
||||||
result += it
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
result.exactType.addIfNotNull(variableUnderAlias.originalType)
|
|
||||||
flow.approvedTypeStatements[variableUnderAlias.variable]?.let { result += it }
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun addTypeStatement(flow: PersistentFlow, statement: TypeStatement) {
|
override fun addTypeStatement(flow: PersistentFlow, statement: TypeStatement) {
|
||||||
if (statement.isEmpty) return
|
if (statement.isEmpty) return
|
||||||
with(flow) {
|
with(flow) {
|
||||||
|
|||||||
+1
-2
@@ -56,8 +56,7 @@ class VariableStorageImpl(private val session: FirSession) : VariableStorage() {
|
|||||||
fir: FirElement,
|
fir: FirElement,
|
||||||
stability: PropertyStability
|
stability: PropertyStability
|
||||||
): RealVariable {
|
): RealVariable {
|
||||||
val variable = getOrCreateRealVariableWithoutUnwrappingAlias(flow, symbol, fir, stability)
|
return flow.unwrapVariable(getOrCreateRealVariableWithoutUnwrappingAlias(flow, symbol, fir, stability))
|
||||||
return flow.directAliasMap[variable]?.variable ?: variable
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun FirElement.unwrapElement(): FirElement = when (this) {
|
private fun FirElement.unwrapElement(): FirElement = when (this) {
|
||||||
|
|||||||
+2
-1
@@ -265,7 +265,8 @@ FILE fqName:<root> fileName:/suspendConversionOnArbitraryExpression.kt
|
|||||||
TYPE_OP type=kotlin.coroutines.SuspendFunction0<kotlin.Unit> origin=CAST typeOperand=kotlin.coroutines.SuspendFunction0<kotlin.Unit>
|
TYPE_OP type=kotlin.coroutines.SuspendFunction0<kotlin.Unit> origin=CAST typeOperand=kotlin.coroutines.SuspendFunction0<kotlin.Unit>
|
||||||
GET_VAR 'var b: kotlin.Function0<kotlin.Unit> [var] declared in <root>.testSmartCastOnVarVsSuspendConversion' type=kotlin.Function0<kotlin.Unit> origin=null
|
GET_VAR 'var b: kotlin.Function0<kotlin.Unit> [var] declared in <root>.testSmartCastOnVarVsSuspendConversion' type=kotlin.Function0<kotlin.Unit> origin=null
|
||||||
CALL 'public final fun useSuspend (sfn: kotlin.coroutines.SuspendFunction0<kotlin.Unit>): kotlin.Unit declared in <root>' type=kotlin.Unit origin=null
|
CALL 'public final fun useSuspend (sfn: kotlin.coroutines.SuspendFunction0<kotlin.Unit>): kotlin.Unit declared in <root>' type=kotlin.Unit origin=null
|
||||||
sfn: GET_VAR 'var b: kotlin.Function0<kotlin.Unit> [var] declared in <root>.testSmartCastOnVarVsSuspendConversion' type=kotlin.Function0<kotlin.Unit> origin=null
|
sfn: TYPE_OP type=kotlin.coroutines.SuspendFunction0<kotlin.Unit> origin=IMPLICIT_CAST typeOperand=kotlin.coroutines.SuspendFunction0<kotlin.Unit>
|
||||||
|
GET_VAR 'var b: kotlin.Function0<kotlin.Unit> [var] declared in <root>.testSmartCastOnVarVsSuspendConversion' type=kotlin.Function0<kotlin.Unit> origin=null
|
||||||
FUN name:testIntersectionVsSuspendConversion visibility:public modality:FINAL <T> (x:T of <root>.testIntersectionVsSuspendConversion) returnType:kotlin.Unit
|
FUN name:testIntersectionVsSuspendConversion visibility:public modality:FINAL <T> (x:T of <root>.testIntersectionVsSuspendConversion) returnType:kotlin.Unit
|
||||||
TYPE_PARAMETER name:T index:0 variance: superTypes:[kotlin.Function0<kotlin.Unit>; kotlin.coroutines.SuspendFunction0<kotlin.Unit>] reified:false
|
TYPE_PARAMETER name:T index:0 variance: superTypes:[kotlin.Function0<kotlin.Unit>; kotlin.coroutines.SuspendFunction0<kotlin.Unit>] reified:false
|
||||||
VALUE_PARAMETER name:x index:0 type:T of <root>.testIntersectionVsSuspendConversion
|
VALUE_PARAMETER name:x index:0 type:T of <root>.testIntersectionVsSuspendConversion
|
||||||
|
|||||||
+1
-1
@@ -181,7 +181,7 @@ fun testSmartCastVsSuspendConversion(a: Function0<Unit>) {
|
|||||||
fun testSmartCastOnVarVsSuspendConversion(a: Function0<Unit>) {
|
fun testSmartCastOnVarVsSuspendConversion(a: Function0<Unit>) {
|
||||||
var b: Function0<Unit> = a
|
var b: Function0<Unit> = a
|
||||||
b as SuspendFunction0<Unit> /*~> Unit */
|
b as SuspendFunction0<Unit> /*~> Unit */
|
||||||
useSuspend(sfn = b)
|
useSuspend(sfn = b /*as SuspendFunction0<Unit> */)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <T> testIntersectionVsSuspendConversion(x: T) where T : Function0<Unit>, T : SuspendFunction0<Unit> {
|
fun <T> testIntersectionVsSuspendConversion(x: T) where T : Function0<Unit>, T : SuspendFunction0<Unit> {
|
||||||
|
|||||||
@@ -206,20 +206,20 @@ fun <T> T.case_7() {
|
|||||||
val x = this
|
val x = this
|
||||||
if (x is Interface1?) {
|
if (x is Interface1?) {
|
||||||
if (x != null) {
|
if (x != null) {
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("T & T!! & Interface1")!>x<!>
|
<!DEBUG_INFO_EXPRESSION_TYPE("T & Interface1 & T!!")!>x<!>
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("T & T!! & Interface1")!>x<!>.equals(null)
|
<!DEBUG_INFO_EXPRESSION_TYPE("T & Interface1 & T!!")!>x<!>.equals(null)
|
||||||
x.propT
|
x.propT
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("T & T!! & Interface1")!>x<!>.propAny
|
<!DEBUG_INFO_EXPRESSION_TYPE("T & Interface1 & T!!")!>x<!>.propAny
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("T & T!! & Interface1")!>x<!>.propNullableT
|
<!DEBUG_INFO_EXPRESSION_TYPE("T & Interface1 & T!!")!>x<!>.propNullableT
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("T & T!! & Interface1")!>x<!>.propNullableAny
|
<!DEBUG_INFO_EXPRESSION_TYPE("T & Interface1 & T!!")!>x<!>.propNullableAny
|
||||||
x.funT()
|
x.funT()
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("T & T!! & Interface1")!>x<!>.funAny()
|
<!DEBUG_INFO_EXPRESSION_TYPE("T & Interface1 & T!!")!>x<!>.funAny()
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("T & T!! & Interface1")!>x<!>.funNullableT()
|
<!DEBUG_INFO_EXPRESSION_TYPE("T & Interface1 & T!!")!>x<!>.funNullableT()
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("T & T!! & Interface1")!>x<!>.funNullableAny()
|
<!DEBUG_INFO_EXPRESSION_TYPE("T & Interface1 & T!!")!>x<!>.funNullableAny()
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("T & T!! & Interface1")!>x<!>.itest1()
|
<!DEBUG_INFO_EXPRESSION_TYPE("T & Interface1 & T!!")!>x<!>.itest1()
|
||||||
|
|
||||||
x.apply {
|
x.apply {
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("T!! & Interface1")!>this<!>
|
<!DEBUG_INFO_EXPRESSION_TYPE("Interface1 & T!!")!>this<!>
|
||||||
equals(null)
|
equals(null)
|
||||||
propT
|
propT
|
||||||
propAny
|
propAny
|
||||||
@@ -230,29 +230,29 @@ fun <T> T.case_7() {
|
|||||||
funNullableT()
|
funNullableT()
|
||||||
funNullableAny()
|
funNullableAny()
|
||||||
itest1()
|
itest1()
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("T!! & Interface1")!>this<!>.equals(null)
|
<!DEBUG_INFO_EXPRESSION_TYPE("Interface1 & T!!")!>this<!>.equals(null)
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("T!! & Interface1")!>this<!>.propT
|
<!DEBUG_INFO_EXPRESSION_TYPE("Interface1 & T!!")!>this<!>.propT
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("T!! & Interface1")!>this<!>.propAny
|
<!DEBUG_INFO_EXPRESSION_TYPE("Interface1 & T!!")!>this<!>.propAny
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("T!! & Interface1")!>this<!>.propNullableT
|
<!DEBUG_INFO_EXPRESSION_TYPE("Interface1 & T!!")!>this<!>.propNullableT
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("T!! & Interface1")!>this<!>.propNullableAny
|
<!DEBUG_INFO_EXPRESSION_TYPE("Interface1 & T!!")!>this<!>.propNullableAny
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("T!! & Interface1")!>this<!>.funT()
|
<!DEBUG_INFO_EXPRESSION_TYPE("Interface1 & T!!")!>this<!>.funT()
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("T!! & Interface1")!>this<!>.funAny()
|
<!DEBUG_INFO_EXPRESSION_TYPE("Interface1 & T!!")!>this<!>.funAny()
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("T!! & Interface1")!>this<!>.funNullableT()
|
<!DEBUG_INFO_EXPRESSION_TYPE("Interface1 & T!!")!>this<!>.funNullableT()
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("T!! & Interface1")!>this<!>.funNullableAny()
|
<!DEBUG_INFO_EXPRESSION_TYPE("Interface1 & T!!")!>this<!>.funNullableAny()
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("T!! & Interface1")!>this<!>.itest1()
|
<!DEBUG_INFO_EXPRESSION_TYPE("Interface1 & T!!")!>this<!>.itest1()
|
||||||
}
|
}
|
||||||
x.also {
|
x.also {
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("T!! & Interface1")!>it<!>
|
<!DEBUG_INFO_EXPRESSION_TYPE("Interface1 & T!!")!>it<!>
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("T!! & Interface1")!>it<!>.itest1()
|
<!DEBUG_INFO_EXPRESSION_TYPE("Interface1 & T!!")!>it<!>.itest1()
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("T!! & Interface1")!>it<!>.equals(null)
|
<!DEBUG_INFO_EXPRESSION_TYPE("Interface1 & T!!")!>it<!>.equals(null)
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("T!! & Interface1")!>it<!>.propT
|
<!DEBUG_INFO_EXPRESSION_TYPE("Interface1 & T!!")!>it<!>.propT
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("T!! & Interface1")!>it<!>.propAny
|
<!DEBUG_INFO_EXPRESSION_TYPE("Interface1 & T!!")!>it<!>.propAny
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("T!! & Interface1")!>it<!>.propNullableT
|
<!DEBUG_INFO_EXPRESSION_TYPE("Interface1 & T!!")!>it<!>.propNullableT
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("T!! & Interface1")!>it<!>.propNullableAny
|
<!DEBUG_INFO_EXPRESSION_TYPE("Interface1 & T!!")!>it<!>.propNullableAny
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("T!! & Interface1")!>it<!>.funT()
|
<!DEBUG_INFO_EXPRESSION_TYPE("Interface1 & T!!")!>it<!>.funT()
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("T!! & Interface1")!>it<!>.funAny()
|
<!DEBUG_INFO_EXPRESSION_TYPE("Interface1 & T!!")!>it<!>.funAny()
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("T!! & Interface1")!>it<!>.funNullableT()
|
<!DEBUG_INFO_EXPRESSION_TYPE("Interface1 & T!!")!>it<!>.funNullableT()
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("T!! & Interface1")!>it<!>.funNullableAny()
|
<!DEBUG_INFO_EXPRESSION_TYPE("Interface1 & T!!")!>it<!>.funNullableAny()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -258,20 +258,20 @@ fun <T> case_7(y: T) {
|
|||||||
val x = y
|
val x = y
|
||||||
if (x is Interface1?) {
|
if (x is Interface1?) {
|
||||||
if (x != null) {
|
if (x != null) {
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("T & T!! & Interface1")!>x<!>
|
<!DEBUG_INFO_EXPRESSION_TYPE("T & Interface1 & T!!")!>x<!>
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("T & T!! & Interface1")!>x<!>.equals(null)
|
<!DEBUG_INFO_EXPRESSION_TYPE("T & Interface1 & T!!")!>x<!>.equals(null)
|
||||||
x.propT
|
x.propT
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("T & T!! & Interface1")!>x<!>.propAny
|
<!DEBUG_INFO_EXPRESSION_TYPE("T & Interface1 & T!!")!>x<!>.propAny
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("T & T!! & Interface1")!>x<!>.propNullableT
|
<!DEBUG_INFO_EXPRESSION_TYPE("T & Interface1 & T!!")!>x<!>.propNullableT
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("T & T!! & Interface1")!>x<!>.propNullableAny
|
<!DEBUG_INFO_EXPRESSION_TYPE("T & Interface1 & T!!")!>x<!>.propNullableAny
|
||||||
x.funT()
|
x.funT()
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("T & T!! & Interface1")!>x<!>.funAny()
|
<!DEBUG_INFO_EXPRESSION_TYPE("T & Interface1 & T!!")!>x<!>.funAny()
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("T & T!! & Interface1")!>x<!>.funNullableT()
|
<!DEBUG_INFO_EXPRESSION_TYPE("T & Interface1 & T!!")!>x<!>.funNullableT()
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("T & T!! & Interface1")!>x<!>.funNullableAny()
|
<!DEBUG_INFO_EXPRESSION_TYPE("T & Interface1 & T!!")!>x<!>.funNullableAny()
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("T & T!! & Interface1")!>x<!>.itest()
|
<!DEBUG_INFO_EXPRESSION_TYPE("T & Interface1 & T!!")!>x<!>.itest()
|
||||||
|
|
||||||
x.apply {
|
x.apply {
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("T!! & Interface1")!>this<!>
|
<!DEBUG_INFO_EXPRESSION_TYPE("Interface1 & T!!")!>this<!>
|
||||||
equals(null)
|
equals(null)
|
||||||
propT
|
propT
|
||||||
propAny
|
propAny
|
||||||
@@ -282,29 +282,29 @@ fun <T> case_7(y: T) {
|
|||||||
funNullableT()
|
funNullableT()
|
||||||
funNullableAny()
|
funNullableAny()
|
||||||
itest()
|
itest()
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("T!! & Interface1")!>this<!>.equals(null)
|
<!DEBUG_INFO_EXPRESSION_TYPE("Interface1 & T!!")!>this<!>.equals(null)
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("T!! & Interface1")!>this<!>.propT
|
<!DEBUG_INFO_EXPRESSION_TYPE("Interface1 & T!!")!>this<!>.propT
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("T!! & Interface1")!>this<!>.propAny
|
<!DEBUG_INFO_EXPRESSION_TYPE("Interface1 & T!!")!>this<!>.propAny
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("T!! & Interface1")!>this<!>.propNullableT
|
<!DEBUG_INFO_EXPRESSION_TYPE("Interface1 & T!!")!>this<!>.propNullableT
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("T!! & Interface1")!>this<!>.propNullableAny
|
<!DEBUG_INFO_EXPRESSION_TYPE("Interface1 & T!!")!>this<!>.propNullableAny
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("T!! & Interface1")!>this<!>.funT()
|
<!DEBUG_INFO_EXPRESSION_TYPE("Interface1 & T!!")!>this<!>.funT()
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("T!! & Interface1")!>this<!>.funAny()
|
<!DEBUG_INFO_EXPRESSION_TYPE("Interface1 & T!!")!>this<!>.funAny()
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("T!! & Interface1")!>this<!>.funNullableT()
|
<!DEBUG_INFO_EXPRESSION_TYPE("Interface1 & T!!")!>this<!>.funNullableT()
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("T!! & Interface1")!>this<!>.funNullableAny()
|
<!DEBUG_INFO_EXPRESSION_TYPE("Interface1 & T!!")!>this<!>.funNullableAny()
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("T!! & Interface1")!>this<!>.itest()
|
<!DEBUG_INFO_EXPRESSION_TYPE("Interface1 & T!!")!>this<!>.itest()
|
||||||
}
|
}
|
||||||
x.also {
|
x.also {
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("T!! & Interface1")!>it<!>
|
<!DEBUG_INFO_EXPRESSION_TYPE("Interface1 & T!!")!>it<!>
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("T!! & Interface1")!>it<!>.itest()
|
<!DEBUG_INFO_EXPRESSION_TYPE("Interface1 & T!!")!>it<!>.itest()
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("T!! & Interface1")!>it<!>.equals(null)
|
<!DEBUG_INFO_EXPRESSION_TYPE("Interface1 & T!!")!>it<!>.equals(null)
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("T!! & Interface1")!>it<!>.propT
|
<!DEBUG_INFO_EXPRESSION_TYPE("Interface1 & T!!")!>it<!>.propT
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("T!! & Interface1")!>it<!>.propAny
|
<!DEBUG_INFO_EXPRESSION_TYPE("Interface1 & T!!")!>it<!>.propAny
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("T!! & Interface1")!>it<!>.propNullableT
|
<!DEBUG_INFO_EXPRESSION_TYPE("Interface1 & T!!")!>it<!>.propNullableT
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("T!! & Interface1")!>it<!>.propNullableAny
|
<!DEBUG_INFO_EXPRESSION_TYPE("Interface1 & T!!")!>it<!>.propNullableAny
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("T!! & Interface1")!>it<!>.funT()
|
<!DEBUG_INFO_EXPRESSION_TYPE("Interface1 & T!!")!>it<!>.funT()
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("T!! & Interface1")!>it<!>.funAny()
|
<!DEBUG_INFO_EXPRESSION_TYPE("Interface1 & T!!")!>it<!>.funAny()
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("T!! & Interface1")!>it<!>.funNullableT()
|
<!DEBUG_INFO_EXPRESSION_TYPE("Interface1 & T!!")!>it<!>.funNullableT()
|
||||||
<!DEBUG_INFO_EXPRESSION_TYPE("T!! & Interface1")!>it<!>.funNullableAny()
|
<!DEBUG_INFO_EXPRESSION_TYPE("Interface1 & T!!")!>it<!>.funNullableAny()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user