feat: disallow patterns with choice nodes
@Kha Patterns with nested "choice" nodes produce counterintuitive behavior, and hard to understand errors. They only work when we have the exact same overloads at macro definition and application time. Here is a funky example ``` syntax [myAdd] term "++":65 term:65 : term -- overloads "++" /- The following `macro_rules` manages to eliminate "choice" node by using the explicitly provided node kind. -/ macro_rules [myAdd] `($a ++ $b) => `($a + $b) check (1:Nat) ++ 2 -- works as expected syntax "FOO!" term : term /- Before this commit, the following pattern was accepted, and it contained a "choice" node for `++`. It is a `myAdd` or `HasAppend.append`. Now, this kind of pattern is rejected since it contains a nested "choice" -/ macro_rules `(FOO! $a ++ $b) => `($a ++ $b) /- Before this commit, the following command worked because it contained a "choice" node similar to the one at macro definition time. -/ check FOO! [1, 2] ++ [2, 3] -- Now, we have 3 overloads for "++". syntax [myAppend] term "++":65 term:65 : term -- The `macro_rules` fails here. ``` This commit fixes this weird behavior by disallowing "choice" nodes in patterns.
This commit is contained in:
parent
4e580e78bc
commit
145bd50903
2 changed files with 12 additions and 2 deletions
|
|
@ -330,8 +330,11 @@ alts ← alts.getArgs.getSepElems.mapM $ fun alt => do {
|
|||
pat ← if pats.getArgs.size == 1 then pure $ pats.getArg 0
|
||||
else throwError stx "match_syntax: expected exactly one pattern per alternative";
|
||||
let pat := if pat.isOfKind `Lean.Parser.Term.stxQuot then pat.setArg 1 $ elimAntiquotChoices $ pat.getArg 1 else pat;
|
||||
let rhs := alt.getArg 2;
|
||||
pure ([pat], rhs)
|
||||
match pat.find? $ fun stx => stx.getKind == choiceKind with
|
||||
| some choiceStx => throwError choiceStx "invalid pattern, nested syntax has multiple interpretations"
|
||||
| none =>
|
||||
let rhs := alt.getArg 2;
|
||||
pure ([pat], rhs)
|
||||
};
|
||||
-- letBindRhss (compileStxMatch stx [discr]) alts.toList []
|
||||
compileStxMatch stx [discr] alts.toList
|
||||
|
|
|
|||
|
|
@ -750,6 +750,13 @@ match stx.isTermId? relaxed with
|
|||
| some (id, opt) => if opt.isNone then some id else none
|
||||
| none => none
|
||||
|
||||
partial def findAux (p : Syntax → Bool) : Syntax → Option Syntax
|
||||
| stx@(Syntax.node _ args) => if p stx then some stx else args.findSome? findAux
|
||||
| stx => if p stx then some stx else none
|
||||
|
||||
def find? (stx : Syntax) (p : Syntax → Bool) : Option Syntax :=
|
||||
findAux p stx
|
||||
|
||||
end Syntax
|
||||
end Lean
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue