lean4-htt/tests/elab/constructor_as_variable.lean
Garmelon 08eb78a5b2
chore: switch to new test/bench suite (#12590)
This PR sets up the new integrated test/bench suite. It then migrates
all benchmarks and some related tests to the new suite. There's also
some documentation and some linting.

For now, a lot of the old tests are left alone so this PR doesn't become
even larger than it already is. Eventually, all tests should be migrated
to the new suite though so there isn't a confusing mix of two systems.
2026-02-25 13:51:53 +00:00

169 lines
5.1 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: Using `MyProd.construct` would be valid:
[apply] `MyProd.construct`
-/
#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: Using one of these would be valid:
[apply] `List.Sublist.cons`
[apply] `Lean.Grind.AC.Seq.cons`
[apply] `List.Lex.cons`
[apply] `List.Perm.below.cons`
[apply] `List.Lex.below.cons`
[apply] `List.Pairwise.below.cons`
[apply] `List.cons`
[apply] `List.Sublist.below.cons`
[apply] `List.Perm.cons`
[apply] `List.Pairwise.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: Using one of these would be valid:
[apply] `List.Sublist.cons`
[apply] `Lean.Grind.AC.Seq.cons`
[apply] `List.Lex.cons`
[apply] `List.Perm.below.cons`
[apply] `List.Lex.below.cons`
[apply] `List.Pairwise.below.cons`
[apply] `List.cons`
[apply] `List.Sublist.below.cons`
[apply] `List.Perm.cons`
[apply] `List.Pairwise.cons`
[apply] `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