Skip to content

Commit

Permalink
explain control flow a bit
Browse files Browse the repository at this point in the history
  • Loading branch information
sandersn committed Jun 16, 2023
1 parent e71a6c8 commit 8683f92
Showing 1 changed file with 38 additions and 1 deletion.
39 changes: 38 additions & 1 deletion codebase/compiler/Codebase-Compiler-Binder.md
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,44 @@ TODO: Finish this

## Control Flow

TODO: Missing completely
Like symbols, control flow involves a walk of the tree, setting some information for certain kinds of nodes and skipping all other nodes.
For control flow, nodes that can narrow or otherwise introduce type information are the relevant ones.
Containers and declarations are the same as for symbol binding, so those concepts are reused.
Declarations introduce type information; containers form the scope where type information is relevant.
Other nodes may narrow, so they also interact with control flow.

The control flow graph is a directed acyclic graph; that means each relevant node points to its antecedents (parents).
Specifically, each node can have a `flowNode`; this flow node has a `kind` and one or more `antecedents`.
As the binder walks the tree, `bindWorker` assigns the current flow node to specific nodes that can introduce type information.
Specific nodes that affect control flow alter the current flow node, such as `bindWhileStatement`.

Here's an example:

```ts
function f(x: string | number) {
if (typeof x === 'string') {
return x
} else {
console.log(x)
}
return x
}
```

Here, the binder creates a `FlowStart` for `x: string | number`.
Then when it walks the `if/else`, it creates two `FlowCondition` nodes, each with an antecedent of the original `FlowStart`.
The two nodes correspond to the `then` body—where the condition `typeof x === "string"` is true—and the `else` body—where it's false.
For `return x` inside the `then` body, it creates an Unreachable flow node.
It also creates a post-if `FlowLabel` that joins the control flow between the two branches of the conditional.

During checking of various references of `x`, control flow analysis will walk up the tree until it finds a control flow node, at which point it runs back through the control flow graph until it reaches a `FlowStart`.
For example, to check the first `x` reference in `typeof x === "string"`, it walks up *past* the `if` — the condition is not contained in the flow of the `then` or the `else` bodies — and reaches FlowStart.
The type here is `string | number`.
But in the first `return x`, the first flow node it reaches is the `FlowCondition` for the `then` branch of the if/else.
That check narrows `string | number` to `string`.
Finally, the last `return x` starts with the post-if flow node, which unions the types that result from the `then` and `else` branches.
But because the `then` branch returns, it doesn't contribute anything to the union; the resulting type is just `number`.


## Emit flags

Expand Down

0 comments on commit 8683f92

Please sign in to comment.