7474PATCH_MARKER_BEGIN = "-- BEGIN expose_report diagnostics patch"
7575PATCH_MARKER_END = "-- END expose_report diagnostics patch"
7676
77- # The extra LeanOptions lines inserted into `mathlibLeanOptions`.
77+ # Files that fail to elaborate when `diagnostics=true` is enabled globally.
78+ # We turn diagnostics off in each one for the duration of the build, then
79+ # restore the original source. Four are `#guard_msgs` mismatches caused by
80+ # the extra `[diag]` info messages; the fifth is an `aesop`/`naturality`
81+ # tactic failure that empirically also goes away with diagnostics off.
82+ DIAGNOSTICS_OFF_FILES : list [str ] = [
83+ "Mathlib/Tactic/Linter/ValidatePRTitle.lean" ,
84+ "Mathlib/Order/Interval/Lex.lean" ,
85+ "Mathlib/Tactic/NormNum/Ordinal.lean" ,
86+ "Mathlib/Probability/ConditionalProbability.lean" ,
87+ "Mathlib/CategoryTheory/Discrete/Basic.lean" ,
88+ ]
89+ FILE_PATCH_LINE = (
90+ "-- expose_report: locally disable diagnostics so this file builds "
91+ "under global `diagnostics=true`\n set_option diagnostics false\n "
92+ )
93+
94+ # Diagnostics options are inserted into `mathlibLeanOptions`. This DOES
95+ # affect Lake's olean hash, so the build rebuilds Mathlib from scratch. The
96+ # tradeoff is necessary: `weakLeanArgs` doesn't change the hash, but Lake
97+ # then sees the existing oleans as up-to-date and skips re-elaboration —
98+ # no re-elaboration means no diagnostics output. After this script
99+ # finishes, run `lake exe cache get` to restore cached oleans (their
100+ # unchanged hashes are still on the cache server).
78101PATCH_BLOCK = f""" { PATCH_MARKER_BEGIN }
79102 ⟨`diagnostics, true⟩,
80103 ⟨`diagnostics.threshold, (0 : Nat)⟩,
81104 { PATCH_MARKER_END }
82105"""
83106
84- # Insertion anchor inside `mathlibLeanOptions := #[ ... ]`. We insert *after*
85- # this line (which has no trailing comment, so preserving trailing text is
86- # not an issue).
107+ # Insertion anchor inside `mathlibLeanOptions := #[ ... ]`.
87108ANCHOR = " ⟨`autoImplicit, false⟩,\n "
88109
89110
90111def patch_lakefile () -> str :
91- """Insert the diagnostics options into mathlibLeanOptions. Returns the
92- original contents ( for restoration) ."""
112+ """Insert the diagnostics weakLeanArgs into the mathlib package config.
113+ Returns the original contents for restoration."""
93114 original = LAKEFILE .read_text ()
94115 if PATCH_MARKER_BEGIN in original :
95116 raise RuntimeError (
@@ -109,6 +130,42 @@ def restore_lakefile(original: str) -> None:
109130 LAKEFILE .write_text (original )
110131
111132
133+ def patch_diagnostics_off_files () -> dict [str , str ]:
134+ """Insert `set_option diagnostics false` after the imports of each file
135+ in `DIAGNOSTICS_OFF_FILES`. Returns originals for restoration.
136+
137+ Insertion point: the line *after* the last `import` / `public import`
138+ line of the file. Works for both module-mode files (which have
139+ `module` followed by imports) and non-module files. The copyright
140+ comment block stays at the top.
141+ """
142+ originals : dict [str , str ] = {}
143+ for rel in DIAGNOSTICS_OFF_FILES :
144+ path = REPO_ROOT / rel
145+ text = path .read_text ()
146+ originals [rel ] = text
147+ if FILE_PATCH_LINE in text :
148+ continue
149+ lines = text .splitlines (keepends = True )
150+ last_import = - 1
151+ for i , line in enumerate (lines ):
152+ stripped = line .lstrip ()
153+ if stripped .startswith ("import " ) or stripped .startswith ("public import " ):
154+ last_import = i
155+ if last_import < 0 :
156+ raise RuntimeError (f"no import line found in { rel } ; "
157+ f"don't know where to insert set_option" )
158+ insert_at = last_import + 1
159+ new_lines = lines [:insert_at ] + ["\n " , FILE_PATCH_LINE ] + lines [insert_at :]
160+ path .write_text ("" .join (new_lines ))
161+ return originals
162+
163+
164+ def restore_diagnostics_off_files (originals : dict [str , str ]) -> None :
165+ for rel , text in originals .items ():
166+ (REPO_ROOT / rel ).write_text (text )
167+
168+
112169def run_build (log_path : Path ) -> int :
113170 """Stream `lake build Mathlib` to stdout and to `log_path`. Returns exit."""
114171 log_path .parent .mkdir (parents = True , exist_ok = True )
@@ -248,11 +305,13 @@ def main() -> int:
248305
249306 rc = 0
250307 if not args .skip_build :
251- original = patch_lakefile ()
308+ original_lakefile = patch_lakefile ()
309+ original_files = patch_diagnostics_off_files ()
252310 try :
253311 rc = run_build (args .log )
254312 finally :
255- restore_lakefile (original )
313+ restore_lakefile (original_lakefile )
314+ restore_diagnostics_off_files (original_files )
256315 if rc != 0 :
257316 print (f"[build_with_diagnostics] lake build exited { rc } ; "
258317 f"log preserved at { args .log } . "
0 commit comments