18 Commits

Author SHA1 Message Date
Brian Norman b2041e0927 [FIR] Disable data flow from in-place lambdas
There are many complications with the current design of passing data
from within in-place lambdas to surrounding code. Solving these
complications will involve more time to investigation than is available
within the K2 release. So we are disabling passing type statement
information from lambdas for the time being until more time can be
devoted to a more complete solution.

^KT-60958 Fixed
^KT-63530 Fixed
2023-12-14 16:40:27 +00:00
Brian Norman 0881910a1b [FIR] Rewind DFA after call arguments for correct receiver smartcasting
^KT-63709 Fixed
2023-12-08 14:32:22 +00:00
Brian Norman b55fda0c55 [FIR] Create CFG for files to track top-level property initialization
In order to properly analyze top-level property initialization, a
control-flow graph must be created for FirFiles. This change adds the
foundation for the file CFG and updates body resolve to create the CFG.
Checking the CFG for proper initialization is separated into a following
change to ease code review.

KT-56683
2023-08-31 12:50:52 +00:00
pyos e86b87fe0b Test: FIR CFA: fix the names of some nodes 2023-01-10 15:40:52 +02:00
pyos 54f32a6fba Test: FIR CFA: index nodes in rendering order 2023-01-10 15:40:49 +02:00
pyos faf0129a5d Test: FIR CFA: sort edges by style & target node id 2023-01-10 15:40:46 +02:00
Yan Zhulanow d652dc620c [FE] Preserve legacy contract description calls in bodies
^KT-55231 Fixed
^KTIJ-21012 Fixed
2022-12-26 11:46:58 +00:00
Dmitriy Novozhilov b174bb8844 [FIR] Update testdata after introducing FirResolvedErrorReference 2022-12-15 12:12:19 +00:00
pyos 664a70ec13 FIR DFA: split flow for postponed lambdas from a single node
This removes the need for hacks around the order in which function
call arguments are visited, fixes called-in-place lambda arguments
for augmented assignment operators, and makes CFG dumps a bit prettier.
2022-12-08 10:19:34 +00:00
pyos c4c05f5248 FIR CFG: remove ordering from control flow through in-place lambdas
Old graph:

  arg -> lambda enter -> ... -> lambda exit -> lambda enter -> ... ->
   -> lambda exit -> call

New graph:

  arg -+-> lambda enter -> ... -> lambda exit -+-> call
       \-> lambda enter -> ... -> lambda exit -/
2022-12-08 10:19:31 +00:00
pyos a9be27e330 FIR CFG: add union nodes
Quick quiz:

 Q: In a CFG, what does `a -> b -> c -> d` mean?
 A: `a`, then `b`, then `c`, then `d`.

 Q: In a CFG, what does `a -> b -> d; a -> c -> d` mean?
 A: `a`, then `b` or `c`, then `d`.

 Q: So how do you encode "a, then (b, then c) or (c, then b), then d`?
 A: You can't.

Problem is, you need to, because that's what `a; run2({ b }, { c }); d`
does when `run2` has a contract that it calls both its lambda arguments
in-place: `shuffle(listOf(block1, block2)).forEach { it() }` is a
perfectly valid implementation for it, as little sense as that makes.

So that's what union nodes solve. When a node implements
`UnionNodeMarker`, its inputs are interpreted as "all visited in some
order" instead of the normal "one of the inputs is visited".

Currently this is used for data flow. It *should* also be used for
control flow, but it isn't. But it should be. But that's not so easy.

BTW, `try` exit is NOT a union node; although lambdas in one branch can
be completed according to types' of lambdas in another, data does not
flow between the branches anyway (since we don't know how much of the
`try` executed before jumping into `catch`, and `catch`es are mutually
exclusive) so a `try` expression is more like `when` than a function
call with called-in-place-exactly-once arguments. The fact that
`exitTryExpression` used `processUnionOfArguments` in a weird way
should've hinted at that, but now we know for certain.
2022-12-08 10:19:29 +00:00
pyos 99bebfa183 FIR DFA: merge non-conflicting aliases from union flows
E.g. after `f({ x = a }, { x })`, if `f` calls both lambdas in-place,
`x` should be aliased to `a` even though only one path does that.
2022-12-08 10:19:29 +00:00
pyos 3392e066df FIR DFA: add more called-in-place tests 2022-12-08 10:19:27 +00:00
pyos 3436535e7a FIR DFA: deprioritize branches with no reassignments in flow unions
callBothLambdas({ x = "..." }, { x is Int })
  // the assignment always executes, so x is String | (String & Int);
  // the latter is always a subtype of the former so it can be ignored
2022-11-22 15:44:27 +00:00
Simon Ogorodnik 513af2dfbc FIR. Refactor smart-cast representation in FIR tree
Make smart-casts non-transparent expression without delegation
to underlying FirQualifiedAccessExpression, as children delegation in
fir tree has unclear semantics
Remove two different kinds of tree nodes for smart-casts
2022-08-15 21:46:11 +00:00
pyos 8214e4f806 FIR CFG: check lambda concurrency by data flow, not control flow
var p: String? = something
    if (p != null) {
      foo(
        run { p = null; n() },
        // This lambda executes strictly after the one above by CFG,
        // but data flow for type inference comes from before the call
        // so p would get smartcasted if not forbidden.
	run { p.length; 123 }
      )
    }
2022-07-11 18:11:30 +03:00
pyos 82731802ee FIR CFG: add one more test case 2022-07-11 18:11:30 +03:00
pyos c2ae74c7cd FIR CFG: when unifying flows, group statements by assignment
Consider a function `run2` that has 2 lambda arguments called in place.
We don't know the order in which they're called, so here:

    var x: Any? = something
    run2(
      { x = null },
      { x as String },
    )
    // <--

it's not correct to simply `&&` the statements together, as that would
produce `x is Nothing? && x is String && x is Any?`. Instead, statements
should be grouped by assignment first, and different groups are `||`-ed.
This means in the above example we now get `x is Nothing? || (x is Any?
&& x is String)` == `x is String?`.
2022-06-15 20:05:50 +00:00