unified: Support OrPattern bindings

This commit is contained in:
Asger F
2026-07-03 09:21:21 +02:00
parent 891e244116
commit 036ed04eee
2 changed files with 47 additions and 5 deletions

View File

@@ -213,12 +213,39 @@ private module LocalNameBindingInput implements LocalNameBindingInputSig<Locatio
)
}
predicate declInScope(AstNode definingNode, string name, AstNode scope) {
bindingContext(definingNode, scope) and
(
definingNode.(NamePattern).getIdentifier().getValue() = name
/**
* Gets the nearest enclosing `OrPattern` to which variable bindings in `p` should be lifted.
*
* To ensure that `case .foo(let x), .bar(let x)` result in a single definition for
* the variable `x`, the `OrPattern` becomes the `definingNode` for `x`.
*
* At the moment no further checks are needed since the Swift compiler enforces that
* variable names bound in any branch are bound in all branches.
*/
private OrPattern getEnclosingOrPattern(Pattern p) {
p = result.getPattern(_)
or
exists(Pattern parent | result = getEnclosingOrPattern(parent) |
p = parent.(ConstructorPattern).getElement(_).getPattern()
or
definingNode.(Identifier).getValue() = name
p = parent.(TuplePattern).getElement(_).getPattern()
)
}
predicate declInScope(AstNode definingNode, string name, AstNode scope) {
exists(AstNode pattern |
bindingContext(pattern, scope) and
(
pattern.(NamePattern).getIdentifier().getValue() = name
or
pattern.(Identifier).getValue() = name
) and
(
definingNode = getEnclosingOrPattern(pattern)
or
not exists(getEnclosingOrPattern(pattern)) and
definingNode = pattern
)
)
}

View File

@@ -334,3 +334,18 @@ func t37() {
print(x) // $ access=x3
}
}
enum E38 {
case a(Int)
case b(Int)
}
// Switch with a multi-pattern case that binds 'x' in each pattern
// Note: the testing framework does not make it possible to name the 'x' variable in this case.
func t38(value: E38) {
switch value { // $ access=value
case .a(let x), // $ access=x
.b(let x): // $ access=x
print(x) // $ access=x
}
}