@@ -77,6 +77,75 @@ public meta section
7777
7878open Lean Meta Elab Tactic
7979
80+ /-- Configuration for the `convert` family of tactics.
81+ This is `Congr!.Config` with different, less aggressive, defaults.
82+
83+ To elaborate config options for `convert`, use `Convert.elabConfig` which chooses
84+ between `Convert.CheapConfig` and `Convert.ExpensiveConfig` based on other flags.
85+ -/
86+ structure Convert.CheapConfig extends Congr!.Config where
87+ postTransparency := .reducible
88+
89+ /-- Internal elaborator for `Convert.CheapConfig`: use `Convert.elabConfig` instead. -/
90+ declare_config_elab Convert.elabCheapConfig Convert.CheapConfig
91+
92+ /-- A configuration option that makes `convert` do the sorts of aggressive unfoldings that `congr`
93+ does while also similarly preventing `convert` from considering partial applications or congruences
94+ between different functions being applied.
95+
96+ Note that `convert (config := .unfoldSameFun)` and `convert! (config := .unfoldSameFun)`
97+ currently do the same thing since `.unfoldSameFun` runs at default transparency always.
98+ This may change in the future, if `convert!` affects other options too.
99+ -/
100+ abbrev Convert.CheapConfig.unfoldSameFun : Convert.CheapConfig :=
101+ { Congr!.Config.unfoldSameFun with }
102+
103+ /-- Configuration for the `convert!` family of tactics.
104+ This is `Convert.CheapConfig` (used by `convert` without exclamation mark) with different,
105+ more aggressive, defaults.
106+
107+ To elaborate config options for `convert`, use `Convert.elabConfig` which chooses
108+ between `Convert.CheapConfig` and `Convert.ExpensiveConfig` based on other flags.
109+
110+ We separate out the two structures to allow the user to explicitly set options in the call, so for
111+ example the following call runs at `.instances` transparency.
112+ ```
113+ convert! (postTransparency := .instances)
114+ ```
115+ -/
116+ structure Convert.ExpensiveConfig extends Convert.CheapConfig where
117+ -- TODO: also enable this in the future? (For backwards compatibility we won't do so right now.)
118+ -- preTransparency := .default
119+ -- transparency := .default
120+ postTransparency := .default
121+
122+ /-- Internal elaborator for `Convert.ExpensiveConfig`: use `Convert.elabConfig` instead. -/
123+ declare_config_elab Convert.elabExpensiveConfig Convert.ExpensiveConfig
124+
125+ /-- A configuration option that makes `convert!` do the sorts of aggressive unfoldings that `congr`
126+ does while also similarly preventing `convert!` from considering partial applications or congruences
127+ between different functions being applied.
128+
129+ Note that `convert (config := .unfoldSameFun)` and `convert! (config := .unfoldSameFun)`
130+ currently do the same thing since `.unfoldSameFun` runs at default transparency always.
131+ This may change in the future, if `convert!` affects other options too.
132+ -/
133+ abbrev Convert.ExpensiveConfig.unfoldSameFun : Convert.ExpensiveConfig :=
134+ { Congr!.Config.unfoldSameFun with }
135+
136+ /-- Configuration elaborator for the `convert`/`convert!` family of tactics.
137+
138+ If `expensive` is true, we're elaborating for `convert!`, and will configure to run at default
139+ transparency (unless explicitly overridden by the user saying e.g. `(transparency := .instances)`.)
140+ -/
141+ def Convert.elabConfig (expensive : Bool) (stx : Syntax) : TacticM Congr!.Config := do
142+ -- Implement overridable fields by choosing to elaborate one of two structures,
143+ -- which have different defaults (that can later be overridden by the user).
144+ if expensive then
145+ pure { ← Convert.elabExpensiveConfig stx with }
146+ else
147+ pure { ← Convert.elabCheapConfig stx with }
148+
80149/--
81150Close the goal `g` using `Eq.mp v e`,
82151where `v` is a metavariable asserting that the type of `g` and `e` are equal.
@@ -132,8 +201,7 @@ pattern-matched, like `rintro` would, using the `with` keyword.
132201See also `convert_to t`, where `t` specifies the expected type, instead of a proof term of type `t`.
133202In other words, `convert_to t` works like `convert (?_ : t)`. Both tactics use the same options.
134203
135- * `convert! e` uses default transparency when solving side goals. This is currently the same
136- behaviour as `convert`, but `convert` will use reducible transparency in the future.
204+ * `convert! e` uses default transparency, rather than reducible, when solving side goals.
137205* `convert ← e` creates equality goals in the opposite direction (with the goal type on the right).
138206* `convert e using n`, where `n` is a positive numeral, controls the depth with which congruence is
139207 applied. For example, if the main goal is `⊢ Prime (n + n + 1)` and `e : Prime (2 * n + 1)`, then
@@ -156,6 +224,7 @@ example {n : ℕ} (e : Prime (2 * n + 1)) :
156224 ring
157225
158226-- `convert` can fail where `exact` succeeds.
227+ def p (n : ℕ) := True
159228example (h : p 0) : p 1 := by
160229 fail_if_success
161230 convert h -- fails, left-over goal 1 = 0
@@ -200,9 +269,9 @@ def elabTermForConvert (term : Syntax) (expectedType? : Option Expr) :
200269 return t
201270
202271elab_rules : tactic
203- | `(tactic| convert $[!]? $cfg $[←%$sym]? $term $[using $n]? $[with $ps?*]?) =>
272+ | `(tactic| convert $[!%$expensive ]? $cfg $[←%$sym]? $term $[using $n]? $[with $ps?*]?) =>
204273 withMainContext do
205- let config ← Congr! .elabConfig (mkOptionalNode cfg)
274+ let config ← Convert .elabConfig expensive.isSome cfg
206275 let patterns := (ps?.getD #[]).toList
207276 let expectedType ← mkFreshExprMVar (mkSort (← getLevel (← getMainTarget)))
208277 let (e, gs) ← elabTermForConvert term expectedType
@@ -221,8 +290,7 @@ pattern-matched, like `rintro` would, using the `with` keyword.
221290`convert e`, where `e` is a term of type `t`, uses `e` to close the new main goal. In other words,
222291`convert e` works like `convert_to t; refine e`. Both tactics use the same options.
223292
224- * `convert_to! t` uses default transparency when solving side goals. This is currently the same
225- behaviour as `convert_to`, but `convert_to` will use reducible transparency in the future.
293+ * `convert_to! t` uses default transparency, rather than reducible, when solving side goals.
226294* `convert_to ty at h` changes the type of the local hypothesis `h` to `ty`. If later local
227295 hypotheses or the goal depend on `h`, then `convert_to t at h` may leave a copy of `h`.
228296* `convert_to ← t` creates equality goals in the opposite direction (with the original goal type on
@@ -238,7 +306,7 @@ pattern-matched, like `rintro` would, using the `with` keyword.
238306* `convert_to (config := cfg) t` uses the configuration options in `cfg` to control the congruence
239307 rules (see `Congr!.Config`).
240308 -/
241- syntax (name := convertTo) "convert_to" Lean.Parser.Tactic.optConfig " ←" ? ppSpace term
309+ syntax (name := convertTo) "convert_to" ( "!" )? Lean.Parser.Tactic.optConfig " ←" ? ppSpace term
242310 (" using " num)? (" with" (ppSpace colGt rintroPat)*)? (Parser.Tactic.location)? : tactic
243311
244312@ [tactic_alt convertTo]
@@ -247,13 +315,13 @@ syntax (name := convert_to!) "convert_to!" Lean.Parser.Tactic.optConfig " ←"?
247315
248316macro_rules
249317| `(tactic| convert_to! $cfg $[←%$l]? $t $[using $n]? $[with $w]? $[$loc]?) =>
250- `(tactic| convert_to $cfg $[←%$l]? $t:term $[using $n]? $[with $w]? $[$loc]?)
318+ `(tactic| convert_to ! $cfg $[←%$l]? $t:term $[using $n]? $[with $w]? $[$loc]?)
251319
252320elab_rules : tactic
253- | `(tactic| convert_to $cfg $[←%$sym]? $newType $[using $n]?
321+ | `(tactic| convert_to $[!%$expensive]? $ cfg $[←%$sym]? $newType $[using $n]?
254322 $[with $ps?*]? $[$loc?:location]?) => do
255323 let n : ℕ := n |>.map (·.getNat) |>.getD 1
256- let config ← Congr! .elabConfig cfg
324+ let config ← Convert .elabConfig expensive.isSome cfg
257325 let patterns := (ps?.getD #[]).toList
258326 withLocation (expandOptLocation (mkOptionalNode loc?))
259327 (atLocal := fun fvarId ↦ do
@@ -279,8 +347,7 @@ into new goals, using the hole's name, if any, as the goal case name.
279347Like `congr!`, `convert_to` introduces variables while applying congruence rules. These can be
280348pattern-matched, like `rintro` would, using the `with` keyword.
281349
282- * `ac_change! t` uses default transparency when solving side goals. This is currently the same
283- behaviour as `ac_change`, but `ac_change` will use reducible transparency in the future.
350+ * `ac_change! t` uses default transparency, rather than reducible, when solving side goals.
284351* `ac_change t using n`, where `n` is a positive numeral, controls the depth with which congruence
285352 is applied. For example, if the main goal is `⊢ Prime ((a * b + 1) + c)`,
286353 then `ac_change Prime ((1 + a * b) + c) using 2` solves the side goals, and
@@ -305,5 +372,4 @@ macro_rules
305372| `(tactic| ac_change! $t $[using $n]?) =>
306373 `(tactic| convert_to! $t:term $[using $n]? <;> try ac_rfl)
307374
308-
309375end Mathlib.Tactic
0 commit comments