Appearance
| 1 | namespace Syntax.Trees.Statements is | |
| 2 | use Source; | |
| 3 | ||
| 4 | // One clause of an `if let` binding — a single | |
| 5 | // `pattern[: T] = scrutinee[ /\ guard]` slice. A REFUTABLE_BINDING | |
| 6 | // holds an ordered list of these; each clause's scrutinee compiles | |
| 7 | // under the narrowed environment produced by the prior clauses. | |
| 8 | // | |
| 9 | // Not visited as an AST node in its own right — the surrounding | |
| 10 | // REFUTABLE_BINDING walks the clause's pieces (narrow_type_expression | |
| 11 | // / scrutinee / pattern / guard) directly, and the semantic and IL | |
| 12 | // passes iterate clauses and drive each clause's work inline. | |
| 13 | class REFUTABLE_BINDING_CLAUSE: Trees.Node is | |
| 14 | scrutinee: Expressions.Expression public; | |
| 15 | narrow_type_expression: TypeExpressions.TypeExpression? public; | |
| 16 | pattern: Variables.VariableLeft public; | |
| 17 | guard: Expressions.Expression? public; | |
| 18 | ||
| 19 | // True for the leaf-name shorthand (`if let x.y.z?` / | |
| 20 | // `if let x.y: T`), where the pattern's name was inferred | |
| 21 | // from the path's last member. The formatter prints the | |
| 22 | // shorthand back rather than the expanded form. | |
| 23 | is_inferred_name: bool public; | |
| 24 | ||
| 25 | init( | |
| 26 | location: LOCATION, | |
| 27 | scrutinee: Expressions.Expression, | |
| 28 | narrow_type_expression: TypeExpressions.TypeExpression?, | |
| 29 | pattern: Variables.VariableLeft, | |
| 30 | guard: Expressions.Expression? | |
| 31 | ) is | |
| 32 | super.init(location); | |
| 33 | ||
| 34 | ||
| 35 | self.scrutinee = scrutinee; | |
| 36 | self.narrow_type_expression = narrow_type_expression; | |
| 37 | self.pattern = pattern; | |
| 38 | self.guard = guard; | |
| 39 | si | |
| 40 | si | |
| 41 | ||
| 42 | // The binding shape of an `if let` arm. Semantically equivalent | |
| 43 | // to `isa V(scrutinee) /\ <bind pattern from scrutinee>` per clause | |
| 44 | // when a narrow target is given, and to a `?` (presence) test plus | |
| 45 | // a bind from the unwrapped value when it is not. A multi-clause | |
| 46 | // binding short-circuits left-to-right: every clause's test and | |
| 47 | // optional guard must succeed for the then-arm to fire. | |
| 48 | // | |
| 49 | // The semantic and IL passes drive narrowing and binding directly | |
| 50 | // off this node — the scrutinee remains visible to flow narrowing | |
| 51 | // and to the destructure's DESTRUCTURE_CONSTRAINT path, which is | |
| 52 | // what gives `if let` inference parity with the `isa V(t) ... let | |
| 53 | // p = t` shape for recursive lambdas. | |
| 54 | class REFUTABLE_BINDING: Trees.Node is | |
| 55 | clauses: Collections.LIST[REFUTABLE_BINDING_CLAUSE] public; | |
| 56 | ||
| 57 | init( | |
| 58 | location: LOCATION, | |
| 59 | clauses: Collections.Iterable[REFUTABLE_BINDING_CLAUSE] | |
| 60 | ) is | |
| 61 | super.init(location); | |
| 62 | ||
| 63 | ||
| 64 | self.clauses = Collections.LIST[REFUTABLE_BINDING_CLAUSE](clauses); | |
| 65 | ||
| 66 | assert self.clauses.count > 0 else "refutable binding has no clauses"; | |
| 67 | si | |
| 68 | ||
| 69 | accept(visitor: Visitor) is | |
| 70 | visitor.visit(self); | |
| 71 | si | |
| 72 | ||
| 73 | walk(visitor: Visitor) is | |
| 74 | if !visitor.pre(self) then | |
| 75 | for c in clauses do | |
| 76 | if let c.narrow_type_expression? then | |
| 77 | narrow_type_expression.walk(visitor); | |
| 78 | fi | |
| 79 | ||
| 80 | c.scrutinee.walk(visitor); | |
| 81 | c.pattern.walk(visitor); | |
| 82 | ||
| 83 | if let c.guard? then | |
| 84 | guard.walk(visitor); | |
| 85 | fi | |
| 86 | od | |
| 87 | fi | |
| 88 | ||
| 89 | accept(visitor); | |
| 90 | si | |
| 91 | si | |
| 92 | si |