FIR DFA: remove RealVariableAndType

This commit is contained in:
pyos
2022-11-03 15:05:28 +01:00
committed by teamcity
parent 33363ba1fc
commit 7c8e9ac316
13 changed files with 133 additions and 187 deletions
@@ -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};
} }
@@ -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|
} }
} }
@@ -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
} }
} }
@@ -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 })
@@ -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) {
@@ -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) {
@@ -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
@@ -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()
} }
} }
} }