|
| 1 | +-- Thank you to Damiano Testa |
| 2 | +-- https://leanprover.zulipchat.com/#narrow/channel/270676-lean4/topic/restricting.20axioms/near/501743343 |
| 3 | + |
| 4 | +import Lean.Util.CollectAxioms |
| 5 | +import Mathlib.Tactic.DeclarationNames |
| 6 | + |
| 7 | +/-! |
| 8 | +# The "detectClassical" linter |
| 9 | +
|
| 10 | +The "detectClassical" linter emits a warning on declarations that depend on the `Classical.choice` |
| 11 | +axiom. |
| 12 | +-/ |
| 13 | + |
| 14 | +open Lean Elab Command |
| 15 | + |
| 16 | +namespace Katydid.Std.Linter |
| 17 | + |
| 18 | +/-- |
| 19 | +The "detectClassical" linter emits a warning on declarations that depend on the `Classical.choice` |
| 20 | +axiom. |
| 21 | +-/ |
| 22 | +register_option linter.detectClassical : Bool := { |
| 23 | + defValue := true |
| 24 | + descr := "enable the detectClassical linter" |
| 25 | +} |
| 26 | + |
| 27 | +/-- |
| 28 | +The `linter.verbose.detectClassical` option is a flag to make the `detectClassical` linter emit |
| 29 | +a confirmation on declarations that depend *not* on the `Classical.choice` axiom. |
| 30 | +-/ |
| 31 | +register_option linter.verbose.detectClassical : Bool := { |
| 32 | + defValue := false |
| 33 | + descr := "enable the verbose setting for the detectClassical linter" |
| 34 | +} |
| 35 | + |
| 36 | +namespace DetectClassical |
| 37 | + |
| 38 | +@[inherit_doc Katydid.Std.Linter.linter.detectClassical] |
| 39 | +def detectClassicalLinter : Linter where run := withSetOptionIn fun stx ↦ do |
| 40 | + unless Linter.getLinterValue linter.detectClassical (← getOptions) do |
| 41 | + return |
| 42 | + if (← get).messages.hasErrors then |
| 43 | + return |
| 44 | + let d := (stx.getPos?.getD default) |
| 45 | + let nmsd := (← Mathlib.Linter.getNamesFrom d) |
| 46 | + let nms := nmsd.filter (! ·.getId.isInternal) |
| 47 | + let verbose? := Linter.getLinterValue linter.verbose.detectClassical (← getOptions) |
| 48 | + for constStx in nms do |
| 49 | + let constName := constStx.getId |
| 50 | + let axioms ← collectAxioms constName |
| 51 | + if axioms.isEmpty then |
| 52 | + if verbose? then |
| 53 | + logInfoAt constStx m!"'{constName}' does not depend on any axioms" |
| 54 | + return |
| 55 | + if !axioms.contains `Classical.choice then |
| 56 | + if verbose? then |
| 57 | + logInfoAt constStx |
| 58 | + m!"'{constName}' is non-classical and depends on axioms: {axioms.toList}" |
| 59 | + else |
| 60 | + Linter.logLint linter.detectClassical constStx |
| 61 | + m!"'{constName}' depends on 'Classical.choice' on axioms: {axioms.toList}" |
| 62 | + |
| 63 | +initialize addLinter detectClassicalLinter |
| 64 | + |
| 65 | +end DetectClassical |
| 66 | + |
| 67 | +end Katydid.Std.Linter |
0 commit comments