lean4-htt/tests/lean/run/constructor_as_variable.lean
jrr6 4759506bcf
chore: use note and hint' for message addenda (#8980)
This PR improves the consistency of error message formatting by
rendering addenda of several existing error messages as labeled notes
and hints.
2025-06-27 15:16:01 +00:00

166 lines
4.9 KiB
Text
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/-!
Testing for linter.constructorNameAsVariable
This linter checks warns when a bound variable's name is the name of a constructor of the variable's
type, which probably indicates a namespace mistake, but can be otherwise hard to find.
The linter is designed to interact well with the suggestions provided when a non-constructor is used
where a constructor would be expected in a pattern, so that users who don't know Lean namespaces
will be guided to the right qualified names. Thus, both are tested together here.
-/
set_option linter.unusedVariables false
inductive A where
| x | y
-- Test that the linter works even in the presence of errors (making it useful for confused new
-- users)
/--
warning: Local variable 'x' resembles constructor 'A.x' - write '.x' (with a dot) or 'A.x' to use the constructor.
Note: This linter can be disabled with `set_option linter.constructorNameAsVariable false`
-/
#guard_msgs(drop error, warning) in
def f : A → Unit
| x => _
-- Show that the linter also works when there are no errors
/--
warning: Local variable 'x' resembles constructor 'A.x' - write '.x' (with a dot) or 'A.x' to use the constructor.
Note: This linter can be disabled with `set_option linter.constructorNameAsVariable false`
-/
#guard_msgs(warning) in
def g : A → Unit
| x => ()
-- Check that turning it off works
#guard_msgs in
set_option linter.constructorNameAsVariable false in
def g' : A → Unit
| x => ()
-- Avoid false positives
#guard_msgs in
def h : A → Unit
| z => ()
-- Check that it works for let-bindings
/--
warning: Local variable 'x' resembles constructor 'A.x' - write '.x' (with a dot) or 'A.x' to use the constructor.
Note: This linter can be disabled with `set_option linter.constructorNameAsVariable false`
---
warning: Local variable 'y' resembles constructor 'A.y' - write '.y' (with a dot) or 'A.y' to use the constructor.
Note: This linter can be disabled with `set_option linter.constructorNameAsVariable false`
-/
#guard_msgs in
def i (a : A × A) : Unit :=
let (x, y) := a
()
/--
warning: Local variable 'x' resembles constructor 'A.x' - write '.x' (with a dot) or 'A.x' to use the constructor.
Note: This linter can be disabled with `set_option linter.constructorNameAsVariable false`
-/
#guard_msgs in
def i' : Unit :=
let x : A := .x
()
-- Check that it works in tactic proofs
/--
warning: Local variable 'x' resembles constructor 'A.x' - write '.x' (with a dot) or 'A.x' to use the constructor.
Note: This linter can be disabled with `set_option linter.constructorNameAsVariable false`
-/
#guard_msgs in
theorem j (a : A ⊕ A) : True := by
cases a with
| inl x => trivial
| inr z => trivial
-- Top-level names do not trigger the lint
#guard_msgs in
def x : A := A.x
/-! Test the interaction with the invalid match pattern error messages -/
inductive MyProd where
| construct : Nat → Nat → MyProd
/--
error: Invalid pattern: Expected a constructor or constant marked with `[match_pattern]`
Hint: 'MyProd.construct' is similar
-/
#guard_msgs in
def ctorSuggestion1 (pair : MyProd) : Nat :=
match pair with
| construct x y => y
-- This test is a realistic situation if a user doesn't know how Lean namespaces work
/--
error: Invalid pattern: Expected a constructor or constant marked with `[match_pattern]`
Hint: These are similar:
'List.Lex.below.cons',
'List.Lex.cons',
'List.Pairwise.below.cons',
'List.Pairwise.cons',
'List.Perm.below.cons',
'List.Perm.cons',
'List.Sublist.below.cons',
'List.Sublist.cons',
'List.cons'
---
warning: Local variable 'nil' resembles constructor 'List.nil' - write '.nil' (with a dot) or 'List.nil' to use the constructor.
Note: This linter can be disabled with `set_option linter.constructorNameAsVariable false`
-/
#guard_msgs in
def ctorSuggestion2 (list : List α) : Nat :=
match list with
| nil => 0
| cons x xs => 1 + ctorSuggestion2 xs
-- Adding another `cons` also adds a suggestion
inductive StringList : Type where
| nil
| cons (s : String) (ss : StringList)
/--
error: Invalid pattern: Expected a constructor or constant marked with `[match_pattern]`
Hint: These are similar:
'List.Lex.below.cons',
'List.Lex.cons',
'List.Pairwise.below.cons',
'List.Pairwise.cons',
'List.Perm.below.cons',
'List.Perm.cons',
'List.Sublist.below.cons',
'List.Sublist.cons',
'List.cons',
'StringList.cons'
---
warning: Local variable 'nil' resembles constructor 'List.nil' - write '.nil' (with a dot) or 'List.nil' to use the constructor.
Note: This linter can be disabled with `set_option linter.constructorNameAsVariable false`
-/
#guard_msgs in
def ctorSuggestion3 (list : List α) : Nat :=
match list with
| nil => 0
| cons x xs => 1 + ctorSuggestion2 xs
-- There isn't always a suggestion to provide
/-- error: Invalid pattern: Expected a constructor or constant marked with `[match_pattern]` -/
#guard_msgs in
def ctorNoSuggestion (x : α) :=
match x with
| notAConstructor a b c => 42