FIR: Support FirComparisonOperator in body transformers and DFA

^KT-31163 In Progress
This commit is contained in:
Denis Zharkov
2020-02-26 16:45:57 +03:00
parent c3aed433ae
commit 434444cd69
31 changed files with 191 additions and 149 deletions
@@ -233,6 +233,10 @@ abstract class FirDataFlowAnalyzer<FLOW : Flow>(
node.flow = flow
}
fun exitComparisonExpressionCall(comparisonExpression: FirComparisonExpression) {
graphBuilder.exitComparisonExpression(comparisonExpression).mergeIncomingFlow()
}
fun exitOperatorCall(operatorCall: FirOperatorCall) {
val node = graphBuilder.exitOperatorCall(operatorCall).mergeIncomingFlow()
when (val operation = operatorCall.operation) {
@@ -180,6 +180,7 @@ class BinaryOrExitNode(owner: ControlFlowGraph, override val fir: FirBinaryLogic
class TypeOperatorCallNode(owner: ControlFlowGraph, override val fir: FirTypeOperatorCall, level: Int, id: Int) : CFGNode<FirTypeOperatorCall>(owner, level, id)
class OperatorCallNode(owner: ControlFlowGraph, override val fir: FirOperatorCall, level: Int, id: Int) : AbstractBinaryExitNode<FirOperatorCall>(owner, level, id)
class ComparisonExpressionNode(owner: ControlFlowGraph, override val fir: FirComparisonExpression, level: Int, id: Int) : CFGNode<FirComparisonExpression>(owner, level, id)
// ----------------------------------- Jump -----------------------------------
@@ -256,6 +256,10 @@ class ControlFlowGraphBuilder {
return createOperatorCallNode(operatorCall).also { addNewSimpleNode(it) }
}
fun exitComparisonExpression(comparisonExpression: FirComparisonExpression): ComparisonExpressionNode {
return ComparisonExpressionNode(graph, comparisonExpression, levelCounter, createId()).also { addNewSimpleNode(it) }
}
// ----------------------------------- Jump -----------------------------------
fun exitJump(jump: FirJump<*>): JumpNode {
@@ -723,4 +727,4 @@ class ControlFlowGraphBuilder {
fun reset() {
exitsOfAnonymousFunctions.clear()
}
}
}
@@ -159,6 +159,7 @@ private fun CFGNode<*>.render(): String =
is QualifiedAccessNode -> "Access variable ${fir.calleeReference.render(FirRenderer.RenderMode.DontRenderLambdaBodies)}"
is OperatorCallNode -> "Operator ${fir.operation.operator}"
is ComparisonExpressionNode -> "Comparison ${fir.operation.operator}"
is TypeOperatorCallNode -> "Type operator: \"${fir.render(FirRenderer.RenderMode.DontRenderLambdaBodies)}\""
is JumpNode -> "Jump: ${fir.render()}"
is StubNode -> "Stub"
@@ -244,4 +245,4 @@ private fun ControlFlowGraph.sortNodes(): List<CFGNode<*>> {
}
}
private fun List<CFGNode<*>>.indicesMap(): Map<CFGNode<*>, Int> = mapIndexed { i, node -> node to i }.toMap()
private fun List<CFGNode<*>>.indicesMap(): Map<CFGNode<*>, Int> = mapIndexed { i, node -> node to i }.toMap()
@@ -106,6 +106,13 @@ open class FirBodyResolveTransformer(
return expressionsTransformer.transformThisReceiverExpression(thisReceiverExpression, data)
}
override fun transformComparisonExpression(
comparisonExpression: FirComparisonExpression,
data: ResolutionMode
): CompositeTransformResult<FirStatement> {
return expressionsTransformer.transformComparisonExpression(comparisonExpression, data)
}
override fun transformOperatorCall(operatorCall: FirOperatorCall, data: ResolutionMode): CompositeTransformResult<FirStatement> {
return expressionsTransformer.transformOperatorCall(operatorCall, data)
}
@@ -208,6 +208,15 @@ class FirExpressionsResolveTransformer(transformer: FirBodyResolveTransformer) :
return transformQualifiedAccessExpression(thisReceiverExpression, data)
}
override fun transformComparisonExpression(
comparisonExpression: FirComparisonExpression,
data: ResolutionMode
): CompositeTransformResult<FirStatement> {
return (comparisonExpression.transformChildren(transformer, ResolutionMode.ContextIndependent) as FirComparisonExpression).also {
it.resultType = comparisonExpression.typeRef.resolvedTypeFromPrototype(builtinTypes.booleanType.type)
}.transformSingle(integerLiteralTypeApproximator, null).also(dataFlowAnalyzer::exitComparisonExpressionCall).compose()
}
override fun transformOperatorCall(operatorCall: FirOperatorCall, data: ResolutionMode): CompositeTransformResult<FirStatement> {
if (operatorCall.operation in FirOperation.BOOLEANS) {
// TODO: add approximation of integer literals
+1 -1
View File
@@ -1,7 +1,7 @@
FILE: fib.kt
public final fun fibIterative(n: R|kotlin/Int|): R|kotlin/Int| {
when () {
<(R|<local>/n|, Int(2)) -> {
CMP(<, R|<local>/n|.R|kotlin/Int.compareTo|(Int(2))) -> {
^fibIterative Int(1)
}
}
@@ -7,15 +7,15 @@ FILE: kotlinSam.kt
}
public final fun main(): R|kotlin/Unit| {
R|/foo|(R|/MyRunnable|(<L> = MyRunnable@fun <anonymous>(x: R|kotlin/Int|): R|kotlin/Boolean| {
^ >(R|<local>/x|, Int(1))
^ CMP(>, R|<local>/x|.R|kotlin/Int.compareTo|(Int(1)))
}
))
R|/foo|(R|/MyRunnable|(MyRunnable@fun <anonymous>(it: R|kotlin/Int|): R|kotlin/Boolean| {
^ >(R|<local>/it|, Int(1))
^ CMP(>, R|<local>/it|.R|kotlin/Int.compareTo|(Int(1)))
}
))
lval x: R|(kotlin/Int) -> kotlin/Boolean| = fun <anonymous>(x: R|kotlin/Int|): R|kotlin/Boolean| {
^ >(R|<local>/x|, Int(1))
^ CMP(>, R|<local>/x|.R|kotlin/Int.compareTo|(Int(1)))
}
R|/foo|(R|/MyRunnable|(R|<local>/x|))
@@ -6,15 +6,15 @@ FILE: main.kt
}
public final fun main(): R|kotlin/Unit| {
<Inapplicable(INAPPLICABLE): [/foo]>#(R|/MyRunnable|(<L> = MyRunnable@fun <anonymous>(x: R|kotlin/Int|): R|kotlin/Boolean| {
^ >(R|<local>/x|, Int(1))
^ CMP(>, R|<local>/x|.R|kotlin/Int.compareTo|(Int(1)))
}
))
<Inapplicable(INAPPLICABLE): [/foo]>#(R|/MyRunnable|(MyRunnable@fun <anonymous>(it: R|kotlin/Int|): R|kotlin/Boolean| {
^ >(R|<local>/it|, Int(1))
^ CMP(>, R|<local>/it|.R|kotlin/Int.compareTo|(Int(1)))
}
))
lval x: R|(kotlin/Int) -> kotlin/Boolean| = fun <anonymous>(x: R|kotlin/Int|): R|kotlin/Boolean| {
^ >(R|<local>/x|, Int(1))
^ CMP(>, R|<local>/x|.R|kotlin/Int.compareTo|(Int(1)))
}
<Inapplicable(INAPPLICABLE): [/foo]>#(R|/MyRunnable|(R|<local>/x|))
@@ -3,15 +3,15 @@ FILE: main.kt
}
public final fun main(): R|kotlin/Unit| {
R|/foo|(R|/MyRunnable|(<L> = MyRunnable@fun <anonymous>(x: R|kotlin/Int|): R|kotlin/Boolean| {
^ >(R|<local>/x|, Int(1))
^ CMP(>, R|<local>/x|.R|kotlin/Int.compareTo|(Int(1)))
}
))
R|/foo|(R|/MyRunnable|(MyRunnable@fun <anonymous>(it: R|kotlin/Int|): R|kotlin/Boolean| {
^ >(R|<local>/it|, Int(1))
^ CMP(>, R|<local>/it|.R|kotlin/Int.compareTo|(Int(1)))
}
))
lval x: R|(kotlin/Int) -> kotlin/Boolean| = fun <anonymous>(x: R|kotlin/Int|): R|kotlin/Boolean| {
^ >(R|<local>/x|, Int(1))
^ CMP(>, R|<local>/x|.R|kotlin/Int.compareTo|(Int(1)))
}
R|/foo|(R|/MyRunnable|(R|<local>/x|))
@@ -30,10 +30,10 @@ fun main() {
foo1 { x -> x > 1 }
foo1(f)
<!INAPPLICABLE_CANDIDATE!>foo2<!> { x -> x > 1 }
<!INAPPLICABLE_CANDIDATE!>foo2<!> { x -> x <!UNRESOLVED_REFERENCE!>><!> 1 }
<!INAPPLICABLE_CANDIDATE!>foo2<!>(f)
<!INAPPLICABLE_CANDIDATE!>foo3<!> { x -> x > 1 }
<!INAPPLICABLE_CANDIDATE!>foo3<!> { x -> x <!UNRESOLVED_REFERENCE!>><!> 1 }
<!INAPPLICABLE_CANDIDATE!>foo3<!>(f)
foo4 { x -> x > 1 }
@@ -30,26 +30,26 @@ FILE: kotlinSam.kt
}
public final fun main(): R|kotlin/Unit| {
lval f: R|(kotlin/Int) -> kotlin/Boolean| = fun <anonymous>(t: R|kotlin/Int|): R|kotlin/Boolean| {
^ >(R|<local>/t|, Int(1))
^ CMP(>, R|<local>/t|.R|kotlin/Int.compareTo|(Int(1)))
}
R|/foo1|(<L> = foo1@fun <anonymous>(x: R|kotlin/Int|): R|kotlin/Boolean| {
^ >(R|<local>/x|, Int(1))
^ CMP(>, R|<local>/x|.R|kotlin/Int.compareTo|(Int(1)))
}
)
R|/foo1|(R|<local>/f|)
<Inapplicable(INAPPLICABLE): [/foo2]>#(<L> = foo2@fun <anonymous>(x: R|ERROR CLASS: No type for parameter|): R|kotlin/Boolean| {
^ >(R|<local>/x|, Int(1))
^ CMP(>, R|<local>/x|.<Unresolved name: compareTo>#(Int(1)))
}
)
<Inapplicable(INAPPLICABLE): [/foo2]>#(R|<local>/f|)
<Inapplicable(INAPPLICABLE): [/foo3]>#(<L> = foo3@fun <anonymous>(x: R|ERROR CLASS: No type for parameter|): R|kotlin/Boolean| {
^ >(R|<local>/x|, Int(1))
^ CMP(>, R|<local>/x|.<Unresolved name: compareTo>#(Int(1)))
}
)
<Inapplicable(INAPPLICABLE): [/foo3]>#(R|<local>/f|)
R|/foo4|(<L> = foo4@fun <anonymous>(x: R|kotlin/Int|): R|kotlin/Boolean| {
^ >(R|<local>/x|, Int(1))
^ CMP(>, R|<local>/x|.R|kotlin/Int.compareTo|(Int(1)))
}
)
R|/foo4|(R|<local>/f|)
@@ -20,10 +20,10 @@ fun foo(m: MyRunnable) {}
fun main() {
JavaUsage.<!INAPPLICABLE_CANDIDATE!>foo<!> {
x ->
x > 1
x <!UNRESOLVED_REFERENCE!>><!> 1
}
JavaUsage.<!INAPPLICABLE_CANDIDATE!>foo<!>({ <!UNRESOLVED_REFERENCE!>it<!> > 1 })
JavaUsage.<!INAPPLICABLE_CANDIDATE!>foo<!>({ <!UNRESOLVED_REFERENCE!>it<!> <!UNRESOLVED_REFERENCE!>><!> 1 })
val x = { x: Int -> x > 1 }
@@ -3,15 +3,15 @@ FILE: main.kt
}
public final fun main(): R|kotlin/Unit| {
Q|JavaUsage|.<Inapplicable(INAPPLICABLE): [/JavaUsage.foo]>#(<L> = foo@fun <anonymous>(x: R|ERROR CLASS: No type for parameter|): R|kotlin/Boolean| {
^ >(R|<local>/x|, Int(1))
^ CMP(>, R|<local>/x|.<Unresolved name: compareTo>#(Int(1)))
}
)
Q|JavaUsage|.<Inapplicable(INAPPLICABLE): [/JavaUsage.foo]>#(foo@fun <anonymous>(): R|kotlin/Boolean| {
^ >(<Unresolved name: it>#, Int(1))
^ CMP(>, <Unresolved name: it>#.<Unresolved name: compareTo>#(Int(1)))
}
)
lval x: R|(kotlin/Int) -> kotlin/Boolean| = fun <anonymous>(x: R|kotlin/Int|): R|kotlin/Boolean| {
^ >(R|<local>/x|, Int(1))
^ CMP(>, R|<local>/x|.R|kotlin/Int.compareTo|(Int(1)))
}
Q|JavaUsage|.<Inapplicable(INAPPLICABLE): [/JavaUsage.foo]>#(R|<local>/x|)
@@ -3,15 +3,15 @@ FILE: main.kt
}
public final fun main(): R|kotlin/Unit| {
Q|JavaUsage|.R|/JavaUsage.foo|(<L> = foo@fun <anonymous>(x: R|kotlin/Int|): R|kotlin/Boolean| {
^ >(R|<local>/x|, Int(1))
^ CMP(>, R|<local>/x|.R|kotlin/Int.compareTo|(Int(1)))
}
)
Q|JavaUsage|.R|/JavaUsage.foo|(foo@fun <anonymous>(it: R|kotlin/Int|): R|kotlin/Boolean| {
^ >(R|<local>/it|, Int(1))
^ CMP(>, R|<local>/it|.R|kotlin/Int.compareTo|(Int(1)))
}
)
lval x: R|(kotlin/Int) -> kotlin/Boolean| = fun <anonymous>(x: R|kotlin/Int|): R|kotlin/Boolean| {
^ >(R|<local>/x|, Int(1))
^ CMP(>, R|<local>/x|.R|kotlin/Int.compareTo|(Int(1)))
}
Q|JavaUsage|.R|/JavaUsage.foo|(R|<local>/x|)
@@ -3,15 +3,15 @@ FILE: main.kt
}
public final fun main(): R|kotlin/Unit| {
Q|JavaUsage|.R|/JavaUsage.foo|(<L> = foo@fun <anonymous>(x: R|kotlin/Int|): R|ft<kotlin/Boolean, kotlin/Boolean?>!| {
^ >(R|<local>/x|, Int(1))
^ CMP(>, R|<local>/x|.R|kotlin/Int.compareTo|(Int(1)))
}
)
Q|JavaUsage|.R|/JavaUsage.foo|(foo@fun <anonymous>(it: R|kotlin/Int|): R|ft<kotlin/Boolean, kotlin/Boolean?>!| {
^ >(R|<local>/it|, Int(1))
^ CMP(>, R|<local>/it|.R|kotlin/Int.compareTo|(Int(1)))
}
)
lval x: R|(kotlin/Int) -> kotlin/Boolean| = fun <anonymous>(x: R|kotlin/Int|): R|kotlin/Boolean| {
^ >(R|<local>/x|, Int(1))
^ CMP(>, R|<local>/x|.R|kotlin/Int.compareTo|(Int(1)))
}
Q|JavaUsage|.R|/JavaUsage.foo|(R|<local>/x|)
@@ -3,15 +3,15 @@ FILE: main.kt
}
public final fun main(): R|kotlin/Unit| {
Q|JavaUsage|.R|/JavaUsage.foo|(<L> = foo@fun <anonymous>(x: R|kotlin/Int|): R|kotlin/Boolean| {
^ >(R|<local>/x|, Int(1))
^ CMP(>, R|<local>/x|.R|kotlin/Int.compareTo|(Int(1)))
}
)
Q|JavaUsage|.R|/JavaUsage.foo|(foo@fun <anonymous>(it: R|kotlin/Int|): R|kotlin/Boolean| {
^ >(R|<local>/it|, Int(1))
^ CMP(>, R|<local>/it|.R|kotlin/Int.compareTo|(Int(1)))
}
)
lval x: R|(kotlin/Int) -> kotlin/Boolean| = fun <anonymous>(x: R|kotlin/Int|): R|kotlin/Boolean| {
^ >(R|<local>/x|, Int(1))
^ CMP(>, R|<local>/x|.R|kotlin/Int.compareTo|(Int(1)))
}
Q|JavaUsage|.R|/JavaUsage.foo|(R|<local>/x|)
@@ -11,7 +11,7 @@ FILE: ifWithCR.kt
private set(value: R|kotlin/CharSequence?|): R|kotlin/Unit|
public final fun main(x: R|kotlin/Int|): R|kotlin/Unit| {
lval x: R|kotlin/reflect/KMutableProperty0<kotlin/CharSequence?>| = when () {
>(R|<local>/x|, Int(1)) -> {
CMP(>, R|<local>/x|.R|kotlin/Int.compareTo|(Int(1))) -> {
R|<local>/x|::R|/readOnlyWrapper|
}
else -> {
@@ -100,183 +100,187 @@ digraph callsInPlace_kt {
34 [label="Const: String(test_4)"];
35 [label="Access variable R|<local>/it|"];
36 [label="Const: Int(0)"];
37 [label="Operator >"];
38 [label="Exit function anonymousFunction"];
37 [label="Function call: R|<local>/it|.R|kotlin/Int.compareTo|(Int(0))"];
38 [label="Comparison >"];
39 [label="Exit function anonymousFunction"];
}
39 [label="Postponed exit from lambda"];
40 [label="Function call: Int(1).R|kotlin/takeUnless|<R|kotlin/Int|>(<L> = takeUnless@fun <anonymous>(it: R|kotlin/Int|): R|kotlin/Boolean| <kind=EXACTLY_ONCE> )"];
41 [label="Exit function test_4" style="filled" fillcolor=red];
40 [label="Postponed exit from lambda"];
41 [label="Function call: Int(1).R|kotlin/takeUnless|<R|kotlin/Int|>(<L> = takeUnless@fun <anonymous>(it: R|kotlin/Int|): R|kotlin/Boolean| <kind=EXACTLY_ONCE> )"];
42 [label="Exit function test_4" style="filled" fillcolor=red];
}
30 -> {31};
31 -> {32};
32 -> {33};
32 -> {39} [color=red];
32 -> {40} [color=red];
33 -> {34};
34 -> {35};
35 -> {36};
36 -> {37};
37 -> {38};
38 -> {39} [color=green];
39 -> {40};
38 -> {39};
39 -> {40} [color=green];
40 -> {41};
41 -> {42};
subgraph cluster_8 {
color=red
42 [label="Enter function test_5" style="filled" fillcolor=red];
43 [label="Const: Int(1)"];
44 [label="Postponed enter to lambda"];
43 [label="Enter function test_5" style="filled" fillcolor=red];
44 [label="Const: Int(1)"];
45 [label="Postponed enter to lambda"];
subgraph cluster_9 {
color=blue
45 [label="Enter function anonymousFunction"];
46 [label="Const: String(test_5)"];
47 [label="Access variable R|<local>/it|"];
48 [label="Const: Int(0)"];
49 [label="Operator >"];
50 [label="Exit function anonymousFunction"];
46 [label="Enter function anonymousFunction"];
47 [label="Const: String(test_5)"];
48 [label="Access variable R|<local>/it|"];
49 [label="Const: Int(0)"];
50 [label="Function call: R|<local>/it|.R|kotlin/Int.compareTo|(Int(0))"];
51 [label="Comparison >"];
52 [label="Exit function anonymousFunction"];
}
51 [label="Postponed exit from lambda"];
52 [label="Function call: Int(1).R|kotlin/takeUnless|<R|kotlin/Int|>(predicate = takeUnless@fun <anonymous>(it: R|kotlin/Int|): R|kotlin/Boolean| <kind=EXACTLY_ONCE> )"];
53 [label="Exit function test_5" style="filled" fillcolor=red];
53 [label="Postponed exit from lambda"];
54 [label="Function call: Int(1).R|kotlin/takeUnless|<R|kotlin/Int|>(predicate = takeUnless@fun <anonymous>(it: R|kotlin/Int|): R|kotlin/Boolean| <kind=EXACTLY_ONCE> )"];
55 [label="Exit function test_5" style="filled" fillcolor=red];
}
42 -> {43};
43 -> {44};
44 -> {45};
44 -> {51} [color=red];
45 -> {46};
45 -> {53} [color=red];
46 -> {47};
47 -> {48};
48 -> {49};
49 -> {50};
50 -> {51} [color=green];
50 -> {51};
51 -> {52};
52 -> {53};
52 -> {53} [color=green];
53 -> {54};
54 -> {55};
subgraph cluster_10 {
color=red
54 [label="Enter function myRun" style="filled" fillcolor=red];
55 [label="Function call: R|<local>/block1|.R|FakeOverride<kotlin/Function0.invoke: R|kotlin/Unit|>|()"];
56 [label="Function call: R|<local>/block2|.R|FakeOverride<kotlin/Function0.invoke: R|kotlin/Unit|>|()"];
57 [label="Exit function myRun" style="filled" fillcolor=red];
56 [label="Enter function myRun" style="filled" fillcolor=red];
57 [label="Function call: R|<local>/block1|.R|FakeOverride<kotlin/Function0.invoke: R|kotlin/Unit|>|()"];
58 [label="Function call: R|<local>/block2|.R|FakeOverride<kotlin/Function0.invoke: R|kotlin/Unit|>|()"];
59 [label="Exit function myRun" style="filled" fillcolor=red];
}
54 -> {55};
55 -> {56};
56 -> {57};
57 -> {58};
58 -> {59};
subgraph cluster_11 {
color=red
58 [label="Enter function test_6" style="filled" fillcolor=red];
59 [label="Postponed enter to lambda"];
60 [label="Enter function test_6" style="filled" fillcolor=red];
61 [label="Postponed enter to lambda"];
subgraph cluster_12 {
color=blue
60 [label="Enter function anonymousFunction"];
61 [label="Const: String(test_6_1)"];
62 [label="Exit function anonymousFunction"];
62 [label="Enter function anonymousFunction"];
63 [label="Const: String(test_6_1)"];
64 [label="Exit function anonymousFunction"];
}
63 [label="Postponed exit from lambda"];
64 [label="Postponed enter to lambda"];
65 [label="Postponed exit from lambda"];
66 [label="Postponed enter to lambda"];
subgraph cluster_13 {
color=blue
65 [label="Enter function anonymousFunction"];
66 [label="Const: String(test_6_2)"];
67 [label="Exit function anonymousFunction"];
67 [label="Enter function anonymousFunction"];
68 [label="Const: String(test_6_2)"];
69 [label="Exit function anonymousFunction"];
}
68 [label="Postponed exit from lambda"];
69 [label="Function call: R|/myRun|(myRun@fun <anonymous>(): R|kotlin/Unit| <kind=UNKNOWN> , <L> = myRun@fun <anonymous>(): R|kotlin/Unit| <kind=UNKNOWN> )"];
70 [label="Exit function test_6" style="filled" fillcolor=red];
70 [label="Postponed exit from lambda"];
71 [label="Function call: R|/myRun|(myRun@fun <anonymous>(): R|kotlin/Unit| <kind=UNKNOWN> , <L> = myRun@fun <anonymous>(): R|kotlin/Unit| <kind=UNKNOWN> )"];
72 [label="Exit function test_6" style="filled" fillcolor=red];
}
58 -> {59};
59 -> {60};
59 -> {63} [color=red];
60 -> {62 61};
60 -> {61};
61 -> {62};
62 -> {60};
62 -> {63} [color=green];
61 -> {65} [color=red];
62 -> {64 63};
63 -> {64};
64 -> {65};
64 -> {68} [color=red];
65 -> {67 66};
64 -> {62};
64 -> {65} [color=green];
65 -> {66};
66 -> {67};
67 -> {65};
67 -> {68} [color=green];
66 -> {70} [color=red];
67 -> {69 68};
68 -> {69};
69 -> {70};
69 -> {67};
69 -> {70} [color=green];
70 -> {71};
71 -> {72};
subgraph cluster_14 {
color=red
71 [label="Enter function test_7" style="filled" fillcolor=red];
72 [label="Postponed enter to lambda"];
73 [label="Enter function test_7" style="filled" fillcolor=red];
74 [label="Postponed enter to lambda"];
subgraph cluster_15 {
color=blue
73 [label="Enter function anonymousFunction"];
74 [label="Const: String(test_7_2)"];
75 [label="Exit function anonymousFunction"];
75 [label="Enter function anonymousFunction"];
76 [label="Const: String(test_7_2)"];
77 [label="Exit function anonymousFunction"];
}
76 [label="Postponed exit from lambda"];
77 [label="Postponed enter to lambda"];
78 [label="Postponed exit from lambda"];
79 [label="Postponed enter to lambda"];
subgraph cluster_16 {
color=blue
78 [label="Enter function anonymousFunction"];
79 [label="Const: String(test_7_1)"];
80 [label="Exit function anonymousFunction"];
80 [label="Enter function anonymousFunction"];
81 [label="Const: String(test_7_1)"];
82 [label="Exit function anonymousFunction"];
}
81 [label="Postponed exit from lambda"];
82 [label="Function call: R|/myRun|(block2 = myRun@fun <anonymous>(): R|kotlin/Unit| <kind=UNKNOWN> , block1 = myRun@fun <anonymous>(): R|kotlin/Unit| <kind=UNKNOWN> )"];
83 [label="Exit function test_7" style="filled" fillcolor=red];
83 [label="Postponed exit from lambda"];
84 [label="Function call: R|/myRun|(block2 = myRun@fun <anonymous>(): R|kotlin/Unit| <kind=UNKNOWN> , block1 = myRun@fun <anonymous>(): R|kotlin/Unit| <kind=UNKNOWN> )"];
85 [label="Exit function test_7" style="filled" fillcolor=red];
}
71 -> {72};
72 -> {73};
72 -> {76} [color=red];
73 -> {75 74};
73 -> {74};
74 -> {75};
75 -> {73};
75 -> {76} [color=green];
74 -> {78} [color=red];
75 -> {77 76};
76 -> {77};
77 -> {78};
77 -> {81} [color=red];
78 -> {80 79};
77 -> {75};
77 -> {78} [color=green];
78 -> {79};
79 -> {80};
80 -> {78};
80 -> {81} [color=green];
79 -> {83} [color=red];
80 -> {82 81};
81 -> {82};
82 -> {83};
82 -> {80};
82 -> {83} [color=green];
83 -> {84};
84 -> {85};
subgraph cluster_17 {
color=red
84 [label="Enter function myDummyRun" style="filled" fillcolor=red];
85 [label="Function call: R|<local>/block|.R|FakeOverride<kotlin/Function0.invoke: R|kotlin/Unit|>|()"];
86 [label="Exit function myDummyRun" style="filled" fillcolor=red];
86 [label="Enter function myDummyRun" style="filled" fillcolor=red];
87 [label="Function call: R|<local>/block|.R|FakeOverride<kotlin/Function0.invoke: R|kotlin/Unit|>|()"];
88 [label="Exit function myDummyRun" style="filled" fillcolor=red];
}
84 -> {85};
85 -> {86};
86 -> {87};
87 -> {88};
subgraph cluster_18 {
color=red
87 [label="Enter function test_8" style="filled" fillcolor=red];
88 [label="Postponed enter to lambda"];
89 [label="Postponed exit from lambda"];
90 [label="Function call: R|/myDummyRun|(<L> = myDummyRun@fun <anonymous>(): R|kotlin/Unit|)"];
91 [label="Exit function test_8" style="filled" fillcolor=red];
89 [label="Enter function test_8" style="filled" fillcolor=red];
90 [label="Postponed enter to lambda"];
91 [label="Postponed exit from lambda"];
92 [label="Function call: R|/myDummyRun|(<L> = myDummyRun@fun <anonymous>(): R|kotlin/Unit|)"];
93 [label="Exit function test_8" style="filled" fillcolor=red];
}
87 -> {88};
88 -> {89 89} [color=green];
89 -> {90};
90 -> {91};
90 -> {91 91} [color=green];
91 -> {92};
92 -> {93};
subgraph cluster_19 {
color=red
92 [label="Enter function anonymousFunction" style="filled" fillcolor=red];
93 [label="Const: String(test_8)"];
94 [label="Exit function anonymousFunction" style="filled" fillcolor=red];
94 [label="Enter function anonymousFunction" style="filled" fillcolor=red];
95 [label="Const: String(test_8)"];
96 [label="Exit function anonymousFunction" style="filled" fillcolor=red];
}
92 -> {93};
93 -> {94};
94 -> {95};
95 -> {96};
}
@@ -22,14 +22,14 @@ FILE: callsInPlace.kt
public final fun test_4(): R|kotlin/Unit| {
Int(1).R|kotlin/takeUnless|<R|kotlin/Int|>(<L> = takeUnless@fun <anonymous>(it: R|kotlin/Int|): R|kotlin/Boolean| <kind=EXACTLY_ONCE> {
String(test_4)
^ >(R|<local>/it|, Int(0))
^ CMP(>, R|<local>/it|.R|kotlin/Int.compareTo|(Int(0)))
}
)
}
public final fun test_5(): R|kotlin/Unit| {
Int(1).R|kotlin/takeUnless|<R|kotlin/Int|>(predicate = takeUnless@fun <anonymous>(it: R|kotlin/Int|): R|kotlin/Boolean| <kind=EXACTLY_ONCE> {
String(test_5)
^ >(R|<local>/it|, Int(0))
^ CMP(>, R|<local>/it|.R|kotlin/Int.compareTo|(Int(0)))
}
)
}
@@ -1020,6 +1020,12 @@ class FirRenderer(builder: StringBuilder, private val mode: RenderMode = RenderM
visitCall(operatorCall)
}
override fun visitComparisonExpression(comparisonExpression: FirComparisonExpression) {
print("CMP(${comparisonExpression.operation.operator}, ")
comparisonExpression.compareToCall.accept(this)
print(")")
}
override fun visitComponentCall(componentCall: FirComponentCall) {
componentCall.annotations.renderAnnotations()
componentCall.explicitReceiver.accept(this)
@@ -8,7 +8,7 @@ fun f(): Unit {
x = null
x <!INAPPLICABLE_CANDIDATE!>+<!> 1
x <!INAPPLICABLE_CANDIDATE!>plus<!> 1
x < 1
x <!INAPPLICABLE_CANDIDATE!><<!> 1
<!UNRESOLVED_REFERENCE!>x += 1<!>
x == 1
@@ -29,4 +29,4 @@ fun f(): Unit {
false || y
y && true
y && 1
}
}
@@ -1,6 +1,6 @@
// !WITH_NEW_INFERENCE
fun test() {
if (<!UNRESOLVED_REFERENCE!>x<!> > 0) {
if (<!UNRESOLVED_REFERENCE!>x<!> <!UNRESOLVED_REFERENCE!>><!> 0) {
}
}
}
@@ -13,5 +13,5 @@ public class B {
// FILE: main.kt
fun test() {
B.bar() { it.<!INAPPLICABLE_CANDIDATE!>hashCode<!>() > 0 }
B.bar() { it.<!INAPPLICABLE_CANDIDATE!>hashCode<!>() <!UNRESOLVED_REFERENCE!>><!> 0 }
}
@@ -1,2 +1,2 @@
// !WITH_NEW_INFERENCE
val unwrapped = <!UNRESOLVED_REFERENCE!>some<!><<!UNRESOLVED_REFERENCE!><!UNRESOLVED_REFERENCE!><!UNRESOLVED_REFERENCE!><!UNRESOLVED_REFERENCE!>sdf<!>()()<!><out Any><!>::unwrap<!>
val unwrapped = <!UNRESOLVED_REFERENCE!>some<!><!UNRESOLVED_REFERENCE!><<!><!UNRESOLVED_REFERENCE!><!UNRESOLVED_REFERENCE!><!UNRESOLVED_REFERENCE!><!UNRESOLVED_REFERENCE!>sdf<!>()()<!><out Any><!>::unwrap<!>
@@ -8,9 +8,9 @@ fun composite() {
}
fun html() {
<!SYNTAX!><<!><!UNRESOLVED_REFERENCE!>html<!>><!SYNTAX!><<!><!UNRESOLVED_REFERENCE!>/<!><!UNRESOLVED_REFERENCE!>html<!>><!SYNTAX!><!>
<!SYNTAX!><<!><!UNRESOLVED_REFERENCE!>html<!><!UNRESOLVED_REFERENCE!>><!><!SYNTAX!><<!><!UNRESOLVED_REFERENCE!>/<!><!UNRESOLVED_REFERENCE!>html<!>><!SYNTAX!><!>
}
fun html1() {
<!SYNTAX!><<!><!UNRESOLVED_REFERENCE!>html<!>><!SYNTAX!><<!><!UNRESOLVED_REFERENCE!>/<!><!UNRESOLVED_REFERENCE!>html<!>><!UNRESOLVED_REFERENCE!>html<!>
}
<!SYNTAX!><<!><!UNRESOLVED_REFERENCE!>html<!><!UNRESOLVED_REFERENCE!>><!><!SYNTAX!><<!><!UNRESOLVED_REFERENCE!>/<!><!UNRESOLVED_REFERENCE!>html<!>><!UNRESOLVED_REFERENCE!>html<!>
}
@@ -11,7 +11,7 @@ fun takeFirst(expr: StringBuilder): Char {
fun evaluateArg(expr: CharSequence, numbers: ArrayList<Int>): Int {
if (expr.length == 0) throw Exception("Syntax error: Character expected");
val c = <!INAPPLICABLE_CANDIDATE!>takeFirst<!>(expr)
if (c >= '0' && c <= '9') {
if (c <!UNRESOLVED_REFERENCE!>>=<!> '0' && c <!UNRESOLVED_REFERENCE!><=<!> '9') {
val n = c <!UNRESOLVED_REFERENCE!>-<!> '0'
if (!numbers.contains(n)) throw Exception("You used incorrect number: " + n)
numbers.remove(n)
@@ -3,6 +3,6 @@
// See EA-76890 / KT-10843: NPE during analysis
fun lambda(x : Int?) = x?.<!UNRESOLVED_REFERENCE!>let<!> <!UNRESOLVED_REFERENCE!>l<!> {
y ->
if (y > 0) return@l x
if (y <!UNRESOLVED_REFERENCE!>><!> 0) return@l x
y
}!!
@@ -5,7 +5,7 @@ class A(val x: String?) {
fun foo(other: A) {
when {
x == null && other.x == null -> "1"
x.<!INAPPLICABLE_CANDIDATE!>length<!> > 0 -> "2"
x.<!INAPPLICABLE_CANDIDATE!>length<!> <!UNRESOLVED_REFERENCE!>><!> 0 -> "2"
}
}
}
}
@@ -3,7 +3,7 @@
fun indexOfMax(a: IntArray): Int? {
var maxI: Int? = 0
a.forEachIndexed { i, value ->
if (value >= <!INAPPLICABLE_CANDIDATE!>a[maxI]<!>) {
if (value <!AMBIGUITY!>>=<!> <!INAPPLICABLE_CANDIDATE!>a[maxI]<!>) {
maxI = i
}
else if (value < 0) {
@@ -11,4 +11,4 @@ fun indexOfMax(a: IntArray): Int? {
}
}
return maxI
}
}
@@ -396,6 +396,12 @@ class FirVisualizer(private val firFile: FirFile) : BaseRenderer() {
data.append("operator call ${operatorCall.operation}")
}
override fun visitComparisonExpression(comparisonExpression: FirComparisonExpression, data: StringBuilder) {
data.append("CMP(${comparisonOperator.operation.operator}, ")
comparisonOperator.compareToCall.accept(this, data)
data.append(")")
}
override fun visitTypeOperatorCall(typeOperatorCall: FirTypeOperatorCall, data: StringBuilder) {
//skip rendering for as/as?/is/!is
}