FIR: Support FirComparisonOperator in body transformers and DFA
^KT-31163 In Progress
This commit is contained in:
@@ -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 -----------------------------------
|
||||
|
||||
|
||||
+5
-1
@@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
-1
@@ -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()
|
||||
|
||||
+7
@@ -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)
|
||||
}
|
||||
|
||||
+9
@@ -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
@@ -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|))
|
||||
|
||||
+3
-3
@@ -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|)
|
||||
|
||||
+2
-2
@@ -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
-3
@@ -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
-3
@@ -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|)
|
||||
|
||||
+1
-1
@@ -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 -> {
|
||||
|
||||
+102
-98
@@ -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) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -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 }
|
||||
}
|
||||
|
||||
Vendored
+1
-1
@@ -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
|
||||
}!!
|
||||
|
||||
Vendored
+2
-2
@@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
-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
|
||||
}
|
||||
}
|
||||
|
||||
+6
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user