import Lean open Lean Elab Tactic Doc /-! This test ensures that user-facing tactic names shipped with Lean are kept unambiguous. -/ #eval show MetaM Unit from do let firsts ← firstTacticTokens -- Compute a reverse mapping from first tokens to their syntax kinds let mut rev : Std.HashMap String (List Name) := {} for (k, firstTok) in firsts do rev := rev.alter firstTok fun x? => x?.map (k :: ·) |>.getD [k] -- Check each for ambiguity for (firstTok, kindsForToken) in rev do -- Skip kinds that are alternative syntax for some user-facing parser let kindsForToken ← kindsForToken.filterM fun k => do pure <| (Parser.Tactic.Doc.alternativeOfTactic (← getEnv) k).isNone -- If it's ambiguous, log an error. if kindsForToken.length > 1 then let kinds := MessageData.andList <| kindsForToken.map (m!"`{.ofConstName ·}`") logError m!"`{firstTok}` is the ambiguous first token for {kinds}" /-! This test ensures that user-facing tactic names are found for all the tactics that we ship. -/ #eval show MetaM Unit from do let firsts ← firstTacticTokens let some tactics := (Lean.Parser.parserExtension.getState (← getEnv)).categories.find? `tactic | return for (t, ()) in tactics.kinds do if t == ``Lean.Parser.Tactic.nestedTactic then continue unless firsts.contains t do logError m!"Couldn't find the first token for tactic syntax kind {t}" /-! This test spot-checks tactics defined in a few ways to make sure they all have user-facing names: * Defined using `syntax ... : tactic`, both leading and trailing (`intros` and `<;>`) * Defined using `declare_simp_like_tactic` (`simpAutoUnfold`) * Defined with custom user-facing names (`Lean.Parser.Tactic.letrec`) -/ /-- info: (some intro) (some <;>) (some simp!) (some (let rec)) -/ #guard_msgs in #eval show MetaM Unit from do let firsts ← firstTacticTokens IO.println (firsts.get? ``Lean.Parser.Tactic.intro) IO.println (firsts.get? ``Lean.Parser.Tactic.«tactic_<;>_») IO.println (firsts.get? ``Lean.Parser.Tactic.simpAutoUnfold) IO.println (firsts.get? ``Lean.Parser.Tactic.letrec)