Skip to content

feat: haveI/letI tactic linter#41657

Open
JovanGerb wants to merge 10 commits into
leanprover-community:masterfrom
JovanGerb:Jovan-haveI-letI-linter
Open

feat: haveI/letI tactic linter#41657
JovanGerb wants to merge 10 commits into
leanprover-community:masterfrom
JovanGerb:Jovan-haveI-letI-linter

Conversation

@JovanGerb

@JovanGerb JovanGerb commented Jul 12, 2026

Copy link
Copy Markdown
Contributor

This PR implements a variation on the linter that was written by Claude in #41562. It suggest to use have/let instead of haveI/letI whenever the goal is a proposition.

See also https://leanprover.zulipchat.com/#narrow/channel/287929-mathlib4/topic/surprising.20have.2FhaveI.20kernel.20phenomenon/with/609718493


Open in Gitpod

@JovanGerb JovanGerb changed the title feat: haveI/letI` tactic linter feat: haveI/letI tactic linter Jul 12, 2026
@github-actions

github-actions Bot commented Jul 12, 2026

Copy link
Copy Markdown

PR summary 2197c33724

Import changes for modified files

No significant changes to the import graph

Import changes for all files
Files Import difference
../mathlib-ci/scripts/pr_summary/import_trans_difference.sh all
There are 8208 files with changed transitive imports taking up over 357980 characters: this is too many to display!
You can run this locally from your mathlib4 directory:

git clone https://github.com/leanprover-community/mathlib-ci.git ../mathlib-ci


Declarations diff (regex)

+ runHaveI
+ runLetI

You can run this locally as follows
## from your `mathlib4` directory:
git clone https://github.com/leanprover-community/mathlib-ci.git ../mathlib-ci

## summary with just the declaration names:
../mathlib-ci/scripts/pr_summary/declarations_diff.sh <optional_commit>

## more verbose report:
../mathlib-ci/scripts/pr_summary/declarations_diff.sh long <optional_commit>

The doc-module for scripts/pr_summary/declarations_diff.sh in the mathlib-ci repository contains some details about this script.

Declarations diff (Lean)

Lean-aware diff — post-build, computed from the Lean environment (commit 2197c33).

  • +3 new declarations
  • −0 removed declarations
+Mathlib.Linter.HaveILetI.linter.style.haveILetI
+Mathlib.Linter.HaveILetI.tacticHaveI__
+Mathlib.Linter.HaveILetI.tacticLetI__

No changes to strong technical debt.

No changes to weak technical debt.

Current commit 2197c33724
Reference commit f98b1aa39a

This script lives in the mathlib-ci repository. To run it locally, from your mathlib4 directory:

git clone https://github.com/leanprover-community/mathlib-ci.git ../mathlib-ci
../mathlib-ci/scripts/reporting/technical-debt-metrics.sh pr_summary
  • The relative value is the weighted sum of the differences with weight given by the inverse of the current value of the statistic.
  • The absolute value is the relative value divided by the total sum of the inverses of the current values (i.e. the weighted average of the differences).

@github-actions github-actions Bot added the t-linter Linter label Jul 12, 2026

@Vierkantor Vierkantor left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good to me: although there was the suggestion to merge this with the let-for-Prop linter, it seems there is no obvious way to merge the two implementations (apart from putting them in the same file maybe?). The implementation is a lot neater than my idea of digging around in infotrees with TacticAnalysis :)

I'll wait with delegating until everything builds and @thorimur has had a chance to comment.

Comment thread Mathlib/Tactic/Linter/HaveLetI.lean Outdated
Comment thread Mathlib/Tactic/Linter/HaveLetI.lean Outdated
Comment thread Mathlib/Tactic/Linter/HaveLetI.lean Outdated
Comment thread Mathlib/Tactic/Linter/HaveLetI.lean Outdated
mathlib-bors Bot pushed a commit that referenced this pull request Jul 14, 2026
…oal is a prop (#41708)

Using `haveI`/`letI` for instances in proofs is a holdover from Lean 3, and is unnecessary in Lean 4. As explained by @Vierkantor on Zulip [here](https://leanprover.zulipchat.com/#narrow/channel/287929-mathlib4/topic/letI.2FhaveI.20linter/near/609781158):

> Historical note: a lot of the `haveI`/`letI` usage is a remnant of Lean 3 times, where the `I` stood for Instances: the old versions of the `have`/`let` tactics would not add the new variable to the list of available instances, and you'd need `haveI`/`letI` to force an update to the instance cache and make them visible. In our modern Lean 4 age, basic `have`/`let` already make the instance available and `I` instead only stands for Inline. But the old `haveI` got ported to the new `haveI` and so there is a bit of a superstition that we have to keep using `haveI` and `letI` for instances.

(Note that inlining can change IR for compiled defs, so we don't change those.)

Try-this statements produced by #41657; applied mechanically by running `scripts/runSkimmer.sh`.

Then, Mathlib.CategoryTheory.Galois.Basic was fixed up manually: it turned out that the `haveI`'s triggering the linter were completely unnecessary, which might be why universe issues came about when the linter suggested turning them into `have`s.

Cleaning up term-mode `haveI`/`letI` is left for another PR.

Co-authored-by: @JovanGerb
mpacholski pushed a commit to mpacholski/mathlib4 that referenced this pull request Jul 16, 2026
…oal is a prop (leanprover-community#41708)

Using `haveI`/`letI` for instances in proofs is a holdover from Lean 3, and is unnecessary in Lean 4. As explained by @Vierkantor on Zulip [here](https://leanprover.zulipchat.com/#narrow/channel/287929-mathlib4/topic/letI.2FhaveI.20linter/near/609781158):

> Historical note: a lot of the `haveI`/`letI` usage is a remnant of Lean 3 times, where the `I` stood for Instances: the old versions of the `have`/`let` tactics would not add the new variable to the list of available instances, and you'd need `haveI`/`letI` to force an update to the instance cache and make them visible. In our modern Lean 4 age, basic `have`/`let` already make the instance available and `I` instead only stands for Inline. But the old `haveI` got ported to the new `haveI` and so there is a bit of a superstition that we have to keep using `haveI` and `letI` for instances.

(Note that inlining can change IR for compiled defs, so we don't change those.)

Try-this statements produced by leanprover-community#41657; applied mechanically by running `scripts/runSkimmer.sh`.

Then, Mathlib.CategoryTheory.Galois.Basic was fixed up manually: it turned out that the `haveI`'s triggering the linter were completely unnecessary, which might be why universe issues came about when the linter suggested turning them into `have`s.

Cleaning up term-mode `haveI`/`letI` is left for another PR.

Co-authored-by: @JovanGerb
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

t-linter Linter

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants