From a3b79b7df7de4465cd02107cbe7325a1422de59a Mon Sep 17 00:00:00 2001 From: Michael Rothgang Date: Sat, 12 Jul 2025 10:15:34 +0200 Subject: [PATCH 001/106] feat: custom elaborators for differential geometry Add two sets of custom elaborators for differential geometry, to - infer the model with corners in `MDifferentiable{WithinAt,At,On}` or `ContMDiff{WithinAt,At,On}` expressions from the local context, and provide shorter notation in that setting - convert a fibre bundle section from a dependent section to a function into the total space, making working with differentiability of sections of fibre bundles less cumbersome This was [discussed on zulip](...), to overall broad consensus. This code has substantial tests and has been tried in the branch in #26221 (uncovering minor issues, but not substantial ones). The implementation itself is of prototype quality and will be cleaned up in the future. Once it is more robust, more differential geometry files can be converted to use it. ----------- I agree that merging not fully polished code is not ideal, but propose doing so for two reasons: - the work in #26221 used these elaborators extensively (to test them). Reverting those changes, merging the code, only to re-apply them is not a good use of time. Merging this PR now enables merging the work in #26221 soon. - the feature is clearly useful and not going away: in the files that use it, it works well already. Holding off on further adopting, but merging it now seems like a good compromise. --- Mathlib.lean | 2 + Mathlib/Geometry/Manifold/Elaborators.lean | 386 ++++++++++++++++++ Mathlib/Geometry/Manifold/Traces.lean | 17 + .../DifferentialGeometry/Elaborators.lean | 301 ++++++++++++++ 4 files changed, 706 insertions(+) create mode 100644 Mathlib/Geometry/Manifold/Elaborators.lean create mode 100644 Mathlib/Geometry/Manifold/Traces.lean create mode 100644 MathlibTest/DifferentialGeometry/Elaborators.lean diff --git a/Mathlib.lean b/Mathlib.lean index 15b19b247f7c10..95d15a8275037f 100644 --- a/Mathlib.lean +++ b/Mathlib.lean @@ -3893,6 +3893,7 @@ import Mathlib.Geometry.Manifold.ContMDiffMFDeriv import Mathlib.Geometry.Manifold.ContMDiffMap import Mathlib.Geometry.Manifold.DerivationBundle import Mathlib.Geometry.Manifold.Diffeomorph +import Mathlib.Geometry.Manifold.Elaborators import Mathlib.Geometry.Manifold.GroupLieAlgebra import Mathlib.Geometry.Manifold.Instances.Icc import Mathlib.Geometry.Manifold.Instances.Real @@ -3923,6 +3924,7 @@ import Mathlib.Geometry.Manifold.Riemannian.PathELength import Mathlib.Geometry.Manifold.Sheaf.Basic import Mathlib.Geometry.Manifold.Sheaf.LocallyRingedSpace import Mathlib.Geometry.Manifold.Sheaf.Smooth +import Mathlib.Geometry.Manifold.Traces import Mathlib.Geometry.Manifold.VectorBundle.Basic import Mathlib.Geometry.Manifold.VectorBundle.FiberwiseLinear import Mathlib.Geometry.Manifold.VectorBundle.Hom diff --git a/Mathlib/Geometry/Manifold/Elaborators.lean b/Mathlib/Geometry/Manifold/Elaborators.lean new file mode 100644 index 00000000000000..c49814b40dc9b7 --- /dev/null +++ b/Mathlib/Geometry/Manifold/Elaborators.lean @@ -0,0 +1,386 @@ +/- +Copyright (c) 2025 Patrick Massot. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Patrick Massot, Michael Rothgang +-/ +import Mathlib.Geometry.Manifold.VectorBundle.Tangent +import Mathlib.Geometry.Manifold.BumpFunction +import Mathlib.Geometry.Manifold.VectorBundle.MDifferentiable +import Mathlib.Geometry.Manifold.Traces + +/-! +# Elaborators for differential geometry + +This file defines custom elaborators for differential geometry, to allow for more compact notation. +There are two classes of elaborators. The first provides more compact notation for differentiability +and continuous differentiability on manifolds, including inference of the model with corners. +They allow writing +- `MDiff f` for `MDifferentiable I J f` +- `MDiffAt f x` for `MDifferentiableAt I J f x` +- `MDiff[u] f` for `MDifferentiableOn I J f u` +- `MDiffAt[u] f` for `DifferentiableWithinAt I J f u x` +- `CMDiff n f` for `ContMDiff I J n f` +- `CMDiffAt n f x` for `ContMDiffAt I J n f x` +- `CMDiff[u] n f` for `ContMDiffOn I J n f u` +- `CMDiffAt[u] n f` for `ContMDiffWithinAt I J n f u x`. + +In each of these cases, the models with corners are inferred from the domain and codomain of `f`. +The search for models with corners uses the local context and is (almost) only syntactic, hence +hopefully fast enough to always run. + +Secondly, this space adds an elaborator to ease working with sections in a fibre bundle, +converting a section `s : Π x : M, Π V x` to a non-dependent function into the total space of the +bundle. +```lean +-- omitted: let `V` be a fibre bundle over `M` +variable {σ : Π x : M, V x} {σ' : (x : E) → Trivial E E' x} {s : E → E'} + +-- outputs `fun x ↦ TotalSpace.mk' F x (σ x) : M → TotalSpace F V` +#check T% σ + +-- outputs `fun x ↦ TotalSpace.mk' E' x (σ' x) : E → TotalSpace E' (Trivial E E')` +-- Note how the name of the bound variable `x` is preserved. +#check T% σ' + +-- outputs `fun a ↦ TotalSpace.mk' E' a (s a) : E → TotalSpace E' (Trivial E E')` +#check T% s +``` + +These elaborators can be combined: `CMDiffAt[u] n (T% s) x` + +**Warning.** These elaborators are a proof of concept; the implementation should be considered a +prototype. Don't rewrite all of mathlib to use it just yet. Notable bugs and limitations include +the following. + +## TODO +- extend the feature to infer e.g. models with corners on product manifolds + (this has to make a guess, hence cannot always be correct: but it could make the guess that + is correct 90% of the time) +- fix pretty-printing: currently, the `commandStart` linter expects some different formatting +- better error messages: forgetting e.g. the `T%` elaborator yields cryptic errors +- make all these elaborators scoped to the `Manifold` namespace +- further testing and fixing of edge cases +- add test for the difference between `CMDiff` and `ContMDiff%` (and decide on one behaviour) +- added tests for all of the above + +-/ + +open scoped Bundle Manifold ContDiff + +section +open Lean Meta Elab Tactic +open Mathlib.Tactic + +/-- Try to infer the universe of an expression `e` -/ +def _root_.Lean.Expr.getUniverse (e : Expr) : TermElabM (Level) := do + if let .sort (.succ u) ← inferType e >>= instantiateMVars then + return u + else + throwError m!"Could not find universe of {e}." + +/-- Call `mkApp` recursively with 12 arguments -/ +@[match_pattern] def mkApp12 (f a b c d e g e₁ e₂ e₃ e₄ e₅ e₆ : Expr) := + mkApp6 (mkApp6 f a b c d e g) e₁ e₂ e₃ e₄ e₅ e₆ + +/-- Elaborator for sections in a fibre bundle: converts a section as a dependent function +to a non-dependent function into the total space. This handles the cases of +- sections of a trivial bundle +- vector fields on a manifold (i.e., sections of the tangent bundle) +- sections of an explicit fibre bundle +- turning a bare function `E → E'` into a section of the trivial bundle `Bundle.Trivial E E'` + +This elaborator operates purely syntactically, by analysing the local contexts for suitable +hypothesis for the above cases. Therefore, it is (hopefully) fast enough to always run. +-/ +-- TODO: document how this elaborator works, any gotchas, etc. +elab "T% " t:term : term => do + let e ← Term.elabTerm t none + let etype ← inferType e >>= instantiateMVars + match etype with + | .forallE x base (mkApp3 (.const `Bundle.Trivial _) E E' _) _ => + trace[TotalSpaceMk] "Section of a trivial bundle" + if E == base then + return ← withLocalDecl x BinderInfo.default base fun x ↦ do + let body ← mkAppM ``Bundle.TotalSpace.mk' #[E', x, .app e x] + mkLambdaFVars #[x] body + | .forallE x base (mkApp12 (.const `TangentSpace _) _k _ E _ _ _H _ _I _M _ _ _x) _ => + trace[TotalSpaceMk] "Vector field" + return ← withLocalDecl x BinderInfo.default base fun x ↦ do + let body ← mkAppM ``Bundle.TotalSpace.mk' #[E, x, .app e x] + mkLambdaFVars #[x] body + | .forallE x base (.app V _) _ => + trace[TotalSpaceMk] "Section of a bundle as a dependent function" + for decl in ← getLocalHyps do + let decltype ← inferType decl >>= instantiateMVars + match decltype with + | mkApp7 (.const `FiberBundle _) _ F _ _ E _ _ => + if E == V then + return ← withLocalDecl x BinderInfo.default base fun x ↦ do + let body ← mkAppM ``Bundle.TotalSpace.mk' #[F, x, .app e x] + mkLambdaFVars #[x] body + | _ => pure () + | .forallE x src tgt _ => + trace[TotalSpaceMk] "Section of a trivial bundle as a non-dependent function" + let us ← src.getUniverse + let ut ← tgt.getUniverse + let triv_bundle := mkAppN (.const `Bundle.Trivial [us, ut]) #[src, tgt] + return ← withLocalDecl x BinderInfo.default src fun x ↦ do + let body := mkAppN (.const ``Bundle.TotalSpace.mk' [us, ut, ut]) + #[src, triv_bundle, tgt, x, .app e x] + mkLambdaFVars #[x] body + | _ => pure () + return e + +/-- Try to find a `ModelWithCorners` instance on an expression `e`, using the local context +to infer the expected type. This supports the following cases: +- the model with corners on the total space of a vector bundle +- a model with corners on a manifold +- the trivial model `𝓘(𝕜, E)` on a normed space +- if the above are not found, try to find a `NontriviallyNormedField` instance on the type of `e`, + and if successful, return `𝓘(𝕜)`. + +Further cases can be added as necessary. +This implementation is not maximally robust yet, but already useful. +-/ +-- FIXME: better failure when trying to find a `NormedField` instance +def find_model (e : Expr) (baseInfo : Option (Expr × Expr) := none) : TermElabM Expr := do + trace[MDiffElab] m!"Searching a model for: {e}" + if let mkApp3 (.const `Bundle.TotalSpace _) _ F V := e then + if let mkApp12 (.const `TangentSpace _) _k _ _E _ _ _H _ I M _ _ _x := V then + trace[MDiffElab] m!"This is the total space of the tangent bundle of {M}" + let srcIT : Term ← PrettyPrinter.delab I + let resTerm : Term ← `(ModelWithCorners.prod $srcIT ModelWithCorners.tangent $srcIT) + let res ← Term.elabTerm resTerm none + trace[MDiffElab] m!"Found model: {res}" + return res + + trace[MDiffElab] m!"This is a total space with fiber {F}" + if let some (_src, srcI) := baseInfo then + let mut K : Expr := default + let mut normedSpaceInst : Expr := default + let mut Kok : Bool := false + for decl in ← getLocalHyps do + let decltype ← inferType decl >>= instantiateMVars + match decltype with + | mkApp4 (.const `NormedSpace _) K' E _ _ => + if E == F then + K := K' + trace[MDiffElab] m!"{F} is a normed field over {K}" + normedSpaceInst := decl + Kok := true + | _ => pure () + if Kok then break + unless Kok do throwError + m!"Couldn’t find a normed space structure on {F} in local context" + let kT : Term ← PrettyPrinter.delab K + let srcIT : Term ← PrettyPrinter.delab srcI + let FT : Term ← PrettyPrinter.delab F + let iTerm : Term ← `(ModelWithCorners.prod $srcIT 𝓘($kT, $FT)) + let I ← Term.elabTerm iTerm none + trace[MDiffElab] m!"Found model: {I}" + return I + + else + throwError "Having a TotalSpace as source is not yet supported" + let mut H : Expr := default + let mut Hok : Bool := false + let mut K : Expr := default + let mut normedSpaceInst : Expr := default + let mut Kok : Bool := false + for decl in ← getLocalHyps do + let decltype ← inferType decl >>= instantiateMVars + match decltype with + | mkApp4 (.const `ChartedSpace _) H' _ M _ => + if M == e then + H := H' + trace[MDiffElab] m!"H is: {H}" + Hok := true + | mkApp4 (.const `NormedSpace _) K' E _ _ => + if E == e then + K := K' + trace[MDiffElab] m!"Field is: {K}" + normedSpaceInst := decl + Kok := true + | _ => pure () + if Hok || Kok then break + if Kok then + let eT : Term ← PrettyPrinter.delab e + let eK : Term ← PrettyPrinter.delab K + let iTerm : Term ← `(𝓘($eK, $eT)) + let I ← Term.elabTerm iTerm none + trace[MDiffElab] m!"Found model: {I}" + return I + -- let uK ← K.getUniverse + -- let normedFieldK ← synthInstance (.app (.const `NontriviallyNormedField [uK]) K) + -- trace[MDiffElab] m!"NontriviallyNormedField instance is: {normedFieldK}" + -- let ue ← e.getUniverse + -- let normedGroupE ← synthInstance (.app (.const `NormedAddCommGroup [ue]) e) + -- trace[MDiffElab] m!"NormedAddCommGroup instance is: {normedGroupE}" + -- return mkAppN (.const `modelWithCornersSelf [uK, ue]) + -- #[K, normedFieldK, e, normedGroupE, normedSpaceInst] + else if Hok then + for decl in ← getLocalHyps do + let decltype ← inferType decl >>= instantiateMVars + match decltype with + | mkApp7 (.const `ModelWithCorners _) _ _ _ _ _ H' _ => + if H' == H then + trace[MDiffElab] m!"Found model: {decl}" + return decl + | _ => pure () + -- throwError m!"Couldn’t find models with corners with H = {H}" + else + trace[MDiffElab] m!"Hoping {e} is a normed field" + let eT : Term ← PrettyPrinter.delab e + let iTerm : Term ← `(𝓘($eT, $eT)) + let I ← Term.elabTerm iTerm none + trace[MDiffElab] m!"Found model: {I}" + return I + + throwError "Couldn’t find models with corners" + +-- TODO: scope all these elaborators to the `Manifold` namespace + +/-- `MDiffAt[s] f x` elaborates to `MDifferentiableWithinAt I J f s x`, +trying to determine `I` and `J` from the local context. +The argument x can be omitted. -/ +elab:max "MDiffAt[" s:term:arg "]" f:term:arg : term => do + let es ← Term.elabTerm s none + let ef ← Term.elabTerm f none + let etype ← inferType ef >>= instantiateMVars + let _estype ← inferType ef >>= instantiateMVars + match etype with + | .forallE _ src tgt _ => + let srcI ← find_model src + let tgtI ← find_model tgt (src, srcI) + -- TODO: check that `estype` and src are compatible/the same! + return ← mkAppM ``MDifferentiableWithinAt #[srcI, tgtI, ef, es] + | _ => throwError m!"Term {ef} is not a function." + +/-- `MDiffAt f x` elaborates to `MDifferentiableAt I J f x`, +trying to determine `I` and `J` from the local context. +The argument `x` can be omitted. -/ +elab:max "MDiffAt" t:term:arg : term => do + let e ← Term.elabTerm t none + let etype ← inferType e >>= instantiateMVars + match etype with + | .forallE _ src tgt _ => + let srcI ← find_model src + let tgtI ← find_model tgt (src, srcI) + return ← mkAppM ``MDifferentiableAt #[srcI, tgtI, e] + | _ => throwError m!"Term {e} is not a function." + +-- FIXME: remove in favour of MDiffAt (once that one is scoped) +elab:max "MDifferentiableAt%" t:term:arg : term => do + let e ← Term.elabTerm t none + let etype ← inferType e >>= instantiateMVars + match etype with + | .forallE _ src tgt _ => + let srcI ← find_model src + let tgtI ← find_model tgt (src, srcI) + return ← mkAppM ``MDifferentiableAt #[srcI, tgtI, e] + | _ => throwError m!"Term {e} is not a function." + +/-- `MDiff[s] f` elaborates to `MDifferentiableOn I J f`, +trying to determine `I` and `J` from the local context. -/ +elab:max "MDiff[" s:term:arg "]" t:term:arg : term => do + let es ← Term.elabTerm s none + let et ← Term.elabTerm t none + let _estype ← inferType es >>= instantiateMVars + let etype ← inferType et >>= instantiateMVars + match etype with + | .forallE _ src tgt _ => + let srcI ← find_model src + let tgtI ← find_model tgt (src, srcI) + -- TODO: check that `estype` and src are compatible/the same! + return ← mkAppM ``MDifferentiableOn #[srcI, tgtI, et, es] + | _ => throwError m!"Term {et} is not a function." + +/-- `MDiff f` elaborates to `MDifferentiable I J f`, +trying to determine `I` and `J` from the local context. -/ +elab:max "MDiff" t:term:arg : term => do + let e ← Term.elabTerm t none + let etype ← inferType e >>= instantiateMVars + match etype with + | .forallE _ src tgt _ => + let srcI ← find_model src + let tgtI ← find_model tgt (src, srcI) + return ← mkAppM ``MDifferentiable #[srcI, tgtI, e] + | _ => throwError m!"Term {e} is not a function." + +-- TODO: say something about the expected type of `n` being in ℕ or WithTop ℕ∞! +/-- `CMDiffAt[s] n f` elaborates to `ContMDiffWithinAt I J n f s`, +trying to determine `I` and `J` from the local context. -/ +elab:max "CMDiffAt[" s:term:arg "]" nt:term:arg f:term:arg : term => do + let es ← Term.elabTerm s none + let ef ← Term.elabTerm f none + let wtn ← Term.elabTerm (← `(WithTop ℕ∞)) none + let ne ← Term.elabTerm nt wtn + let _estype ← inferType es >>= instantiateMVars + let eftype ← inferType ef >>= instantiateMVars + match eftype with + | .forallE _ src tgt _ => + let srcI ← find_model src + let tgtI ← find_model tgt (src, srcI) + -- TODO: check `estype` and src are compatible + return ← mkAppM ``ContMDiffWithinAt #[srcI, tgtI, ne, ef, es] + | _ => throwError m!"Term {ef} is not a function." + +/-- `CMDiffAt n f` elaborates to `ContMDiffAt I J n f s` +trying to determine `I` and `J` from the local context. -/ +elab:max "CMDiffAt" nt:term:arg t:term:arg : term => do + let e ← Term.elabTerm t none + let wtn ← Term.elabTerm (← `(WithTop ℕ∞)) none + let ne ← Term.elabTermEnsuringType nt wtn + let etype ← inferType e >>= instantiateMVars + match etype with + | .forallE _ src tgt _ => + let srcI ← find_model src + let tgtI ← find_model tgt (src, srcI) + return ← mkAppM ``ContMDiffAt #[srcI, tgtI, ne, e] + | _ => throwError m!"Term {e} is not a function." + +/-- `CMDiff[s] n f` elaborates to `ContMDiffOn I J n f s`, +trying to determine `I` and `J` from the local context. -/ +elab:max "CMDiff[" s:term:arg "]" nt:term:arg f:term:arg : term => do + let es ← Term.elabTerm s none + let ef ← Term.elabTerm f none + let wtn ← Term.elabTerm (← `(WithTop ℕ∞)) none + let ne ← Term.elabTermEnsuringType nt wtn + let _estype ← inferType es >>= instantiateMVars + let eftype ← inferType ef >>= instantiateMVars + match eftype with + | .forallE _ src tgt _ => + let srcI ← find_model src + let tgtI ← find_model tgt (src, srcI) + -- TODO: check `estype` and src are compatible + return ← mkAppM ``ContMDiffOn #[srcI, tgtI, ne, ef, es] + | _ => throwError m!"Term {ef} is not a function." + +/-- `CMDiff n f` elaborates to `ContMDiff I J n f`, +trying to determine `I` and `J` from the local context. -/ +elab:max "CMDiff" nt:term:arg t:term:arg : term => do + let e ← Term.elabTerm t none + let wtn ← Term.elabTerm (← `(WithTop ℕ∞)) none + let ne ← Term.elabTerm nt wtn + let etype ← inferType e >>= instantiateMVars + match etype with + | .forallE _ src tgt _ => + let srcI ← find_model src + let tgtI ← find_model tgt (src, srcI) + return ← mkAppM ``ContMDiff #[srcI, tgtI, ne, e] + | _ => throwError m!"Term {e} is not a function." + +-- TODO: remove in favour of CMDiff (after aligning their behaviour and adding a test for it!) +elab:max "ContMDiff%" nt:term:arg t:term:arg : term => do + let e ← Term.elabTerm t none + let wtn ← Term.elabTerm (← `(WithTop ℕ∞)) none + let ne ← Term.elabTermEnsuringType nt wtn + let etype ← inferType e >>= instantiateMVars + match etype with + | .forallE _ src tgt _ => + let srcI ← find_model src + let tgtI ← find_model tgt (src, srcI) + return ← mkAppM ``ContMDiff #[srcI, tgtI, ne, e] + | _ => throwError m!"Term {e} is not a function." + +end diff --git a/Mathlib/Geometry/Manifold/Traces.lean b/Mathlib/Geometry/Manifold/Traces.lean new file mode 100644 index 00000000000000..e364b875fb2cdc --- /dev/null +++ b/Mathlib/Geometry/Manifold/Traces.lean @@ -0,0 +1,17 @@ +/- +Copyright (c) 2025 Patrick Massot. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Patrick Massot, Michael Rothgang +-/ +import Lean.Util.Trace + +/-! +# Trace classes for differential geometry elaborators + +TODO: add a more complete doc-string + +-/ +open Lean + +initialize registerTraceClass `TotalSpaceMk +initialize registerTraceClass `MDiffElab diff --git a/MathlibTest/DifferentialGeometry/Elaborators.lean b/MathlibTest/DifferentialGeometry/Elaborators.lean new file mode 100644 index 00000000000000..352b7873e7a6f0 --- /dev/null +++ b/MathlibTest/DifferentialGeometry/Elaborators.lean @@ -0,0 +1,301 @@ +import Mathlib.Geometry.Manifold.Elaborators + +import Mathlib.Geometry.Manifold.VectorBundle.SmoothSection +import Mathlib.Geometry.Manifold.VectorBundle.Tangent +import Mathlib.Geometry.Manifold.MFDeriv.FDeriv +import Mathlib.Geometry.Manifold.MFDeriv.SpecificFunctions +import Mathlib.Geometry.Manifold.BumpFunction +import Mathlib.Geometry.Manifold.VectorBundle.MDifferentiable +import Mathlib.Geometry.Manifold.VectorField.LieBracket + +set_option pp.unicode.fun true + +open Bundle Filter Function Topology + +open scoped Bundle Manifold ContDiff + +variable {𝕜 : Type*} [NontriviallyNormedField 𝕜] + +section + +variable {E : Type*} [NormedAddCommGroup E] + [NormedSpace 𝕜 E] {H : Type*} [TopologicalSpace H] (I : ModelWithCorners 𝕜 E H) + {M : Type*} [TopologicalSpace M] [ChartedSpace H M] + +variable {E' : Type*} [NormedAddCommGroup E'] [NormedSpace 𝕜 E'] + +variable (F : Type*) [NormedAddCommGroup F] [NormedSpace 𝕜 F] + -- `F` model fiber + (n : WithTop ℕ∞) + (V : M → Type*) [TopologicalSpace (TotalSpace F V)] + [∀ x, AddCommGroup (V x)] [∀ x, Module 𝕜 (V x)] + [∀ x : M, TopologicalSpace (V x)] [∀ x, IsTopologicalAddGroup (V x)] + [∀ x, ContinuousSMul 𝕜 (V x)] + [FiberBundle F V] [VectorBundle 𝕜 F V] + -- `V` vector bundle + +-- Tests for the T% elaborator, inserting calls to TotalSpace.mk' automatically. +section TotalSpace + +variable {σ : Π x : M, V x} + {σ' : (x : E) → Trivial E E' x} {σ'' : (y : E) → Trivial E E' y} {s : E → E'} + +/-- info: fun x ↦ TotalSpace.mk' F x (σ x) : M → TotalSpace F V -/ +#guard_msgs in +#check T% σ + +-- Note how the name of the bound variable `x` resp. `y` is preserved. +/-- info: fun x ↦ TotalSpace.mk' E' x (σ' x) : E → TotalSpace E' (Trivial E E') -/ +#guard_msgs in +#check T% σ' + +/-- info: fun y ↦ TotalSpace.mk' E' y (σ'' y) : E → TotalSpace E' (Trivial E E') -/ +#guard_msgs in +#check T% σ'' + +/-- info: fun a ↦ TotalSpace.mk' E' a (s a) : E → TotalSpace E' (Trivial E E') -/ +#guard_msgs in +#check T% s + +variable (X : (m : M) → TangentSpace I m) [IsManifold I 1 M] + +/-- info: fun m ↦ TotalSpace.mk' E m (X m) : M → TotalSpace E (TangentSpace I) -/ +#guard_msgs in +#check T% X + +example : (fun m ↦ (X m : TangentBundle I M)) = (fun m ↦ TotalSpace.mk' E m (X m)) := rfl + +end TotalSpace + +-- Elaborators for MDifferentiable{WithinAt,At,On}. +section differentiability + +-- Start with some basic tests: a simple function, both in applied and unapplied form. +variable {EM' : Type*} [NormedAddCommGroup EM'] + [NormedSpace 𝕜 EM'] {H' : Type*} [TopologicalSpace H'] (I' : ModelWithCorners 𝕜 EM' H') + {M' : Type*} [TopologicalSpace M'] [ChartedSpace H' M'] + +-- General case: a function between two manifolds. +variable {f : M → M'} {s : Set M} {m : M} + +/-- info: MDifferentiableWithinAt I I' f s : M → Prop -/ +#guard_msgs in +#check MDiffAt[s] f + +/-- info: MDifferentiableWithinAt I I' f s m : Prop -/ +#guard_msgs in +#check MDiffAt[s] f m + +/-- info: MDifferentiableAt I I' f : M → Prop -/ +#guard_msgs in +#check MDiffAt f + +/-- info: MDifferentiableAt I I' f m : Prop -/ +#guard_msgs in +#check MDiffAt f m + +/-- info: MDifferentiableOn I I' f s : Prop -/ +#guard_msgs in +#check MDiff[s] f + +-- XXX: is this expected behaviour or should it be a bug? +/-- +error: Function expected at + MDifferentiableOn I I' f s +but this term has type + Prop + +Note: Expected a function because this term is being applied to the argument + m +-/ +#guard_msgs in +#check MDiff[s] f m + +/-- info: MDifferentiable I I' f : Prop -/ +#guard_msgs in +#check MDiff f + +/-- +error: Function expected at + MDifferentiable I I' f +but this term has type + Prop + +Note: Expected a function because this term is being applied to the argument + m +-/ +#guard_msgs in +#check MDiff f m + +-- Function from a manifold into a normed space. +variable {g : M → E} + +/-- info: MDifferentiableWithinAt I 𝓘(𝕜, E) g s : M → Prop -/ +#guard_msgs in +#check MDiffAt[s] g +/-- info: MDifferentiableWithinAt I 𝓘(𝕜, E) g s m : Prop -/ +#guard_msgs in +#check MDiffAt[s] g m +/-- info: MDifferentiableAt I 𝓘(𝕜, E) g : M → Prop -/ +#guard_msgs in +#check MDiffAt g +/-- info: MDifferentiableAt I 𝓘(𝕜, E) g m : Prop -/ +#guard_msgs in +#check MDiffAt g m +/-- info: MDifferentiableOn I 𝓘(𝕜, E) g s : Prop -/ +#guard_msgs in +#check MDiff[s] g +-- TODO: fix and enable! #check MDiff[s] g m +/-- info: MDifferentiable I 𝓘(𝕜, E) g : Prop -/ +#guard_msgs in +#check MDiff g +-- TODO: fix and enable! #check MDiff g m + +-- From a manifold into a field. +variable {h : M → 𝕜} + +/-- info: MDifferentiableWithinAt I 𝓘(𝕜, 𝕜) h s : M → Prop -/ +#guard_msgs in +#check MDiffAt[s] h +/-- info: MDifferentiableWithinAt I 𝓘(𝕜, 𝕜) h s m : Prop -/ +#guard_msgs in +#check MDiffAt[s] h m +/-- info: MDifferentiableAt I 𝓘(𝕜, 𝕜) h : M → Prop -/ +#guard_msgs in +#check MDiffAt h +/-- info: MDifferentiableAt I 𝓘(𝕜, 𝕜) h m : Prop -/ +#guard_msgs in +#check MDiffAt h m +/-- info: MDifferentiableOn I 𝓘(𝕜, 𝕜) h s : Prop -/ +#guard_msgs in +#check MDiff[s] h +-- TODO: fix and enable! #check MDiff[s] h m +/-- info: MDifferentiable I 𝓘(𝕜, 𝕜) h : Prop -/ +#guard_msgs in +#check MDiff h +-- TODO: fix and enable! #check MDiff h m + +-- The following tests are more spotty, as most code paths are already covered above. +-- Add further details as necessary. + +-- From a normed space into a manifold. +variable {f : E → M'} {s : Set E} {x : E} +/-- info: MDifferentiableWithinAt 𝓘(𝕜, E) I' f s : E → Prop -/ +#guard_msgs in +#check MDiffAt[s] f +/-- info: MDifferentiableAt 𝓘(𝕜, E) I' f x : Prop -/ +#guard_msgs in +#check MDiffAt f x +-- TODO: fix and enable! #check MDiff[s] f x +/-- info: MDifferentiable 𝓘(𝕜, E) I' f : Prop -/ +#guard_msgs in +#check MDiff f +-- TODO: should this error? if not, fix and enable! #check MDiff f x +-- same! #check MDifferentiable% f x + +-- Between normed spaces. +variable {f : E → E'} {s : Set E} {x : E} + +/-- info: MDifferentiableAt 𝓘(𝕜, E) 𝓘(𝕜, E') f x : Prop -/ +#guard_msgs in +#check MDiffAt f x +/-- info: MDifferentiableAt 𝓘(𝕜, E) 𝓘(𝕜, E') f : E → Prop -/ +#guard_msgs in +#check MDiffAt f +-- should this error or not? #check MDiff[s] f x +/-- info: MDifferentiableWithinAt 𝓘(𝕜, E) 𝓘(𝕜, E') f s : E → Prop -/ +#guard_msgs in +#check MDiffAt[s] f +/-- info: MDifferentiableOn 𝓘(𝕜, E) 𝓘(𝕜, E') f s : Prop -/ +#guard_msgs in +#check MDiff[s] f + + +-- Normed space to a field. +variable {f : E → 𝕜} {s : Set E} {x : E} + +/-- info: MDifferentiableAt 𝓘(𝕜, E) 𝓘(𝕜, 𝕜) f x : Prop -/ +#guard_msgs in +#check MDiffAt f x + +-- Field into a manifold. +variable {f : 𝕜 → M'} {u : Set 𝕜} {a : 𝕜} +/-- info: MDifferentiableAt 𝓘(𝕜, 𝕜) I' f a : Prop -/ +#guard_msgs in +#check MDiffAt f a +/-- info: MDifferentiableOn 𝓘(𝕜, 𝕜) I' f u : Prop -/ +#guard_msgs in +#check MDiff[u] f + +-- Field into a normed space. +variable {f : 𝕜 → E'} {u : Set 𝕜} {a : 𝕜} +/-- info: MDifferentiableAt 𝓘(𝕜, 𝕜) 𝓘(𝕜, E') f a : Prop -/ +#guard_msgs in +#check MDiffAt f a +/-- info: MDifferentiableOn 𝓘(𝕜, 𝕜) 𝓘(𝕜, E') f u : Prop -/ +#guard_msgs in +#check MDiff[u] f + +-- On a field. +variable {f : 𝕜 → 𝕜} {u : Set 𝕜} {a : 𝕜} +/-- info: MDifferentiableAt 𝓘(𝕜, 𝕜) 𝓘(𝕜, 𝕜) f a : Prop -/ +#guard_msgs in +#check MDiffAt f a +/-- info: MDifferentiableOn 𝓘(𝕜, 𝕜) 𝓘(𝕜, 𝕜) f u : Prop -/ +#guard_msgs in +#check MDiff[u] f + +-- This elaborator can be combined with the total space elaborator. +-- XXX: these tests might be incomplete; extend as needed! + +variable {σ : Π x : M, V x} {σ' : (x : E) → Trivial E E' x} {s : E → E'} +variable (X : (m : M) → TangentSpace I m) [IsManifold I 1 M] + +/-- info: MDifferentiableAt I (I.prod 𝓘(𝕜, E)) fun m ↦ TotalSpace.mk' E m (X m) : M → Prop -/ +#guard_msgs in +#check MDiffAt (T% X) + +/-- info: MDifferentiableAt I (I.prod 𝓘(𝕜, F)) fun x ↦ TotalSpace.mk' F x (σ x) : M → Prop -/ +#guard_msgs in +#check MDiffAt (T% σ) + +/-- +info: MDifferentiableAt 𝓘(𝕜, E) (𝓘(𝕜, E).prod 𝓘(𝕜, E')) fun x ↦ TotalSpace.mk' E' x (σ' x) : E → Prop +-/ +#guard_msgs in +#check MDiffAt (T% σ') + +/-- +info: MDifferentiableAt 𝓘(𝕜, E) (𝓘(𝕜, E).prod 𝓘(𝕜, E')) fun a ↦ TotalSpace.mk' E' a (s a) : E → Prop +-/ +#guard_msgs in +#check MDifferentiableAt% (T% s) +/-- info: MDifferentiableAt I (I.prod 𝓘(𝕜, E)) (fun m ↦ TotalSpace.mk' E m (X m)) m : Prop -/ +#guard_msgs in +#check MDifferentiableAt% (T% X) m + +/-- info: MDifferentiableAt I (I.prod 𝓘(𝕜, E)) fun m ↦ TotalSpace.mk' E m (X m) : M → Prop -/ +#guard_msgs in +#check MDifferentiableAt% (T% X) + +/-- info: MDifferentiableAt I (I.prod 𝓘(𝕜, E)) (fun m ↦ TotalSpace.mk' E m (X m)) m : Prop -/ +#guard_msgs in +#check MDifferentiableAt% (T% X) m + +/-- info: MDifferentiableAt I (I.prod 𝓘(𝕜, F)) fun x ↦ TotalSpace.mk' F x (σ x) : M → Prop -/ +#guard_msgs in +#check MDifferentiableAt% (T% σ) + +/-- +info: MDifferentiableAt 𝓘(𝕜, E) (𝓘(𝕜, E).prod 𝓘(𝕜, E')) fun x ↦ TotalSpace.mk' E' x (σ' x) : E → Prop +-/ +#guard_msgs in +#check MDifferentiableAt% (T% σ') + +/-- +info: MDifferentiableAt 𝓘(𝕜, E) (𝓘(𝕜, E).prod 𝓘(𝕜, E')) fun a ↦ TotalSpace.mk' E' a (s a) : E → Prop +-/ +#guard_msgs in +#check MDifferentiableAt% (T% s) + +end differentiability From 81c019b0b3b1e54053c35ea957c65c0ac8b6a88e Mon Sep 17 00:00:00 2001 From: Michael Rothgang Date: Sat, 12 Jul 2025 10:48:13 +0200 Subject: [PATCH 002/106] Remove unused deprecated elaborators; noshake --- Mathlib/Geometry/Manifold/Elaborators.lean | 24 -------------- .../DifferentialGeometry/Elaborators.lean | 33 ------------------- scripts/noshake.json | 2 ++ 3 files changed, 2 insertions(+), 57 deletions(-) diff --git a/Mathlib/Geometry/Manifold/Elaborators.lean b/Mathlib/Geometry/Manifold/Elaborators.lean index c49814b40dc9b7..72e3cbc1c0a695 100644 --- a/Mathlib/Geometry/Manifold/Elaborators.lean +++ b/Mathlib/Geometry/Manifold/Elaborators.lean @@ -269,17 +269,6 @@ elab:max "MDiffAt" t:term:arg : term => do return ← mkAppM ``MDifferentiableAt #[srcI, tgtI, e] | _ => throwError m!"Term {e} is not a function." --- FIXME: remove in favour of MDiffAt (once that one is scoped) -elab:max "MDifferentiableAt%" t:term:arg : term => do - let e ← Term.elabTerm t none - let etype ← inferType e >>= instantiateMVars - match etype with - | .forallE _ src tgt _ => - let srcI ← find_model src - let tgtI ← find_model tgt (src, srcI) - return ← mkAppM ``MDifferentiableAt #[srcI, tgtI, e] - | _ => throwError m!"Term {e} is not a function." - /-- `MDiff[s] f` elaborates to `MDifferentiableOn I J f`, trying to determine `I` and `J` from the local context. -/ elab:max "MDiff[" s:term:arg "]" t:term:arg : term => do @@ -370,17 +359,4 @@ elab:max "CMDiff" nt:term:arg t:term:arg : term => do return ← mkAppM ``ContMDiff #[srcI, tgtI, ne, e] | _ => throwError m!"Term {e} is not a function." --- TODO: remove in favour of CMDiff (after aligning their behaviour and adding a test for it!) -elab:max "ContMDiff%" nt:term:arg t:term:arg : term => do - let e ← Term.elabTerm t none - let wtn ← Term.elabTerm (← `(WithTop ℕ∞)) none - let ne ← Term.elabTermEnsuringType nt wtn - let etype ← inferType e >>= instantiateMVars - match etype with - | .forallE _ src tgt _ => - let srcI ← find_model src - let tgtI ← find_model tgt (src, srcI) - return ← mkAppM ``ContMDiff #[srcI, tgtI, ne, e] - | _ => throwError m!"Term {e} is not a function." - end diff --git a/MathlibTest/DifferentialGeometry/Elaborators.lean b/MathlibTest/DifferentialGeometry/Elaborators.lean index 352b7873e7a6f0..e15c18132a3233 100644 --- a/MathlibTest/DifferentialGeometry/Elaborators.lean +++ b/MathlibTest/DifferentialGeometry/Elaborators.lean @@ -265,37 +265,4 @@ info: MDifferentiableAt 𝓘(𝕜, E) (𝓘(𝕜, E).prod 𝓘(𝕜, E')) fun x #guard_msgs in #check MDiffAt (T% σ') -/-- -info: MDifferentiableAt 𝓘(𝕜, E) (𝓘(𝕜, E).prod 𝓘(𝕜, E')) fun a ↦ TotalSpace.mk' E' a (s a) : E → Prop --/ -#guard_msgs in -#check MDifferentiableAt% (T% s) -/-- info: MDifferentiableAt I (I.prod 𝓘(𝕜, E)) (fun m ↦ TotalSpace.mk' E m (X m)) m : Prop -/ -#guard_msgs in -#check MDifferentiableAt% (T% X) m - -/-- info: MDifferentiableAt I (I.prod 𝓘(𝕜, E)) fun m ↦ TotalSpace.mk' E m (X m) : M → Prop -/ -#guard_msgs in -#check MDifferentiableAt% (T% X) - -/-- info: MDifferentiableAt I (I.prod 𝓘(𝕜, E)) (fun m ↦ TotalSpace.mk' E m (X m)) m : Prop -/ -#guard_msgs in -#check MDifferentiableAt% (T% X) m - -/-- info: MDifferentiableAt I (I.prod 𝓘(𝕜, F)) fun x ↦ TotalSpace.mk' F x (σ x) : M → Prop -/ -#guard_msgs in -#check MDifferentiableAt% (T% σ) - -/-- -info: MDifferentiableAt 𝓘(𝕜, E) (𝓘(𝕜, E).prod 𝓘(𝕜, E')) fun x ↦ TotalSpace.mk' E' x (σ' x) : E → Prop --/ -#guard_msgs in -#check MDifferentiableAt% (T% σ') - -/-- -info: MDifferentiableAt 𝓘(𝕜, E) (𝓘(𝕜, E).prod 𝓘(𝕜, E')) fun a ↦ TotalSpace.mk' E' a (s a) : E → Prop --/ -#guard_msgs in -#check MDifferentiableAt% (T% s) - end differentiability diff --git a/scripts/noshake.json b/scripts/noshake.json index eb97867df63397..aa22fbd4a22d83 100644 --- a/scripts/noshake.json +++ b/scripts/noshake.json @@ -50,6 +50,8 @@ "Mathlib.Data.Sym.Sym2.Init", "Mathlib.Data.Vector.Basic", "Mathlib.Geometry.Manifold.Instances.Real", + "Mathlib.Geometry.Manifold.Elaborators", + "Mathlib.Geometry.Manifold.Traces", "Mathlib.Init", "Mathlib.LinearAlgebra.AffineSpace.Basic", "Mathlib.LinearAlgebra.Matrix.Notation", From 6b09d20cbe5505767c2a51a6ce77cf2dd73c7e87 Mon Sep 17 00:00:00 2001 From: Michael Rothgang Date: Sat, 12 Jul 2025 10:53:49 +0200 Subject: [PATCH 003/106] Scope delaborators --- Mathlib/Geometry/Manifold/Elaborators.lean | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Mathlib/Geometry/Manifold/Elaborators.lean b/Mathlib/Geometry/Manifold/Elaborators.lean index 72e3cbc1c0a695..9cab5ae141b68f 100644 --- a/Mathlib/Geometry/Manifold/Elaborators.lean +++ b/Mathlib/Geometry/Manifold/Elaborators.lean @@ -14,7 +14,7 @@ import Mathlib.Geometry.Manifold.Traces This file defines custom elaborators for differential geometry, to allow for more compact notation. There are two classes of elaborators. The first provides more compact notation for differentiability and continuous differentiability on manifolds, including inference of the model with corners. -They allow writing +All these elaborators are scoped to the `Manifold` namespace. They allow writing - `MDiff f` for `MDifferentiable I J f` - `MDiffAt f x` for `MDifferentiableAt I J f x` - `MDiff[u] f` for `MDifferentiableOn I J f u` @@ -58,7 +58,6 @@ the following. is correct 90% of the time) - fix pretty-printing: currently, the `commandStart` linter expects some different formatting - better error messages: forgetting e.g. the `T%` elaborator yields cryptic errors -- make all these elaborators scoped to the `Manifold` namespace - further testing and fixing of edge cases - add test for the difference between `CMDiff` and `ContMDiff%` (and decide on one behaviour) - added tests for all of the above @@ -82,6 +81,8 @@ def _root_.Lean.Expr.getUniverse (e : Expr) : TermElabM (Level) := do @[match_pattern] def mkApp12 (f a b c d e g e₁ e₂ e₃ e₄ e₅ e₆ : Expr) := mkApp6 (mkApp6 f a b c d e g) e₁ e₂ e₃ e₄ e₅ e₆ +namespace Manifold + /-- Elaborator for sections in a fibre bundle: converts a section as a dependent function to a non-dependent function into the total space. This handles the cases of - sections of a trivial bundle @@ -238,8 +239,6 @@ def find_model (e : Expr) (baseInfo : Option (Expr × Expr) := none) : TermElabM throwError "Couldn’t find models with corners" --- TODO: scope all these elaborators to the `Manifold` namespace - /-- `MDiffAt[s] f x` elaborates to `MDifferentiableWithinAt I J f s x`, trying to determine `I` and `J` from the local context. The argument x can be omitted. -/ @@ -359,4 +358,6 @@ elab:max "CMDiff" nt:term:arg t:term:arg : term => do return ← mkAppM ``ContMDiff #[srcI, tgtI, ne, e] | _ => throwError m!"Term {e} is not a function." +end Manifold + end From 7be9e947a2ff0d3ced3fe055c81ba6b43ed60ebe Mon Sep 17 00:00:00 2001 From: Michael Rothgang Date: Sat, 12 Jul 2025 11:26:14 +0200 Subject: [PATCH 004/106] More minimal imports --- Mathlib/Geometry/Manifold/Elaborators.lean | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Mathlib/Geometry/Manifold/Elaborators.lean b/Mathlib/Geometry/Manifold/Elaborators.lean index 9cab5ae141b68f..0c983799ae6897 100644 --- a/Mathlib/Geometry/Manifold/Elaborators.lean +++ b/Mathlib/Geometry/Manifold/Elaborators.lean @@ -3,9 +3,8 @@ Copyright (c) 2025 Patrick Massot. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Patrick Massot, Michael Rothgang -/ -import Mathlib.Geometry.Manifold.VectorBundle.Tangent -import Mathlib.Geometry.Manifold.BumpFunction -import Mathlib.Geometry.Manifold.VectorBundle.MDifferentiable +import Mathlib.Geometry.Manifold.ContMDiff.Defs +import Mathlib.Geometry.Manifold.MFDeriv.Defs import Mathlib.Geometry.Manifold.Traces /-! From aeacd2056c9c9e047bc4091886755696809dd5aa Mon Sep 17 00:00:00 2001 From: Michael Rothgang Date: Sat, 12 Jul 2025 11:26:21 +0200 Subject: [PATCH 005/106] Use double backticks --- Mathlib/Geometry/Manifold/Elaborators.lean | 30 +++++++++++----------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/Mathlib/Geometry/Manifold/Elaborators.lean b/Mathlib/Geometry/Manifold/Elaborators.lean index 0c983799ae6897..2ce52ee391d2aa 100644 --- a/Mathlib/Geometry/Manifold/Elaborators.lean +++ b/Mathlib/Geometry/Manifold/Elaborators.lean @@ -97,13 +97,13 @@ elab "T% " t:term : term => do let e ← Term.elabTerm t none let etype ← inferType e >>= instantiateMVars match etype with - | .forallE x base (mkApp3 (.const `Bundle.Trivial _) E E' _) _ => + | .forallE x base (mkApp3 (.const ``Bundle.Trivial _) E E' _) _ => trace[TotalSpaceMk] "Section of a trivial bundle" if E == base then return ← withLocalDecl x BinderInfo.default base fun x ↦ do let body ← mkAppM ``Bundle.TotalSpace.mk' #[E', x, .app e x] mkLambdaFVars #[x] body - | .forallE x base (mkApp12 (.const `TangentSpace _) _k _ E _ _ _H _ _I _M _ _ _x) _ => + | .forallE x base (mkApp12 (.const ``TangentSpace _) _k _ E _ _ _H _ _I _M _ _ _x) _ => trace[TotalSpaceMk] "Vector field" return ← withLocalDecl x BinderInfo.default base fun x ↦ do let body ← mkAppM ``Bundle.TotalSpace.mk' #[E, x, .app e x] @@ -145,11 +145,11 @@ This implementation is not maximally robust yet, but already useful. -- FIXME: better failure when trying to find a `NormedField` instance def find_model (e : Expr) (baseInfo : Option (Expr × Expr) := none) : TermElabM Expr := do trace[MDiffElab] m!"Searching a model for: {e}" - if let mkApp3 (.const `Bundle.TotalSpace _) _ F V := e then - if let mkApp12 (.const `TangentSpace _) _k _ _E _ _ _H _ I M _ _ _x := V then + if let mkApp3 (.const ``Bundle.TotalSpace _) _ F V := e then + if let mkApp12 (.const ``TangentSpace _) _k _ _E _ _ _H _ I M _ _ _x := V then trace[MDiffElab] m!"This is the total space of the tangent bundle of {M}" let srcIT : Term ← PrettyPrinter.delab I - let resTerm : Term ← `(ModelWithCorners.prod $srcIT ModelWithCorners.tangent $srcIT) + let resTerm : Term ← ``(ModelWithCorners.prod $srcIT ModelWithCorners.tangent $srcIT) let res ← Term.elabTerm resTerm none trace[MDiffElab] m!"Found model: {res}" return res @@ -162,7 +162,7 @@ def find_model (e : Expr) (baseInfo : Option (Expr × Expr) := none) : TermElabM for decl in ← getLocalHyps do let decltype ← inferType decl >>= instantiateMVars match decltype with - | mkApp4 (.const `NormedSpace _) K' E _ _ => + | mkApp4 (.const ``NormedSpace _) K' E _ _ => if E == F then K := K' trace[MDiffElab] m!"{F} is a normed field over {K}" @@ -175,7 +175,7 @@ def find_model (e : Expr) (baseInfo : Option (Expr × Expr) := none) : TermElabM let kT : Term ← PrettyPrinter.delab K let srcIT : Term ← PrettyPrinter.delab srcI let FT : Term ← PrettyPrinter.delab F - let iTerm : Term ← `(ModelWithCorners.prod $srcIT 𝓘($kT, $FT)) + let iTerm : Term ← ``(ModelWithCorners.prod $srcIT 𝓘($kT, $FT)) let I ← Term.elabTerm iTerm none trace[MDiffElab] m!"Found model: {I}" return I @@ -190,12 +190,12 @@ def find_model (e : Expr) (baseInfo : Option (Expr × Expr) := none) : TermElabM for decl in ← getLocalHyps do let decltype ← inferType decl >>= instantiateMVars match decltype with - | mkApp4 (.const `ChartedSpace _) H' _ M _ => + | mkApp4 (.const ``ChartedSpace _) H' _ M _ => if M == e then H := H' trace[MDiffElab] m!"H is: {H}" Hok := true - | mkApp4 (.const `NormedSpace _) K' E _ _ => + | mkApp4 (.const ``NormedSpace _) K' E _ _ => if E == e then K := K' trace[MDiffElab] m!"Field is: {K}" @@ -206,15 +206,15 @@ def find_model (e : Expr) (baseInfo : Option (Expr × Expr) := none) : TermElabM if Kok then let eT : Term ← PrettyPrinter.delab e let eK : Term ← PrettyPrinter.delab K - let iTerm : Term ← `(𝓘($eK, $eT)) + let iTerm : Term ← ``(𝓘($eK, $eT)) let I ← Term.elabTerm iTerm none trace[MDiffElab] m!"Found model: {I}" return I -- let uK ← K.getUniverse - -- let normedFieldK ← synthInstance (.app (.const `NontriviallyNormedField [uK]) K) + -- let normedFieldK ← synthInstance (.app (.const ``NontriviallyNormedField [uK]) K) -- trace[MDiffElab] m!"NontriviallyNormedField instance is: {normedFieldK}" -- let ue ← e.getUniverse - -- let normedGroupE ← synthInstance (.app (.const `NormedAddCommGroup [ue]) e) + -- let normedGroupE ← synthInstance (.app (.const ``NormedAddCommGroup [ue]) e) -- trace[MDiffElab] m!"NormedAddCommGroup instance is: {normedGroupE}" -- return mkAppN (.const `modelWithCornersSelf [uK, ue]) -- #[K, normedFieldK, e, normedGroupE, normedSpaceInst] @@ -222,7 +222,7 @@ def find_model (e : Expr) (baseInfo : Option (Expr × Expr) := none) : TermElabM for decl in ← getLocalHyps do let decltype ← inferType decl >>= instantiateMVars match decltype with - | mkApp7 (.const `ModelWithCorners _) _ _ _ _ _ H' _ => + | mkApp7 (.const ``ModelWithCorners _) _ _ _ _ _ H' _ => if H' == H then trace[MDiffElab] m!"Found model: {decl}" return decl @@ -316,7 +316,7 @@ elab:max "CMDiffAt[" s:term:arg "]" nt:term:arg f:term:arg : term => do trying to determine `I` and `J` from the local context. -/ elab:max "CMDiffAt" nt:term:arg t:term:arg : term => do let e ← Term.elabTerm t none - let wtn ← Term.elabTerm (← `(WithTop ℕ∞)) none + let wtn ← Term.elabTerm (← ``(WithTop ℕ∞)) none let ne ← Term.elabTermEnsuringType nt wtn let etype ← inferType e >>= instantiateMVars match etype with @@ -331,7 +331,7 @@ trying to determine `I` and `J` from the local context. -/ elab:max "CMDiff[" s:term:arg "]" nt:term:arg f:term:arg : term => do let es ← Term.elabTerm s none let ef ← Term.elabTerm f none - let wtn ← Term.elabTerm (← `(WithTop ℕ∞)) none + let wtn ← Term.elabTerm (← ``(WithTop ℕ∞)) none let ne ← Term.elabTermEnsuringType nt wtn let _estype ← inferType es >>= instantiateMVars let eftype ← inferType ef >>= instantiateMVars From 79c9622303d2184d1d7ec55da47fb40f7ce31e77 Mon Sep 17 00:00:00 2001 From: Michael Rothgang Date: Sat, 12 Jul 2025 11:32:43 +0200 Subject: [PATCH 006/106] Manual noshake --- scripts/noshake.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scripts/noshake.json b/scripts/noshake.json index aa22fbd4a22d83..99609d4075c6ca 100644 --- a/scripts/noshake.json +++ b/scripts/noshake.json @@ -416,6 +416,8 @@ "Mathlib.Lean.Expr.ExtraRecognizers": ["Mathlib.Data.Set.Operations"], "Mathlib.Lean.Expr.Basic": ["Batteries.Logic"], "Mathlib.GroupTheory.MonoidLocalization.Basic": ["Mathlib.Init.Data.Prod"], + "Mathlib.Geometry.Manifold.Elaborators": + ["Mathlib.Geometry.Manifold.ContMDiff.Defs", "Mathlib.Geometry.Manifold.MFDeriv.Defs"], "Mathlib.Geometry.Manifold.Sheaf.Smooth": ["Mathlib.CategoryTheory.Sites.Whiskering"], "Mathlib.Geometry.Manifold.PoincareConjecture": From 0fa641c3e1d64be3bd078f66c7b8c8f4517fb7a8 Mon Sep 17 00:00:00 2001 From: Michael Rothgang Date: Thu, 17 Jul 2025 15:40:14 +0200 Subject: [PATCH 007/106] chore(Elaborators): fix a few typos in doc-strings --- Mathlib/Geometry/Manifold/Elaborators.lean | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/Mathlib/Geometry/Manifold/Elaborators.lean b/Mathlib/Geometry/Manifold/Elaborators.lean index 2ce52ee391d2aa..ac6de4cdb4a983 100644 --- a/Mathlib/Geometry/Manifold/Elaborators.lean +++ b/Mathlib/Geometry/Manifold/Elaborators.lean @@ -295,8 +295,9 @@ elab:max "MDiff" t:term:arg : term => do | _ => throwError m!"Term {e} is not a function." -- TODO: say something about the expected type of `n` being in ℕ or WithTop ℕ∞! -/-- `CMDiffAt[s] n f` elaborates to `ContMDiffWithinAt I J n f s`, -trying to determine `I` and `J` from the local context. -/ +/-- `CMDiffAt[s] n f x` elaborates to `ContMDiffWithinAt I J n f s x`, +trying to determine `I` and `J` from the local context. +The argument `x` can be omitted. -/ elab:max "CMDiffAt[" s:term:arg "]" nt:term:arg f:term:arg : term => do let es ← Term.elabTerm s none let ef ← Term.elabTerm f none @@ -312,8 +313,9 @@ elab:max "CMDiffAt[" s:term:arg "]" nt:term:arg f:term:arg : term => do return ← mkAppM ``ContMDiffWithinAt #[srcI, tgtI, ne, ef, es] | _ => throwError m!"Term {ef} is not a function." -/-- `CMDiffAt n f` elaborates to `ContMDiffAt I J n f s` -trying to determine `I` and `J` from the local context. -/ +/-- `CMDiffAt n f x` elaborates to `ContMDiffAt I J n f x` +trying to determine `I` and `J` from the local context. +The argument `x` can be omitted. -/ elab:max "CMDiffAt" nt:term:arg t:term:arg : term => do let e ← Term.elabTerm t none let wtn ← Term.elabTerm (← ``(WithTop ℕ∞)) none @@ -345,8 +347,8 @@ elab:max "CMDiff[" s:term:arg "]" nt:term:arg f:term:arg : term => do /-- `CMDiff n f` elaborates to `ContMDiff I J n f`, trying to determine `I` and `J` from the local context. -/ -elab:max "CMDiff" nt:term:arg t:term:arg : term => do - let e ← Term.elabTerm t none +elab:max "CMDiff" nt:term:arg f:term:arg : term => do + let e ← Term.elabTerm f none let wtn ← Term.elabTerm (← `(WithTop ℕ∞)) none let ne ← Term.elabTerm nt wtn let etype ← inferType e >>= instantiateMVars From 2e80df40bf51cb3ffccb9a4cc816c66d1e501bfe Mon Sep 17 00:00:00 2001 From: Michael Rothgang Date: Thu, 17 Jul 2025 15:40:26 +0200 Subject: [PATCH 008/106] feat: custom elaborator for mderiv(Within) --- Mathlib/Geometry/Manifold/Elaborators.lean | 31 +++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/Mathlib/Geometry/Manifold/Elaborators.lean b/Mathlib/Geometry/Manifold/Elaborators.lean index ac6de4cdb4a983..8cf058162b33b4 100644 --- a/Mathlib/Geometry/Manifold/Elaborators.lean +++ b/Mathlib/Geometry/Manifold/Elaborators.lean @@ -21,7 +21,9 @@ All these elaborators are scoped to the `Manifold` namespace. They allow writing - `CMDiff n f` for `ContMDiff I J n f` - `CMDiffAt n f x` for `ContMDiffAt I J n f x` - `CMDiff[u] n f` for `ContMDiffOn I J n f u` -- `CMDiffAt[u] n f` for `ContMDiffWithinAt I J n f u x`. +- `CMDiffAt[u] n f` for `ContMDiffWithinAt I J n f u x`, +- `mfderiv[u] f x` for `mfderivWithin I J f s x`, +- `mfderiv% f x` for `mfderiv I J f x`. In each of these cases, the models with corners are inferred from the domain and codomain of `f`. The search for models with corners uses the local context and is (almost) only syntactic, hence @@ -361,4 +363,31 @@ elab:max "CMDiff" nt:term:arg f:term:arg : term => do end Manifold +/-- `mfderiv[u] f x` elaborates to `mfderivWithin I J f x`, +trying to determine `I` and `J` from the local context. -/ +elab:max "mfderiv[" s:term:arg "]" t:term:arg : term => do + let es ← Term.elabTerm s none + let e ← Term.elabTerm t none + let etype ← inferType e >>= instantiateMVars + let _estype ← inferType es >>= instantiateMVars + match etype with + | .forallE _ src tgt _ => + let srcI ← find_model src + let tgtI ← find_model tgt (src, srcI) + -- TODO: check `estype` and src are compatible + return ← mkAppM ``mfderivWithin #[srcI, tgtI, e, es] + | _ => throwError m!"Term {e} is not a function." + +/-- `mfderiv f x` elaborates to `mfderiv I J f x`, +trying to determine `I` and `J` from the local context. -/ +elab:max "mfderiv%" t:term:arg : term => do + let e ← Term.elabTerm t none + let etype ← inferType e >>= instantiateMVars + match etype with + | .forallE _ src tgt _ => + let srcI ← find_model src + let tgtI ← find_model tgt (src, srcI) + return ← mkAppM `mfderiv #[srcI, tgtI, e] + | _ => throwError m!"Term {e} is not a function." + end From e77fbc428244508d1a8b267c6f721a5f0e3c27cd Mon Sep 17 00:00:00 2001 From: Michael Rothgang Date: Thu, 17 Jul 2025 15:45:43 +0200 Subject: [PATCH 009/106] And add some tests, including some for (already fine) error messages --- .../DifferentialGeometry/Elaborators.lean | 101 ++++++++++++++++++ 1 file changed, 101 insertions(+) diff --git a/MathlibTest/DifferentialGeometry/Elaborators.lean b/MathlibTest/DifferentialGeometry/Elaborators.lean index e15c18132a3233..eae8bc13a557a8 100644 --- a/MathlibTest/DifferentialGeometry/Elaborators.lean +++ b/MathlibTest/DifferentialGeometry/Elaborators.lean @@ -266,3 +266,104 @@ info: MDifferentiableAt 𝓘(𝕜, E) (𝓘(𝕜, E).prod 𝓘(𝕜, E')) fun x #check MDiffAt (T% σ') end differentiability + +section mfderiv + +variable {EM' : Type*} [NormedAddCommGroup EM'] + [NormedSpace 𝕜 EM'] {H' : Type*} [TopologicalSpace H'] (I' : ModelWithCorners 𝕜 EM' H') + {M' : Type*} [TopologicalSpace M'] [ChartedSpace H' M'] + +variable {f : M → M'} {s : Set M} {m : M} + +/-- info: mfderiv I I' f : (x : M) → TangentSpace I x →L[𝕜] TangentSpace I' (f x) -/ +#guard_msgs in +#check mfderiv% f + +/-- info: mfderiv I I' f m : TangentSpace I m →L[𝕜] TangentSpace I' (f m) -/ +#guard_msgs in +#check mfderiv% f m + +/-- info: mfderivWithin I I' f s : (x : M) → TangentSpace I x →L[𝕜] TangentSpace I' (f x) -/ +#guard_msgs in +#check mfderiv[s] f + +/-- info: mfderivWithin I I' f s m : TangentSpace I m →L[𝕜] TangentSpace I' (f m) -/ +#guard_msgs in +#check mfderiv[s] f m + +variable {f : E → EM'} {s : Set E} {m : E} + +/-- +info: mfderiv 𝓘(𝕜, E) 𝓘(𝕜, EM') f : (x : E) → TangentSpace 𝓘(𝕜, E) x →L[𝕜] TangentSpace 𝓘(𝕜, EM') (f x) +-/ +#guard_msgs in +#check mfderiv% f + +/-- +info: mfderiv 𝓘(𝕜, E) 𝓘(𝕜, EM') f m : TangentSpace 𝓘(𝕜, E) m →L[𝕜] TangentSpace 𝓘(𝕜, EM') (f m) +-/ +#guard_msgs in +#check mfderiv% f m + +/-- +info: mfderivWithin 𝓘(𝕜, E) 𝓘(𝕜, EM') f s : (x : E) → TangentSpace 𝓘(𝕜, E) x →L[𝕜] TangentSpace 𝓘(𝕜, EM') (f x) +-/ +#guard_msgs in +#check mfderiv[s] f + +/-- +info: mfderivWithin 𝓘(𝕜, E) 𝓘(𝕜, EM') f s m : TangentSpace 𝓘(𝕜, E) m →L[𝕜] TangentSpace 𝓘(𝕜, EM') (f m) +-/ +#guard_msgs in +#check mfderiv[s] f m + +section errors + +-- Test an error message, about mismatched types. +variable {s' : Set M} {m' : M} + +/-- +error: Application type mismatch: In the application + mfderiv 𝓘(𝕜, E) 𝓘(𝕜, EM') f m' +the argument + m' +has type + M : Type u_4 +but is expected to have type + E : Type u_2 +--- +info: mfderiv 𝓘(𝕜, E) 𝓘(𝕜, EM') f sorry : TangentSpace 𝓘(𝕜, E) sorry →L[𝕜] TangentSpace 𝓘(𝕜, EM') (f sorry) +-/ +#guard_msgs in +#check mfderiv% f m' + +-- Error messages: argument s has mismatched type. +/-- +error: Application type mismatch: In the application + mfderivWithin 𝓘(𝕜, E) 𝓘(𝕜, EM') f s' +the argument + s' +has type + Set.{u_4} M : Type u_4 +but is expected to have type + Set.{u_2} E : Type u_2 +-/ +#guard_msgs in +#check mfderiv[s'] f + +/-- +error: Application type mismatch: In the application + mfderivWithin 𝓘(𝕜, E) 𝓘(𝕜, EM') f s' +the argument + s' +has type + Set.{u_4} M : Type u_4 +but is expected to have type + Set.{u_2} E : Type u_2 +-/ +#guard_msgs in +#check mfderiv[s'] f m + +end errors + +end mfderiv From ccb392629222c524018a8df1080b2d7552da8220 Mon Sep 17 00:00:00 2001 From: Michael Rothgang Date: Thu, 17 Jul 2025 16:47:17 +0200 Subject: [PATCH 010/106] Fix the build --- Mathlib/Geometry/Manifold/Elaborators.lean | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/Mathlib/Geometry/Manifold/Elaborators.lean b/Mathlib/Geometry/Manifold/Elaborators.lean index 8cf058162b33b4..6835043b367303 100644 --- a/Mathlib/Geometry/Manifold/Elaborators.lean +++ b/Mathlib/Geometry/Manifold/Elaborators.lean @@ -67,7 +67,6 @@ the following. open scoped Bundle Manifold ContDiff -section open Lean Meta Elab Tactic open Mathlib.Tactic @@ -361,8 +360,6 @@ elab:max "CMDiff" nt:term:arg f:term:arg : term => do return ← mkAppM ``ContMDiff #[srcI, tgtI, ne, e] | _ => throwError m!"Term {e} is not a function." -end Manifold - /-- `mfderiv[u] f x` elaborates to `mfderivWithin I J f x`, trying to determine `I` and `J` from the local context. -/ elab:max "mfderiv[" s:term:arg "]" t:term:arg : term => do @@ -390,4 +387,4 @@ elab:max "mfderiv%" t:term:arg : term => do return ← mkAppM `mfderiv #[srcI, tgtI, e] | _ => throwError m!"Term {e} is not a function." -end +end Manifold From bae571bf9f2ec72ede90249a1c91b1cf89e1180a Mon Sep 17 00:00:00 2001 From: Michael Rothgang Date: Wed, 6 Aug 2025 11:03:03 +0200 Subject: [PATCH 011/106] A few fixes from review --- Mathlib/Geometry/Manifold/Elaborators.lean | 7 +++--- .../DifferentialGeometry/Elaborators.lean | 23 ++++++++++++++++++- 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/Mathlib/Geometry/Manifold/Elaborators.lean b/Mathlib/Geometry/Manifold/Elaborators.lean index 6835043b367303..c25d1cdc616d08 100644 --- a/Mathlib/Geometry/Manifold/Elaborators.lean +++ b/Mathlib/Geometry/Manifold/Elaborators.lean @@ -17,12 +17,12 @@ All these elaborators are scoped to the `Manifold` namespace. They allow writing - `MDiff f` for `MDifferentiable I J f` - `MDiffAt f x` for `MDifferentiableAt I J f x` - `MDiff[u] f` for `MDifferentiableOn I J f u` -- `MDiffAt[u] f` for `DifferentiableWithinAt I J f u x` +- `MDiffAt[u] f x` for `MDifferentiableWithinAt I J f u x` - `CMDiff n f` for `ContMDiff I J n f` - `CMDiffAt n f x` for `ContMDiffAt I J n f x` - `CMDiff[u] n f` for `ContMDiffOn I J n f u` -- `CMDiffAt[u] n f` for `ContMDiffWithinAt I J n f u x`, -- `mfderiv[u] f x` for `mfderivWithin I J f s x`, +- `CMDiffAt[u] n f x` for `ContMDiffWithinAt I J n f u x`, +- `mfderiv[u] f x` for `mfderivWithin I J f u x`, - `mfderiv% f x` for `mfderiv I J f x`. In each of these cases, the models with corners are inferred from the domain and codomain of `f`. @@ -62,6 +62,7 @@ the following. - further testing and fixing of edge cases - add test for the difference between `CMDiff` and `ContMDiff%` (and decide on one behaviour) - added tests for all of the above +- add delaborators for these elaborators -/ diff --git a/MathlibTest/DifferentialGeometry/Elaborators.lean b/MathlibTest/DifferentialGeometry/Elaborators.lean index eae8bc13a557a8..29c9048226c0df 100644 --- a/MathlibTest/DifferentialGeometry/Elaborators.lean +++ b/MathlibTest/DifferentialGeometry/Elaborators.lean @@ -44,6 +44,15 @@ variable {σ : Π x : M, V x} #guard_msgs in #check T% σ +variable {x : M} +/-- info: (fun x ↦ TotalSpace.mk' F x (σ x)) x : TotalSpace F V -/ +#guard_msgs in +#check (T% σ) x +-- XXX: precendence is surprising, as this does nothing +/-- info: σ x : V x -/ +#guard_msgs in +#check T% σ x + -- Note how the name of the bound variable `x` resp. `y` is preserved. /-- info: fun x ↦ TotalSpace.mk' E' x (σ' x) : E → TotalSpace E' (Trivial E E') -/ #guard_msgs in @@ -98,7 +107,7 @@ variable {f : M → M'} {s : Set M} {m : M} #guard_msgs in #check MDiff[s] f --- XXX: is this expected behaviour or should it be a bug? +-- Testing an error message. /-- error: Function expected at MDifferentiableOn I I' f s @@ -111,6 +120,18 @@ Note: Expected a function because this term is being applied to the argument #guard_msgs in #check MDiff[s] f m +/-- +error: Function expected at + MDifferentiableOn I I' f s +but this term has type + Prop + +Note: Expected a function because this term is being applied to the argument + m +-/ +#guard_msgs in +#check MDifferentiableOn I I' f s m + /-- info: MDifferentiable I I' f : Prop -/ #guard_msgs in #check MDiff f From 3e0d75f69a72f92aef7b287295b924a6c4304962 Mon Sep 17 00:00:00 2001 From: Michael Rothgang Date: Wed, 6 Aug 2025 11:05:26 +0200 Subject: [PATCH 012/106] fix: precendence in T%. --- Mathlib/Geometry/Manifold/Elaborators.lean | 2 +- MathlibTest/DifferentialGeometry/Elaborators.lean | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/Mathlib/Geometry/Manifold/Elaborators.lean b/Mathlib/Geometry/Manifold/Elaborators.lean index c25d1cdc616d08..1e65dd3cf81066 100644 --- a/Mathlib/Geometry/Manifold/Elaborators.lean +++ b/Mathlib/Geometry/Manifold/Elaborators.lean @@ -95,7 +95,7 @@ This elaborator operates purely syntactically, by analysing the local contexts f hypothesis for the above cases. Therefore, it is (hopefully) fast enough to always run. -/ -- TODO: document how this elaborator works, any gotchas, etc. -elab "T% " t:term : term => do +elab:max "T% " t:term:arg : term => do let e ← Term.elabTerm t none let etype ← inferType e >>= instantiateMVars match etype with diff --git a/MathlibTest/DifferentialGeometry/Elaborators.lean b/MathlibTest/DifferentialGeometry/Elaborators.lean index 29c9048226c0df..629c2144d79578 100644 --- a/MathlibTest/DifferentialGeometry/Elaborators.lean +++ b/MathlibTest/DifferentialGeometry/Elaborators.lean @@ -44,14 +44,18 @@ variable {σ : Π x : M, V x} #guard_msgs in #check T% σ +-- Testing precedence. variable {x : M} /-- info: (fun x ↦ TotalSpace.mk' F x (σ x)) x : TotalSpace F V -/ #guard_msgs in #check (T% σ) x --- XXX: precendence is surprising, as this does nothing -/-- info: σ x : V x -/ +/-- info: (fun x ↦ TotalSpace.mk' F x (σ x)) x : TotalSpace F V -/ #guard_msgs in #check T% σ x +-- Nothing happening, as expected. +/-- info: σ x : V x -/ +#guard_msgs in +#check T% (σ x) -- Note how the name of the bound variable `x` resp. `y` is preserved. /-- info: fun x ↦ TotalSpace.mk' E' x (σ' x) : E → TotalSpace E' (Trivial E E') -/ From 273f4cd78f1f0b0770d9a185558a32abd17d896c Mon Sep 17 00:00:00 2001 From: Michael Rothgang Date: Wed, 6 Aug 2025 11:14:41 +0200 Subject: [PATCH 013/106] chore: note one TODO It's hard to make a test for this, though! --- Mathlib/Geometry/Manifold/Elaborators.lean | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Mathlib/Geometry/Manifold/Elaborators.lean b/Mathlib/Geometry/Manifold/Elaborators.lean index 1e65dd3cf81066..37605de72dd3d3 100644 --- a/Mathlib/Geometry/Manifold/Elaborators.lean +++ b/Mathlib/Geometry/Manifold/Elaborators.lean @@ -125,6 +125,8 @@ elab:max "T% " t:term:arg : term => do trace[TotalSpaceMk] "Section of a trivial bundle as a non-dependent function" let us ← src.getUniverse let ut ← tgt.getUniverse + -- TODO: can `tgt` depend on `x` in a way that is not a function application? + -- Check that `x` is not a bound variable in `tgt`! let triv_bundle := mkAppN (.const `Bundle.Trivial [us, ut]) #[src, tgt] return ← withLocalDecl x BinderInfo.default src fun x ↦ do let body := mkAppN (.const ``Bundle.TotalSpace.mk' [us, ut, ut]) From 1c6fcac6220c75af94bf5122f2024934fd8eb317 Mon Sep 17 00:00:00 2001 From: Michael Rothgang Date: Tue, 26 Aug 2025 14:47:31 +0200 Subject: [PATCH 014/106] chore: review comments Check reducible defeq instead. TODO, add tests for this! --- Mathlib/Geometry/Manifold/Elaborators.lean | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Mathlib/Geometry/Manifold/Elaborators.lean b/Mathlib/Geometry/Manifold/Elaborators.lean index 37605de72dd3d3..2f17e5e047ad2e 100644 --- a/Mathlib/Geometry/Manifold/Elaborators.lean +++ b/Mathlib/Geometry/Manifold/Elaborators.lean @@ -101,7 +101,7 @@ elab:max "T% " t:term:arg : term => do match etype with | .forallE x base (mkApp3 (.const ``Bundle.Trivial _) E E' _) _ => trace[TotalSpaceMk] "Section of a trivial bundle" - if E == base then + if ← withReducible (isDefEq E base) then return ← withLocalDecl x BinderInfo.default base fun x ↦ do let body ← mkAppM ``Bundle.TotalSpace.mk' #[E', x, .app e x] mkLambdaFVars #[x] body @@ -116,7 +116,7 @@ elab:max "T% " t:term:arg : term => do let decltype ← inferType decl >>= instantiateMVars match decltype with | mkApp7 (.const `FiberBundle _) _ F _ _ E _ _ => - if E == V then + if ← withReducible (isDefEq E V) then return ← withLocalDecl x BinderInfo.default base fun x ↦ do let body ← mkAppM ``Bundle.TotalSpace.mk' #[F, x, .app e x] mkLambdaFVars #[x] body @@ -127,10 +127,10 @@ elab:max "T% " t:term:arg : term => do let ut ← tgt.getUniverse -- TODO: can `tgt` depend on `x` in a way that is not a function application? -- Check that `x` is not a bound variable in `tgt`! - let triv_bundle := mkAppN (.const `Bundle.Trivial [us, ut]) #[src, tgt] + let trivBundle := mkAppN (.const `Bundle.Trivial [us, ut]) #[src, tgt] return ← withLocalDecl x BinderInfo.default src fun x ↦ do let body := mkAppN (.const ``Bundle.TotalSpace.mk' [us, ut, ut]) - #[src, triv_bundle, tgt, x, .app e x] + #[src, trivBundle, tgt, x, .app e x] mkLambdaFVars #[x] body | _ => pure () return e From 1738036d36d6175e1e2bbf980ebc117943becb0f Mon Sep 17 00:00:00 2001 From: Michael Rothgang Date: Tue, 26 Aug 2025 14:49:08 +0200 Subject: [PATCH 015/106] wip: test for beta-reduction in T % --- MathlibTest/DifferentialGeometry/Elaborators.lean | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/MathlibTest/DifferentialGeometry/Elaborators.lean b/MathlibTest/DifferentialGeometry/Elaborators.lean index 629c2144d79578..51ee4fa8419c69 100644 --- a/MathlibTest/DifferentialGeometry/Elaborators.lean +++ b/MathlibTest/DifferentialGeometry/Elaborators.lean @@ -78,6 +78,11 @@ variable (X : (m : M) → TangentSpace I m) [IsManifold I 1 M] example : (fun m ↦ (X m : TangentBundle I M)) = (fun m ↦ TotalSpace.mk' E m (X m)) := rfl +-- Applying a section to an argument. TODO: beta-reduce instead! +/-- info: (fun m ↦ TotalSpace.mk' E m (X m)) x : TotalSpace E (TangentSpace I) -/ +#guard_msgs in +#check (T% X) x + end TotalSpace -- Elaborators for MDifferentiable{WithinAt,At,On}. From d61ded359cafd7735bf2ae01a162036314d0b987 Mon Sep 17 00:00:00 2001 From: Michael Rothgang Date: Tue, 26 Aug 2025 15:02:41 +0200 Subject: [PATCH 016/106] wip: beta-reduce in T% elaborator --- Mathlib/Geometry/Manifold/Elaborators.lean | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Mathlib/Geometry/Manifold/Elaborators.lean b/Mathlib/Geometry/Manifold/Elaborators.lean index 2f17e5e047ad2e..b7757c4a2079d4 100644 --- a/Mathlib/Geometry/Manifold/Elaborators.lean +++ b/Mathlib/Geometry/Manifold/Elaborators.lean @@ -95,8 +95,9 @@ This elaborator operates purely syntactically, by analysing the local contexts f hypothesis for the above cases. Therefore, it is (hopefully) fast enough to always run. -/ -- TODO: document how this elaborator works, any gotchas, etc. -elab:max "T% " t:term:arg : term => do +elab:max "T% " t:term:arg args:term,* : term => do let e ← Term.elabTerm t none + let argsE := ← args.getElems.mapM (Term.elabTerm · none) let etype ← inferType e >>= instantiateMVars match etype with | .forallE x base (mkApp3 (.const ``Bundle.Trivial _) E E' _) _ => @@ -104,6 +105,7 @@ elab:max "T% " t:term:arg : term => do if ← withReducible (isDefEq E base) then return ← withLocalDecl x BinderInfo.default base fun x ↦ do let body ← mkAppM ``Bundle.TotalSpace.mk' #[E', x, .app e x] + -- do we want this instead? let asdf := e.beta (#[x] ++ argsE) mkLambdaFVars #[x] body | .forallE x base (mkApp12 (.const ``TangentSpace _) _k _ E _ _ _H _ _I _M _ _ _x) _ => trace[TotalSpaceMk] "Vector field" From 500c20d7f20f899b21fa17466ef470299400b147 Mon Sep 17 00:00:00 2001 From: Michael Rothgang Date: Tue, 26 Aug 2025 15:03:00 +0200 Subject: [PATCH 017/106] Revert "wip: beta-reduce in T% elaborator" This reverts commit c10258295e9626597b380f36b3dc7efaf0794b4e. --- Mathlib/Geometry/Manifold/Elaborators.lean | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Mathlib/Geometry/Manifold/Elaborators.lean b/Mathlib/Geometry/Manifold/Elaborators.lean index b7757c4a2079d4..2f17e5e047ad2e 100644 --- a/Mathlib/Geometry/Manifold/Elaborators.lean +++ b/Mathlib/Geometry/Manifold/Elaborators.lean @@ -95,9 +95,8 @@ This elaborator operates purely syntactically, by analysing the local contexts f hypothesis for the above cases. Therefore, it is (hopefully) fast enough to always run. -/ -- TODO: document how this elaborator works, any gotchas, etc. -elab:max "T% " t:term:arg args:term,* : term => do +elab:max "T% " t:term:arg : term => do let e ← Term.elabTerm t none - let argsE := ← args.getElems.mapM (Term.elabTerm · none) let etype ← inferType e >>= instantiateMVars match etype with | .forallE x base (mkApp3 (.const ``Bundle.Trivial _) E E' _) _ => @@ -105,7 +104,6 @@ elab:max "T% " t:term:arg args:term,* : term => do if ← withReducible (isDefEq E base) then return ← withLocalDecl x BinderInfo.default base fun x ↦ do let body ← mkAppM ``Bundle.TotalSpace.mk' #[E', x, .app e x] - -- do we want this instead? let asdf := e.beta (#[x] ++ argsE) mkLambdaFVars #[x] body | .forallE x base (mkApp12 (.const ``TangentSpace _) _k _ E _ _ _H _ _I _M _ _ _x) _ => trace[TotalSpaceMk] "Vector field" From 4b82f39aec0b641a3f2285e6748c340b447e7a45 Mon Sep 17 00:00:00 2001 From: grunweg Date: Tue, 30 Sep 2025 08:30:25 +0200 Subject: [PATCH 018/106] Two more typos Co-authored-by: Sebastien Gouezel --- Mathlib/Geometry/Manifold/Elaborators.lean | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Mathlib/Geometry/Manifold/Elaborators.lean b/Mathlib/Geometry/Manifold/Elaborators.lean index 2f17e5e047ad2e..61f6ba7396a820 100644 --- a/Mathlib/Geometry/Manifold/Elaborators.lean +++ b/Mathlib/Geometry/Manifold/Elaborators.lean @@ -271,7 +271,7 @@ elab:max "MDiffAt" t:term:arg : term => do return ← mkAppM ``MDifferentiableAt #[srcI, tgtI, e] | _ => throwError m!"Term {e} is not a function." -/-- `MDiff[s] f` elaborates to `MDifferentiableOn I J f`, +/-- `MDiff[s] f` elaborates to `MDifferentiableOn I J f s`, trying to determine `I` and `J` from the local context. -/ elab:max "MDiff[" s:term:arg "]" t:term:arg : term => do let es ← Term.elabTerm s none @@ -378,7 +378,7 @@ elab:max "mfderiv[" s:term:arg "]" t:term:arg : term => do return ← mkAppM ``mfderivWithin #[srcI, tgtI, e, es] | _ => throwError m!"Term {e} is not a function." -/-- `mfderiv f x` elaborates to `mfderiv I J f x`, +/-- `mfderiv% f x` elaborates to `mfderiv I J f x`, trying to determine `I` and `J` from the local context. -/ elab:max "mfderiv%" t:term:arg : term => do let e ← Term.elabTerm t none From fb21400b8e9424af37c01d9512f19e637d68be4a Mon Sep 17 00:00:00 2001 From: Michael Rothgang Date: Tue, 30 Sep 2025 08:37:29 +0200 Subject: [PATCH 019/106] Document trace classes --- Mathlib/Geometry/Manifold/Traces.lean | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/Mathlib/Geometry/Manifold/Traces.lean b/Mathlib/Geometry/Manifold/Traces.lean index e364b875fb2cdc..83cdf708992932 100644 --- a/Mathlib/Geometry/Manifold/Traces.lean +++ b/Mathlib/Geometry/Manifold/Traces.lean @@ -8,8 +8,16 @@ import Lean.Util.Trace /-! # Trace classes for differential geometry elaborators -TODO: add a more complete doc-string +This file defines custom trace classes for the differential geometry elaborators in +`Mathlib.Geometry.Manifold.Elaborators.lean`. These need to be in a different file for technical +reasons. +The `TotalSpaceMk` trace class is associated to the `T%` elaborator, which converts a section +of a vector bundle as a dependent function to a non-dependent function into the total space. + +The `MDiffElab` trace class corresponds to the elaborators `CMDiff` and friends, and provides +tracing information about inferring a model with corners on the domain (resp. codomain) of the +map in question. -/ open Lean From 24ce05bb67c3f45ff70b0a07803da86cd5751e41 Mon Sep 17 00:00:00 2001 From: Michael Rothgang Date: Tue, 30 Sep 2025 08:51:17 +0200 Subject: [PATCH 020/106] Document product case better --- Mathlib/Geometry/Manifold/Elaborators.lean | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Mathlib/Geometry/Manifold/Elaborators.lean b/Mathlib/Geometry/Manifold/Elaborators.lean index 61f6ba7396a820..9425d8f54cd646 100644 --- a/Mathlib/Geometry/Manifold/Elaborators.lean +++ b/Mathlib/Geometry/Manifold/Elaborators.lean @@ -29,6 +29,11 @@ In each of these cases, the models with corners are inferred from the domain and The search for models with corners uses the local context and is (almost) only syntactic, hence hopefully fast enough to always run. +This has no dedicated support for product manifolds (or product vector spaces) yet; +adding this is left for future changes. (It would make need to make a choice between e.g. the +trivial model with corners on a product `E × F` and the product of the trivial models on `E` and +`F`). + Secondly, this space adds an elaborator to ease working with sections in a fibre bundle, converting a section `s : Π x : M, Π V x` to a non-dependent function into the total space of the bundle. @@ -54,9 +59,11 @@ prototype. Don't rewrite all of mathlib to use it just yet. Notable bugs and lim the following. ## TODO -- extend the feature to infer e.g. models with corners on product manifolds +- extend the elaborator to guess models with corners on product manifolds (this has to make a guess, hence cannot always be correct: but it could make the guess that is correct 90% of the time) + For products of vector spaces `E × F`, this could print a warning about making a choice between + the model in `E × F` and the product of the models on `E` and `F`. - fix pretty-printing: currently, the `commandStart` linter expects some different formatting - better error messages: forgetting e.g. the `T%` elaborator yields cryptic errors - further testing and fixing of edge cases From 0ab1b3be0ab3fb960749d5422878b6649f885269 Mon Sep 17 00:00:00 2001 From: Michael Rothgang Date: Tue, 30 Sep 2025 08:55:19 +0200 Subject: [PATCH 021/106] Clarify cryptic TODO --- Mathlib/Geometry/Manifold/Elaborators.lean | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Mathlib/Geometry/Manifold/Elaborators.lean b/Mathlib/Geometry/Manifold/Elaborators.lean index 9425d8f54cd646..3f57ef34f82a88 100644 --- a/Mathlib/Geometry/Manifold/Elaborators.lean +++ b/Mathlib/Geometry/Manifold/Elaborators.lean @@ -67,7 +67,6 @@ the following. - fix pretty-printing: currently, the `commandStart` linter expects some different formatting - better error messages: forgetting e.g. the `T%` elaborator yields cryptic errors - further testing and fixing of edge cases -- add test for the difference between `CMDiff` and `ContMDiff%` (and decide on one behaviour) - added tests for all of the above - add delaborators for these elaborators @@ -361,6 +360,9 @@ trying to determine `I` and `J` from the local context. -/ elab:max "CMDiff" nt:term:arg f:term:arg : term => do let e ← Term.elabTerm f none let wtn ← Term.elabTerm (← `(WithTop ℕ∞)) none + -- TODO: add a test demonstrating this having this line instead would change behaviour. + -- and decide on which behaviour I prefer! + -- let ne ← Term.elabTermEnsuringType nt wtn let ne ← Term.elabTerm nt wtn let etype ← inferType e >>= instantiateMVars match etype with From 9c3f38a992d8497e7b5f21b9862f0c9542dbb8b1 Mon Sep 17 00:00:00 2001 From: Michael Rothgang Date: Tue, 30 Sep 2025 09:01:40 +0200 Subject: [PATCH 022/106] chore: structure the tests better --- MathlibTest/DifferentialGeometry/Elaborators.lean | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/MathlibTest/DifferentialGeometry/Elaborators.lean b/MathlibTest/DifferentialGeometry/Elaborators.lean index 51ee4fa8419c69..16ba8c99bafb79 100644 --- a/MathlibTest/DifferentialGeometry/Elaborators.lean +++ b/MathlibTest/DifferentialGeometry/Elaborators.lean @@ -34,7 +34,7 @@ variable (F : Type*) [NormedAddCommGroup F] [NormedSpace 𝕜 F] [FiberBundle F V] [VectorBundle 𝕜 F V] -- `V` vector bundle --- Tests for the T% elaborator, inserting calls to TotalSpace.mk' automatically. +/-! Tests for the `T%` elaborator, inserting calls to `TotalSpace.mk'` automatically. -/ section TotalSpace variable {σ : Π x : M, V x} @@ -85,7 +85,7 @@ example : (fun m ↦ (X m : TangentBundle I M)) = (fun m ↦ TotalSpace.mk' E m end TotalSpace --- Elaborators for MDifferentiable{WithinAt,At,On}. +/-! Tests for the elaborators for `MDifferentiable{WithinAt,At,On}`. -/ section differentiability -- Start with some basic tests: a simple function, both in applied and unapplied form. @@ -297,6 +297,14 @@ info: MDifferentiableAt 𝓘(𝕜, E) (𝓘(𝕜, E).prod 𝓘(𝕜, E')) fun x end differentiability +/-! Tests for the custom elaborators for `ContMDiff{WithinAt,At,On}` -/ +section smoothness + +-- TODO: add actual tests! + +end smoothness + +/-! Tests for the custom elaborators for `mfderiv` and `mfderivWithin` -/ section mfderiv variable {EM' : Type*} [NormedAddCommGroup EM'] From 5785f533191c96c822d22203731711a26bee38d3 Mon Sep 17 00:00:00 2001 From: Michael Rothgang Date: Tue, 30 Sep 2025 09:25:37 +0200 Subject: [PATCH 023/106] chore: add many tests for the CMDiffAt elaborators --- .../DifferentialGeometry/Elaborators.lean | 192 +++++++++++++++++- 1 file changed, 191 insertions(+), 1 deletion(-) diff --git a/MathlibTest/DifferentialGeometry/Elaborators.lean b/MathlibTest/DifferentialGeometry/Elaborators.lean index 16ba8c99bafb79..3f11868833da81 100644 --- a/MathlibTest/DifferentialGeometry/Elaborators.lean +++ b/MathlibTest/DifferentialGeometry/Elaborators.lean @@ -300,7 +300,197 @@ end differentiability /-! Tests for the custom elaborators for `ContMDiff{WithinAt,At,On}` -/ section smoothness --- TODO: add actual tests! +-- Copy-pasted the tests for differentiability mutatis mutandis. +-- Start with some basic tests: a simple function, both in applied and unapplied form. +variable {EM' : Type*} [NormedAddCommGroup EM'] + [NormedSpace 𝕜 EM'] {H' : Type*} [TopologicalSpace H'] (I' : ModelWithCorners 𝕜 EM' H') + {M' : Type*} [TopologicalSpace M'] [ChartedSpace H' M'] + +-- TODO: add tests for the error message when smoothness hypotheses are missing + +-- General case: a function between two manifolds. +variable {f : M → M'} {s : Set M} {m : M} + +variable [IsManifold I 1 M] [IsManifold I' 1 M'] + +-- TODO: can there be better error messages when forgetting the smoothness exponent? +section error + +-- yields a parse error, "unexpected toekn '/--'; expected term" +-- #check CMDiffAt[s] f + +/-- error: Term m is not a function. -/ +#guard_msgs in +#check CMDiffAt[s] f m + +/-- error: Term m is not a function. -/ +#guard_msgs in +#check CMDiffAt[s] f m + +-- yields a parse error, "unexpected toekn '/--'; expected term" +-- #check CMDiffAt f + +end error + +/-- info: ContMDiffWithinAt I I' 1 f s : M → Prop -/ +#guard_msgs in +#check CMDiffAt[s] 1 f + +/-- info: ContMDiffWithinAt I I' 1 f s m : Prop -/ +#guard_msgs in +#check CMDiffAt[s] 1 f m + +/-- info: ContMDiffWithinAt I I' 1 f s m : Prop -/ +#guard_msgs in +#check CMDiffAt[s] 1 f m + +/-- info: ContMDiffAt I I' 1 f : M → Prop -/ +#guard_msgs in +#check CMDiffAt 1 f + +/-- info: ContMDiffAt I I' 2 f m : Prop -/ +#guard_msgs in +#check CMDiffAt 2 f m + +/-- info: ContMDiffOn I I' 37 f s : Prop -/ +#guard_msgs in +#check CMDiff[s] 37 f + +-- Testing an error message. +section + +/-- +error: Function expected at + ContMDiffOn I I' 2 f s +but this term has type + Prop + +Note: Expected a function because this term is being applied to the argument + m +-/ +#guard_msgs in +#check CMDiff[s] 2 f m + +variable {n : WithTop ℕ∞} {k : ℕ} {k' : ℕ∞} +/-- +error: Function expected at + ContMDiffOn I I' n f s +but this term has type + Prop + +Note: Expected a function because this term is being applied to the argument + m +-/ +#guard_msgs in +#check ContMDiffOn I I' n f s m + +/-- info: MDifferentiable I I' f : Prop -/ +#guard_msgs in +#check MDiff f + +/-- +error: Function expected at + ContMDiff I I' n f +but this term has type + Prop + +Note: Expected a function because this term is being applied to the argument + m +-/ +#guard_msgs in +#check CMDiff n f m + +end + +-- Tests for coercions from ℕ or ℕ∞ to Withtop ℕ∞. +-- TODO: decide on the correct behaviour and update the tests accordingly! +section coercions +-- TODO: add them +end coercions + +-- Function from a manifold into a normed space. +variable {g : M → E} + +/-- info: ContMDiffWithinAt I 𝓘(𝕜, E) 1 g s : M → Prop -/ +#guard_msgs in +#check CMDiffAt[s] 1 g +/-- info: ContMDiffWithinAt I 𝓘(𝕜, E) 0 g s m : Prop -/ +#guard_msgs in +#check CMDiffAt[s] 0 g m +/-- info: ContMDiffAt I 𝓘(𝕜, E) 1 g : M → Prop -/ +#guard_msgs in +#check CMDiffAt 1 g +/-- info: ContMDiffAt I 𝓘(𝕜, E) 1 g m : Prop -/ +#guard_msgs in +#check CMDiffAt 1 g m +/-- info: ContMDiffOn I 𝓘(𝕜, E) n g s : Prop -/ +#guard_msgs in +#check CMDiff[s] n g +-- TODO: fix and enable! #check CMDiff[s] n g m +/-- info: ContMDiff I 𝓘(𝕜, E) n g : Prop -/ +#guard_msgs in +#check CMDiff n g +-- TODO: fix and enable! #check CMDiff n g m + +-- From a manifold into a field. +variable {h : M → 𝕜} + +/-- info: ContMDiffWithinAt I 𝓘(𝕜, 𝕜) 0 h s : M → Prop -/ +#guard_msgs in +#check CMDiffAt[s] 0 h +/-- info: ContMDiffWithinAt I 𝓘(𝕜, 𝕜) 1 h s m : Prop -/ +#guard_msgs in +#check CMDiffAt[s] 1 h m +/-- info: ContMDiffAt I 𝓘(𝕜, 𝕜) 2 h : M → Prop -/ +#guard_msgs in +#check CMDiffAt 2 h +/-- info: ContMDiffAt I 𝓘(𝕜, 𝕜) n h m : Prop -/ +#guard_msgs in +#check CMDiffAt n h m +/-- info: ContMDiffOn I 𝓘(𝕜, 𝕜) n h s : Prop -/ +#guard_msgs in +#check CMDiff[s] n h +-- TODO: fix and enable! #check CMDiff[s] n h m +/-- info: ContMDiff I 𝓘(𝕜, 𝕜) 37 h : Prop -/ +#guard_msgs in +#check CMDiff 37 h +-- TODO: fix and enable! #check CMDiff 0 h m + +-- The following tests are more spotty, as most code paths are already covered above. +-- Add further details as necessary. +-- This list mirrors some of the tests for `MDifferentiable{WithinAt,At,On}`, but not all. + +-- From a normed space into a manifold. +variable {f : E → M'} {s : Set E} {x : E} +/-- info: ContMDiffWithinAt 𝓘(𝕜, E) I' 2 f s : E → Prop -/ +#guard_msgs in +#check CMDiffAt[s] 2 f +/-- info: ContMDiffAt 𝓘(𝕜, E) I' 3 f x : Prop -/ +#guard_msgs in +#check CMDiffAt 3 f x +-- TODO: fix and enable! #check CMDiff[s] 1 f x +/-- info: ContMDiff 𝓘(𝕜, E) I' 1 f : Prop -/ +#guard_msgs in +#check CMDiff 1 f +-- TODO: should this error? if not, fix and enable! #check CMDiff 1 f x +-- same! #check MDifferentiable% f x + +-- Between normed spaces. +variable {f : E → E'} {s : Set E} {x : E} + +/-- info: ContMDiffAt 𝓘(𝕜, E) 𝓘(𝕜, E') 2 f x : Prop -/ +#guard_msgs in +#check CMDiffAt 2 f x +/-- info: ContMDiffAt 𝓘(𝕜, E) 𝓘(𝕜, E') 2 f : E → Prop -/ +#guard_msgs in +#check CMDiffAt 2 f +-- should this error or not? #check CMDiff[s] 2 f x +/-- info: ContMDiffWithinAt 𝓘(𝕜, E) 𝓘(𝕜, E') 2 f s : E → Prop -/ +#guard_msgs in +#check CMDiffAt[s] 2 f +/-- info: ContMDiffOn 𝓘(𝕜, E) 𝓘(𝕜, E') 2 f s : Prop -/ +#guard_msgs in +#check CMDiff[s] 2 f end smoothness From 4a9a4544a3bf87af52b51b7969fd1993251541ae Mon Sep 17 00:00:00 2001 From: Michael Rothgang Date: Tue, 30 Sep 2025 09:28:51 +0200 Subject: [PATCH 024/106] chore: add tests about coercion behaviour --- .../DifferentialGeometry/Elaborators.lean | 98 ++++++++++++++++++- 1 file changed, 96 insertions(+), 2 deletions(-) diff --git a/MathlibTest/DifferentialGeometry/Elaborators.lean b/MathlibTest/DifferentialGeometry/Elaborators.lean index 3f11868833da81..db00f81d976c28 100644 --- a/MathlibTest/DifferentialGeometry/Elaborators.lean +++ b/MathlibTest/DifferentialGeometry/Elaborators.lean @@ -371,7 +371,7 @@ Note: Expected a function because this term is being applied to the argument #guard_msgs in #check CMDiff[s] 2 f m -variable {n : WithTop ℕ∞} {k : ℕ} {k' : ℕ∞} +variable {n : WithTop ℕ∞} /-- error: Function expected at ContMDiffOn I I' n f s @@ -405,7 +405,101 @@ end -- Tests for coercions from ℕ or ℕ∞ to Withtop ℕ∞. -- TODO: decide on the correct behaviour and update the tests accordingly! section coercions --- TODO: add them + +variable {k : ℕ} {k' : ℕ∞} + +/-- info: ContMDiffWithinAt I I' 0 f s : M → Prop -/ +#guard_msgs in +#check CMDiffAt[s] 0 f + +/-- info: ContMDiffWithinAt I I' 1 f s : M → Prop -/ +#guard_msgs in +#check CMDiffAt[s] 1 f + +/-- info: ContMDiffWithinAt I I' 37 f s : M → Prop -/ +#guard_msgs in +#check CMDiffAt[s] 37 f + +/-- +error: Application type mismatch: In the application + ContMDiffWithinAt I I' k +the argument + k +has type + ℕ : Type +but is expected to have type + WithTop ℕ∞ : Type +-/ +#guard_msgs in +#check CMDiffAt[s] k f + +/-- +error: Application type mismatch: In the application + ContMDiffWithinAt I I' k' +the argument + k' +has type + ℕ∞ : Type +but is expected to have type + WithTop ℕ∞ : Type +-/ +#guard_msgs in +#check CMDiffAt[s] k' f m + +/-- info: ContMDiffWithinAt I I' n f s m : Prop -/ +#guard_msgs in +#check CMDiffAt[s] n f m + +/-- info: ContMDiffAt I I' (↑k) f : M → Prop -/ +#guard_msgs in +#check CMDiffAt k f + +/-- info: ContMDiffAt I I' (↑k') f m : Prop -/ +#guard_msgs in +#check CMDiffAt k' f m + +/-- info: ContMDiffOn I I' (↑k) f s : Prop -/ +#guard_msgs in +#check CMDiff[s] k f + +/-- +error: Function expected at + ContMDiffOn I I' (↑k') f s +but this term has type + Prop + +Note: Expected a function because this term is being applied to the argument + m +-/ +#guard_msgs in +#check CMDiff[s] k' f m + +/-- +error: Application type mismatch: In the application + ContMDiff I I' k +the argument + k +has type + ℕ : Type +but is expected to have type + WithTop ℕ∞ : Type +-/ +#guard_msgs in +#check CMDiff k f + +/-- +error: Application type mismatch: In the application + ContMDiff I I' k' +the argument + k' +has type + ℕ∞ : Type +but is expected to have type + WithTop ℕ∞ : Type +-/ +#guard_msgs in +#check CMDiff k' f m + end coercions -- Function from a manifold into a normed space. From aa520d0d30c3a09d9dcccdcfcf390205f5ce3f9e Mon Sep 17 00:00:00 2001 From: Michael Rothgang Date: Tue, 30 Sep 2025 09:54:16 +0200 Subject: [PATCH 025/106] Support coercion n to WithTop ENat everywhere. --- Mathlib/Geometry/Manifold/Elaborators.lean | 16 ++-- .../DifferentialGeometry/Elaborators.lean | 73 ++++++++----------- 2 files changed, 39 insertions(+), 50 deletions(-) diff --git a/Mathlib/Geometry/Manifold/Elaborators.lean b/Mathlib/Geometry/Manifold/Elaborators.lean index 3f57ef34f82a88..ee1ae0c90ba6a5 100644 --- a/Mathlib/Geometry/Manifold/Elaborators.lean +++ b/Mathlib/Geometry/Manifold/Elaborators.lean @@ -304,15 +304,15 @@ elab:max "MDiff" t:term:arg : term => do return ← mkAppM ``MDifferentiable #[srcI, tgtI, e] | _ => throwError m!"Term {e} is not a function." --- TODO: say something about the expected type of `n` being in ℕ or WithTop ℕ∞! /-- `CMDiffAt[s] n f x` elaborates to `ContMDiffWithinAt I J n f s x`, trying to determine `I` and `J` from the local context. +`n` is coerced to `WithTop ℕ∞` if necessary (so passing a `ℕ`, `∞` or `ω` are all supported). The argument `x` can be omitted. -/ elab:max "CMDiffAt[" s:term:arg "]" nt:term:arg f:term:arg : term => do let es ← Term.elabTerm s none let ef ← Term.elabTerm f none let wtn ← Term.elabTerm (← `(WithTop ℕ∞)) none - let ne ← Term.elabTerm nt wtn + let ne ← Term.elabTermEnsuringType nt wtn let _estype ← inferType es >>= instantiateMVars let eftype ← inferType ef >>= instantiateMVars match eftype with @@ -325,6 +325,7 @@ elab:max "CMDiffAt[" s:term:arg "]" nt:term:arg f:term:arg : term => do /-- `CMDiffAt n f x` elaborates to `ContMDiffAt I J n f x` trying to determine `I` and `J` from the local context. +`n` is coerced to `WithTop ℕ∞` if necessary (so passing a `ℕ`, `∞` or `ω` are all supported). The argument `x` can be omitted. -/ elab:max "CMDiffAt" nt:term:arg t:term:arg : term => do let e ← Term.elabTerm t none @@ -339,7 +340,8 @@ elab:max "CMDiffAt" nt:term:arg t:term:arg : term => do | _ => throwError m!"Term {e} is not a function." /-- `CMDiff[s] n f` elaborates to `ContMDiffOn I J n f s`, -trying to determine `I` and `J` from the local context. -/ +trying to determine `I` and `J` from the local context. +`n` is coerced to `WithTop ℕ∞` if necessary (so passing a `ℕ`, `∞` or `ω` are all supported). -/ elab:max "CMDiff[" s:term:arg "]" nt:term:arg f:term:arg : term => do let es ← Term.elabTerm s none let ef ← Term.elabTerm f none @@ -356,14 +358,12 @@ elab:max "CMDiff[" s:term:arg "]" nt:term:arg f:term:arg : term => do | _ => throwError m!"Term {ef} is not a function." /-- `CMDiff n f` elaborates to `ContMDiff I J n f`, -trying to determine `I` and `J` from the local context. -/ +trying to determine `I` and `J` from the local context. +`n` is coerced to `WithTop ℕ∞` if necessary (so passing a `ℕ`, `∞` or `ω` are all supported). -/ elab:max "CMDiff" nt:term:arg f:term:arg : term => do let e ← Term.elabTerm f none let wtn ← Term.elabTerm (← `(WithTop ℕ∞)) none - -- TODO: add a test demonstrating this having this line instead would change behaviour. - -- and decide on which behaviour I prefer! - -- let ne ← Term.elabTermEnsuringType nt wtn - let ne ← Term.elabTerm nt wtn + let ne ← Term.elabTermEnsuringType nt wtn let etype ← inferType e >>= instantiateMVars match etype with | .forallE _ src tgt _ => diff --git a/MathlibTest/DifferentialGeometry/Elaborators.lean b/MathlibTest/DifferentialGeometry/Elaborators.lean index db00f81d976c28..26aa7826886dd7 100644 --- a/MathlibTest/DifferentialGeometry/Elaborators.lean +++ b/MathlibTest/DifferentialGeometry/Elaborators.lean @@ -319,11 +319,29 @@ section error -- yields a parse error, "unexpected toekn '/--'; expected term" -- #check CMDiffAt[s] f -/-- error: Term m is not a function. -/ +/-- +error: type mismatch + f +has type + M → M' : Type (max u_10 u_4) +but is expected to have type + WithTop ℕ∞ : Type +--- +error: Term m is not a function. +-/ #guard_msgs in #check CMDiffAt[s] f m -/-- error: Term m is not a function. -/ +/-- +error: type mismatch + f +has type + M → M' : Type (max u_10 u_4) +but is expected to have type + WithTop ℕ∞ : Type +--- +error: Term m is not a function. +-/ #guard_msgs in #check CMDiffAt[s] f m @@ -402,8 +420,7 @@ Note: Expected a function because this term is being applied to the argument end --- Tests for coercions from ℕ or ℕ∞ to Withtop ℕ∞. --- TODO: decide on the correct behaviour and update the tests accordingly! +/-! Tests for coercions from `ℕ` or `ℕ∞` to `WithTop ℕ∞` -/ section coercions variable {k : ℕ} {k' : ℕ∞} @@ -420,29 +437,11 @@ variable {k : ℕ} {k' : ℕ∞} #guard_msgs in #check CMDiffAt[s] 37 f -/-- -error: Application type mismatch: In the application - ContMDiffWithinAt I I' k -the argument - k -has type - ℕ : Type -but is expected to have type - WithTop ℕ∞ : Type --/ +/-- info: ContMDiffWithinAt I I' (↑k) f s : M → Prop -/ #guard_msgs in #check CMDiffAt[s] k f -/-- -error: Application type mismatch: In the application - ContMDiffWithinAt I I' k' -the argument - k' -has type - ℕ∞ : Type -but is expected to have type - WithTop ℕ∞ : Type --/ +/-- info: ContMDiffWithinAt I I' (↑k') f s m : Prop -/ #guard_msgs in #check CMDiffAt[s] k' f m @@ -474,28 +473,18 @@ Note: Expected a function because this term is being applied to the argument #guard_msgs in #check CMDiff[s] k' f m -/-- -error: Application type mismatch: In the application - ContMDiff I I' k -the argument - k -has type - ℕ : Type -but is expected to have type - WithTop ℕ∞ : Type --/ +/-- info: ContMDiff I I' (↑k) f : Prop -/ #guard_msgs in #check CMDiff k f /-- -error: Application type mismatch: In the application - ContMDiff I I' k' -the argument - k' -has type - ℕ∞ : Type -but is expected to have type - WithTop ℕ∞ : Type +error: Function expected at + ContMDiff I I' (↑k') f +but this term has type + Prop + +Note: Expected a function because this term is being applied to the argument + m -/ #guard_msgs in #check CMDiff k' f m From a5ff9ea3ca747d10bf6d50ee8d590a6821948338 Mon Sep 17 00:00:00 2001 From: Michael Rothgang Date: Tue, 30 Sep 2025 11:05:47 +0200 Subject: [PATCH 026/106] fix: guard against loose bvars, i.e. non-dependent functions This fixes the cryptic 'unknown identifier #0' errors I saw previous, and provides a *much* nicer error message. --- Mathlib/Geometry/Manifold/Elaborators.lean | 30 ++++ .../DifferentialGeometry/Elaborators.lean | 143 ++++++++++++++++++ 2 files changed, 173 insertions(+) diff --git a/Mathlib/Geometry/Manifold/Elaborators.lean b/Mathlib/Geometry/Manifold/Elaborators.lean index ee1ae0c90ba6a5..60e8bd4a49ed4d 100644 --- a/Mathlib/Geometry/Manifold/Elaborators.lean +++ b/Mathlib/Geometry/Manifold/Elaborators.lean @@ -259,6 +259,9 @@ elab:max "MDiffAt[" s:term:arg "]" f:term:arg : term => do match etype with | .forallE _ src tgt _ => let srcI ← find_model src + if Lean.Expr.hasLooseBVars tgt then + throwError m!"Term {ef} is a dependent function, of type {etype}\n\ + Note: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one" let tgtI ← find_model tgt (src, srcI) -- TODO: check that `estype` and src are compatible/the same! return ← mkAppM ``MDifferentiableWithinAt #[srcI, tgtI, ef, es] @@ -273,6 +276,9 @@ elab:max "MDiffAt" t:term:arg : term => do match etype with | .forallE _ src tgt _ => let srcI ← find_model src + if Lean.Expr.hasLooseBVars tgt then + throwError m!"Term {e} is a dependent function, of type {etype}\n\ + Note: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one" let tgtI ← find_model tgt (src, srcI) return ← mkAppM ``MDifferentiableAt #[srcI, tgtI, e] | _ => throwError m!"Term {e} is not a function." @@ -287,6 +293,9 @@ elab:max "MDiff[" s:term:arg "]" t:term:arg : term => do match etype with | .forallE _ src tgt _ => let srcI ← find_model src + if Lean.Expr.hasLooseBVars tgt then + throwError m!"Term {et} is a dependent function, of type {etype}\n\ + Note: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one" let tgtI ← find_model tgt (src, srcI) -- TODO: check that `estype` and src are compatible/the same! return ← mkAppM ``MDifferentiableOn #[srcI, tgtI, et, es] @@ -300,6 +309,9 @@ elab:max "MDiff" t:term:arg : term => do match etype with | .forallE _ src tgt _ => let srcI ← find_model src + if Lean.Expr.hasLooseBVars tgt then + throwError m!"Term {e} is a dependent function, of type {etype}\n\ + Note: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one" let tgtI ← find_model tgt (src, srcI) return ← mkAppM ``MDifferentiable #[srcI, tgtI, e] | _ => throwError m!"Term {e} is not a function." @@ -318,6 +330,9 @@ elab:max "CMDiffAt[" s:term:arg "]" nt:term:arg f:term:arg : term => do match eftype with | .forallE _ src tgt _ => let srcI ← find_model src + if Lean.Expr.hasLooseBVars tgt then + throwError m!"Term {ef} is a dependent function, of type {eftype}\n\ + Note: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one" let tgtI ← find_model tgt (src, srcI) -- TODO: check `estype` and src are compatible return ← mkAppM ``ContMDiffWithinAt #[srcI, tgtI, ne, ef, es] @@ -335,6 +350,9 @@ elab:max "CMDiffAt" nt:term:arg t:term:arg : term => do match etype with | .forallE _ src tgt _ => let srcI ← find_model src + if Lean.Expr.hasLooseBVars tgt then + throwError m!"Term {e} is a dependent function, of type {etype}\n\ + Note: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one" let tgtI ← find_model tgt (src, srcI) return ← mkAppM ``ContMDiffAt #[srcI, tgtI, ne, e] | _ => throwError m!"Term {e} is not a function." @@ -352,6 +370,9 @@ elab:max "CMDiff[" s:term:arg "]" nt:term:arg f:term:arg : term => do match eftype with | .forallE _ src tgt _ => let srcI ← find_model src + if Lean.Expr.hasLooseBVars tgt then + throwError m!"Term {ef} is a dependent function, of type {eftype}\n\ + Note: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one" let tgtI ← find_model tgt (src, srcI) -- TODO: check `estype` and src are compatible return ← mkAppM ``ContMDiffOn #[srcI, tgtI, ne, ef, es] @@ -368,6 +389,9 @@ elab:max "CMDiff" nt:term:arg f:term:arg : term => do match etype with | .forallE _ src tgt _ => let srcI ← find_model src + if Lean.Expr.hasLooseBVars tgt then + throwError m!"Term {e} is a dependent function, of type {etype}\n\ + Note: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one" let tgtI ← find_model tgt (src, srcI) return ← mkAppM ``ContMDiff #[srcI, tgtI, ne, e] | _ => throwError m!"Term {e} is not a function." @@ -382,6 +406,9 @@ elab:max "mfderiv[" s:term:arg "]" t:term:arg : term => do match etype with | .forallE _ src tgt _ => let srcI ← find_model src + if Lean.Expr.hasLooseBVars tgt then + throwError m!"Term {e} is a dependent function, of type {etype}\n\ + Note: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one" let tgtI ← find_model tgt (src, srcI) -- TODO: check `estype` and src are compatible return ← mkAppM ``mfderivWithin #[srcI, tgtI, e, es] @@ -395,6 +422,9 @@ elab:max "mfderiv%" t:term:arg : term => do match etype with | .forallE _ src tgt _ => let srcI ← find_model src + if Lean.Expr.hasLooseBVars tgt then + throwError m!"Term {e} is a dependent function, of type {etype}\n\ + Note: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one" let tgtI ← find_model tgt (src, srcI) return ← mkAppM `mfderiv #[srcI, tgtI, e] | _ => throwError m!"Term {e} is not a function." diff --git a/MathlibTest/DifferentialGeometry/Elaborators.lean b/MathlibTest/DifferentialGeometry/Elaborators.lean index 26aa7826886dd7..3345d4df3c3e41 100644 --- a/MathlibTest/DifferentialGeometry/Elaborators.lean +++ b/MathlibTest/DifferentialGeometry/Elaborators.lean @@ -117,6 +117,8 @@ variable {f : M → M'} {s : Set M} {m : M} #check MDiff[s] f -- Testing an error message. +section + /-- error: Function expected at MDifferentiableOn I I' f s @@ -157,6 +159,8 @@ Note: Expected a function because this term is being applied to the argument #guard_msgs in #check MDiff f m +end + -- Function from a manifold into a normed space. variable {g : M → E} @@ -295,6 +299,74 @@ info: MDifferentiableAt 𝓘(𝕜, E) (𝓘(𝕜, E).prod 𝓘(𝕜, E')) fun x #guard_msgs in #check MDiffAt (T% σ') +/-! Error messages in case of a forgotten `T%`. -/ +section + +/-- +error: Term X is a dependent function, of type (m : M) → TangentSpace I m +Note: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one +-/ +#guard_msgs in +#check MDiff X + +/-- +error: Term σ is a dependent function, of type (x : M) → V x +Note: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one +-/ +#guard_msgs in +#check MDiff σ + +/-- +error: Term σ' is a dependent function, of type (x : E) → Trivial E E' x +Note: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one +-/ +#guard_msgs in +#check MDiff σ' + +/-- +error: Term σ' is a dependent function, of type (x : E) → Trivial E E' x +Note: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one +-/ +#guard_msgs in +#check MDiff[s] σ' + +/-- +error: Term X is a dependent function, of type (m : M) → TangentSpace I m +Note: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one +-/ +#guard_msgs in +#check MDiffAt (X) + +/-- +error: Term σ is a dependent function, of type (x : M) → V x +Note: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one +-/ +#guard_msgs in +#check MDiffAt ((σ)) + +/-- +error: Term σ' is a dependent function, of type (x : E) → Trivial E E' x +Note: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one +-/ +#guard_msgs in +#check MDiff[s] σ' + +/-- +error: Term σ' is a dependent function, of type (x : E) → Trivial E E' x +Note: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one +-/ +#guard_msgs in +#check MDiffAt σ' + +/-- +error: Term σ' is a dependent function, of type (x : E) → Trivial E E' x +Note: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one +-/ +#guard_msgs in +#check MDiffAt[s] σ' + +end + end differentiability /-! Tests for the custom elaborators for `ContMDiff{WithinAt,At,On}` -/ @@ -491,6 +563,77 @@ Note: Expected a function because this term is being applied to the argument end coercions +/-! Error messages for a missing `T%` elaborator. -/ +section dependent + +variable {σ : Π x : M, V x} {σ' : (x : E) → Trivial E E' x} {s : E → E'} +variable (X : (m : M) → TangentSpace I m) [IsManifold I 1 M] + +/-- +error: Term X is a dependent function, of type (m : M) → TangentSpace I m +Note: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one +-/ +#guard_msgs in +#check CMDiff 0 X + +/-- +error: Term σ is a dependent function, of type (x : M) → V x +Note: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one +-/ +#guard_msgs in +#check CMDiff 0 σ + +/-- +error: Term σ' is a dependent function, of type (x : E) → Trivial E E' x +Note: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one +-/ +#guard_msgs in +#check CMDiff 0 σ' + +/-- +error: Term σ' is a dependent function, of type (x : E) → Trivial E E' x +Note: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one +-/ +#guard_msgs in +#check CMDiff[s] 0 σ' + +/-- +error: Term X is a dependent function, of type (m : M) → TangentSpace I m +Note: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one +-/ +#guard_msgs in +#check CMDiffAt 0 (X) + +/-- +error: Term σ is a dependent function, of type (x : M) → V x +Note: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one +-/ +#guard_msgs in +#check CMDiffAt 0 ((σ)) + +/-- +error: Term σ' is a dependent function, of type (x : E) → Trivial E E' x +Note: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one +-/ +#guard_msgs in +#check CMDiff[s] 0 σ' + +/-- +error: Term σ' is a dependent function, of type (x : E) → Trivial E E' x +Note: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one +-/ +#guard_msgs in +#check CMDiffAt 0 σ' + +/-- +error: Term σ' is a dependent function, of type (x : E) → Trivial E E' x +Note: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one +-/ +#guard_msgs in +#check CMDiffAt[s] 0 σ' + +end dependent + -- Function from a manifold into a normed space. variable {g : M → E} From 1923717a31fae1514029020997b4c0123f90bae7 Mon Sep 17 00:00:00 2001 From: Michael Rothgang Date: Tue, 30 Sep 2025 11:31:20 +0200 Subject: [PATCH 027/106] Add tests for mfderiv and dependent fns also The dependent function warning was added in the previous commit. --- .../DifferentialGeometry/Elaborators.lean | 67 +++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/MathlibTest/DifferentialGeometry/Elaborators.lean b/MathlibTest/DifferentialGeometry/Elaborators.lean index 3345d4df3c3e41..b6170c414cb0c1 100644 --- a/MathlibTest/DifferentialGeometry/Elaborators.lean +++ b/MathlibTest/DifferentialGeometry/Elaborators.lean @@ -771,6 +771,39 @@ info: mfderivWithin 𝓘(𝕜, E) 𝓘(𝕜, EM') f s m : TangentSpace 𝓘(𝕜 #guard_msgs in #check mfderiv[s] f m +variable {σ : Π x : M, V x} {σ' : (x : E) → Trivial E E' x} {s : E → E'} +variable (X : (m : M) → TangentSpace I m) [IsManifold I 1 M] {x : M} + +/-- +info: mfderiv I (I.prod 𝓘(𝕜, E)) (fun m ↦ TotalSpace.mk' E m (X m)) + x : TangentSpace I x →L[𝕜] TangentSpace (I.prod 𝓘(𝕜, E)) (TotalSpace.mk' E x (X x)) +-/ +#guard_msgs in +#check mfderiv% (T% X) x + +/-- +info: mfderiv I (I.prod 𝓘(𝕜, F)) (fun x ↦ TotalSpace.mk' F x (σ x)) + x : TangentSpace I x →L[𝕜] TangentSpace (I.prod 𝓘(𝕜, F)) (TotalSpace.mk' F x (σ x)) +-/ +#guard_msgs in +#check mfderiv% (T% σ) x + +variable {t : Set E} {p : E} + +/-- +info: mfderivWithin 𝓘(𝕜, E) (𝓘(𝕜, E).prod 𝓘(𝕜, E')) (fun x ↦ TotalSpace.mk' E' x (σ' x)) t + p : TangentSpace 𝓘(𝕜, E) p →L[𝕜] TangentSpace (𝓘(𝕜, E).prod 𝓘(𝕜, E')) (TotalSpace.mk' E' p (σ' p)) +-/ +#guard_msgs in +#check mfderiv[t] (T% σ') p + +/-- +info: mfderivWithin 𝓘(𝕜, E) (𝓘(𝕜, E).prod 𝓘(𝕜, E')) (fun x ↦ TotalSpace.mk' E' x (σ' x)) + t : (x : E) → TangentSpace 𝓘(𝕜, E) x →L[𝕜] TangentSpace (𝓘(𝕜, E).prod 𝓘(𝕜, E')) (TotalSpace.mk' E' x (σ' x)) +-/ +#guard_msgs in +#check mfderiv[t] (T% σ') + section errors -- Test an error message, about mismatched types. @@ -820,4 +853,38 @@ but is expected to have type end errors +section + +/-- +error: Term X is a dependent function, of type (m : M) → TangentSpace I m +Note: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one +-/ +#guard_msgs in +#check mfderiv% X x + +/-- +error: Term σ is a dependent function, of type (x : M) → V x +Note: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one +-/ +#guard_msgs in +#check mfderiv% σ x + +variable {t : Set E} {p : E} + +/-- +error: Term σ' is a dependent function, of type (x : E) → Trivial E E' x +Note: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one +-/ +#guard_msgs in +#check mfderiv[t] σ' p + +/-- +error: Term σ' is a dependent function, of type (x : E) → Trivial E E' x +Note: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one +-/ +#guard_msgs in +#check mfderiv[t] σ' + +end + end mfderiv From 44f57dedce9b4e5ad3b56518e659582b5fafb0e9 Mon Sep 17 00:00:00 2001 From: Michael Rothgang Date: Tue, 30 Sep 2025 11:40:00 +0200 Subject: [PATCH 028/106] wip/refactor: use forallBoundedTelescope instead of manual matching As discussed in-person with Floris: this should be more robust, but currently fails (for reasons not yet understood). --- Mathlib/Geometry/Manifold/Elaborators.lean | 20 +++++++++++++++++++ .../DifferentialGeometry/Elaborators.lean | 14 +++++++++++++ 2 files changed, 34 insertions(+) diff --git a/Mathlib/Geometry/Manifold/Elaborators.lean b/Mathlib/Geometry/Manifold/Elaborators.lean index 60e8bd4a49ed4d..0c6bdc934931ae 100644 --- a/Mathlib/Geometry/Manifold/Elaborators.lean +++ b/Mathlib/Geometry/Manifold/Elaborators.lean @@ -283,6 +283,26 @@ elab:max "MDiffAt" t:term:arg : term => do return ← mkAppM ``MDifferentiableAt #[srcI, tgtI, e] | _ => throwError m!"Term {e} is not a function." +-- This implement is more robust (in theory), but currently fails tests. +-- TODO: investigate why, fix this and replace `MDiffAt` by this one! +/-- `MDiffAt2 f x` elaborates to `MDifferentiableAt I J f x`, +trying to determine `I` and `J` from the local context. +The argument `x` can be omitted. -/ +elab:max "MDiffAt2" t:term:arg : term => do + let e ← Term.elabTerm t none + let etype ← inferType e >>= instantiateMVars + forallBoundedTelescope etype (some 1) fun src tgt ↦ do + if let some src := src[0]? then + let srcI ← find_model src + if Lean.Expr.occurs src tgt then + throwError m!"Term {e} is a dependent function, of type {etype}\n\ + Note: you can use the 'T%' elaborator to convert a dependent function \ + to a non-dependent one" + let tgtI ← find_model tgt (src, srcI) + return ← mkAppM ``MDifferentiableAt #[srcI, tgtI, e] + else + throwError m!"Term {e} is not a function." + /-- `MDiff[s] f` elaborates to `MDifferentiableOn I J f s`, trying to determine `I` and `J` from the local context. -/ elab:max "MDiff[" s:term:arg "]" t:term:arg : term => do diff --git a/MathlibTest/DifferentialGeometry/Elaborators.lean b/MathlibTest/DifferentialGeometry/Elaborators.lean index b6170c414cb0c1..c9bd7c25e03bd6 100644 --- a/MathlibTest/DifferentialGeometry/Elaborators.lean +++ b/MathlibTest/DifferentialGeometry/Elaborators.lean @@ -108,6 +108,20 @@ variable {f : M → M'} {s : Set M} {m : M} #guard_msgs in #check MDiffAt f +-- TODO: understand why this fails and fix it! +/-- +error: Application type mismatch: In the application + @modelWithCornersSelf a✝ +the argument + a✝ +has type + M : Type u_4 +but is expected to have type + Type ?u.68271 : Type (?u.68271 + 1) +-/ +#guard_msgs in +#check MDiffAt2 f + /-- info: MDifferentiableAt I I' f m : Prop -/ #guard_msgs in #check MDiffAt f m From 734cb55fca34ca0330df1b7f8b5b0e7625a26f71 Mon Sep 17 00:00:00 2001 From: Michael Rothgang Date: Tue, 30 Sep 2025 11:46:42 +0200 Subject: [PATCH 029/106] Note another TODO --- Mathlib/Geometry/Manifold/Elaborators.lean | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Mathlib/Geometry/Manifold/Elaborators.lean b/Mathlib/Geometry/Manifold/Elaborators.lean index 0c6bdc934931ae..8a489e10e46be1 100644 --- a/Mathlib/Geometry/Manifold/Elaborators.lean +++ b/Mathlib/Geometry/Manifold/Elaborators.lean @@ -59,11 +59,13 @@ prototype. Don't rewrite all of mathlib to use it just yet. Notable bugs and lim the following. ## TODO -- extend the elaborator to guess models with corners on product manifolds +- extend the elaborators to guess models with corners on product manifolds (this has to make a guess, hence cannot always be correct: but it could make the guess that is correct 90% of the time) For products of vector spaces `E × F`, this could print a warning about making a choice between the model in `E × F` and the product of the models on `E` and `F`. +- extend the elaborators to support `PartialHomeomorph`s and `PartialEquiv`s + - fix pretty-printing: currently, the `commandStart` linter expects some different formatting - better error messages: forgetting e.g. the `T%` elaborator yields cryptic errors - further testing and fixing of edge cases From 44ecf374f3ea05b4195bfb5bc36a9d1d79408c0f Mon Sep 17 00:00:00 2001 From: Michael Rothgang Date: Tue, 30 Sep 2025 11:47:41 +0200 Subject: [PATCH 030/106] And another --- Mathlib/Geometry/Manifold/Elaborators.lean | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Mathlib/Geometry/Manifold/Elaborators.lean b/Mathlib/Geometry/Manifold/Elaborators.lean index 8a489e10e46be1..b943509d0c4019 100644 --- a/Mathlib/Geometry/Manifold/Elaborators.lean +++ b/Mathlib/Geometry/Manifold/Elaborators.lean @@ -153,6 +153,8 @@ to infer the expected type. This supports the following cases: Further cases can be added as necessary. This implementation is not maximally robust yet, but already useful. + +TODO: document what `baseInfo` is and how to use it! -/ -- FIXME: better failure when trying to find a `NormedField` instance def find_model (e : Expr) (baseInfo : Option (Expr × Expr) := none) : TermElabM Expr := do From c08dc09eb05cea3d959b82cba74824c0c27f1473 Mon Sep 17 00:00:00 2001 From: Michael Rothgang Date: Tue, 30 Sep 2025 14:12:16 +0200 Subject: [PATCH 031/106] Update error messages for merge --- .../DifferentialGeometry/Elaborators.lean | 66 ++++++++++--------- 1 file changed, 34 insertions(+), 32 deletions(-) diff --git a/MathlibTest/DifferentialGeometry/Elaborators.lean b/MathlibTest/DifferentialGeometry/Elaborators.lean index c9bd7c25e03bd6..89cf378dd0f073 100644 --- a/MathlibTest/DifferentialGeometry/Elaborators.lean +++ b/MathlibTest/DifferentialGeometry/Elaborators.lean @@ -110,14 +110,14 @@ variable {f : M → M'} {s : Set M} {m : M} -- TODO: understand why this fails and fix it! /-- -error: Application type mismatch: In the application - @modelWithCornersSelf a✝ -the argument +error: Application type mismatch: The argument a✝ has type - M : Type u_4 -but is expected to have type - Type ?u.68271 : Type (?u.68271 + 1) + M +of sort `Type u_4` but is expected to have type + Type ?u.60421 +of sort `Type (?u.60421 + 1)` in the application + @modelWithCornersSelf a✝ -/ #guard_msgs in #check MDiffAt2 f @@ -406,12 +406,13 @@ section error -- #check CMDiffAt[s] f /-- -error: type mismatch +error: Type mismatch f has type - M → M' : Type (max u_10 u_4) -but is expected to have type - WithTop ℕ∞ : Type + M → M' +of sort `Type (max u_10 u_4)` but is expected to have type + WithTop ℕ∞ +of sort `Type` --- error: Term m is not a function. -/ @@ -419,12 +420,13 @@ error: Term m is not a function. #check CMDiffAt[s] f m /-- -error: type mismatch +error: Type mismatch f has type - M → M' : Type (max u_10 u_4) -but is expected to have type - WithTop ℕ∞ : Type + M → M' +of sort `Type (max u_10 u_4)` but is expected to have type + WithTop ℕ∞ +of sort `Type` --- error: Term m is not a function. -/ @@ -824,14 +826,14 @@ section errors variable {s' : Set M} {m' : M} /-- -error: Application type mismatch: In the application - mfderiv 𝓘(𝕜, E) 𝓘(𝕜, EM') f m' -the argument +error: Application type mismatch: The argument m' has type - M : Type u_4 -but is expected to have type - E : Type u_2 + M +of sort `Type u_4` but is expected to have type + E +of sort `Type u_2` in the application + mfderiv 𝓘(𝕜, E) 𝓘(𝕜, EM') f m' --- info: mfderiv 𝓘(𝕜, E) 𝓘(𝕜, EM') f sorry : TangentSpace 𝓘(𝕜, E) sorry →L[𝕜] TangentSpace 𝓘(𝕜, EM') (f sorry) -/ @@ -840,27 +842,27 @@ info: mfderiv 𝓘(𝕜, E) 𝓘(𝕜, EM') f sorry : TangentSpace 𝓘(𝕜, E) -- Error messages: argument s has mismatched type. /-- -error: Application type mismatch: In the application - mfderivWithin 𝓘(𝕜, E) 𝓘(𝕜, EM') f s' -the argument +error: Application type mismatch: The argument s' has type - Set.{u_4} M : Type u_4 -but is expected to have type - Set.{u_2} E : Type u_2 + Set.{u_4} M +of sort `Type u_4` but is expected to have type + Set.{u_2} E +of sort `Type u_2` in the application + mfderivWithin 𝓘(𝕜, E) 𝓘(𝕜, EM') f s' -/ #guard_msgs in #check mfderiv[s'] f /-- -error: Application type mismatch: In the application - mfderivWithin 𝓘(𝕜, E) 𝓘(𝕜, EM') f s' -the argument +error: Application type mismatch: The argument s' has type - Set.{u_4} M : Type u_4 -but is expected to have type - Set.{u_2} E : Type u_2 + Set.{u_4} M +of sort `Type u_4` but is expected to have type + Set.{u_2} E +of sort `Type u_2` in the application + mfderivWithin 𝓘(𝕜, E) 𝓘(𝕜, EM') f s' -/ #guard_msgs in #check mfderiv[s'] f m From 86e3b1a039fd0c4ff97250fef1d09251b7822220 Mon Sep 17 00:00:00 2001 From: Michael Rothgang Date: Tue, 30 Sep 2025 14:16:23 +0200 Subject: [PATCH 032/106] One more check and test --- Mathlib/Geometry/Manifold/Elaborators.lean | 4 ++++ MathlibTest/DifferentialGeometry/Elaborators.lean | 9 +++++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/Mathlib/Geometry/Manifold/Elaborators.lean b/Mathlib/Geometry/Manifold/Elaborators.lean index b943509d0c4019..f3536c279d2878 100644 --- a/Mathlib/Geometry/Manifold/Elaborators.lean +++ b/Mathlib/Geometry/Manifold/Elaborators.lean @@ -135,6 +135,10 @@ elab:max "T% " t:term:arg : term => do let ut ← tgt.getUniverse -- TODO: can `tgt` depend on `x` in a way that is not a function application? -- Check that `x` is not a bound variable in `tgt`! + -- xxx: is this check fine or overzealous? + if Lean.Expr.hasLooseBVars tgt then + throwError m!"Term {tgt} has loose bound variables¬ + Note: applying the 'T%' elaborator twice makes no sense." let trivBundle := mkAppN (.const `Bundle.Trivial [us, ut]) #[src, tgt] return ← withLocalDecl x BinderInfo.default src fun x ↦ do let body := mkAppN (.const ``Bundle.TotalSpace.mk' [us, ut, ut]) diff --git a/MathlibTest/DifferentialGeometry/Elaborators.lean b/MathlibTest/DifferentialGeometry/Elaborators.lean index 89cf378dd0f073..766e004abe7e5c 100644 --- a/MathlibTest/DifferentialGeometry/Elaborators.lean +++ b/MathlibTest/DifferentialGeometry/Elaborators.lean @@ -83,6 +83,11 @@ example : (fun m ↦ (X m : TangentBundle I M)) = (fun m ↦ TotalSpace.mk' E m #guard_msgs in #check (T% X) x +-- Applying the same elaborator twice is fine (and idempotent). +/-- info: (fun m ↦ TotalSpace.mk' E m (X m)) x : TotalSpace E (TangentSpace I) -/ +#guard_msgs in +#check (T% (T% X)) x + end TotalSpace /-! Tests for the elaborators for `MDifferentiable{WithinAt,At,On}`. -/ @@ -115,8 +120,8 @@ error: Application type mismatch: The argument has type M of sort `Type u_4` but is expected to have type - Type ?u.60421 -of sort `Type (?u.60421 + 1)` in the application + Type ?u.63950 +of sort `Type (?u.63950 + 1)` in the application @modelWithCornersSelf a✝ -/ #guard_msgs in From 6277145c5184eee0da2cfb1690dadbd4589e9866 Mon Sep 17 00:00:00 2001 From: Michael Rothgang Date: Tue, 30 Sep 2025 15:22:38 +0200 Subject: [PATCH 033/106] chore: use Hint: instead of Note: This matches usage in Lean core. We are not providing further information about the error, but telling the user how they might fix it --- Mathlib/Geometry/Manifold/Elaborators.lean | 22 +++++----- .../DifferentialGeometry/Elaborators.lean | 44 +++++++++---------- 2 files changed, 33 insertions(+), 33 deletions(-) diff --git a/Mathlib/Geometry/Manifold/Elaborators.lean b/Mathlib/Geometry/Manifold/Elaborators.lean index f3536c279d2878..67ed49c672c8be 100644 --- a/Mathlib/Geometry/Manifold/Elaborators.lean +++ b/Mathlib/Geometry/Manifold/Elaborators.lean @@ -269,7 +269,7 @@ elab:max "MDiffAt[" s:term:arg "]" f:term:arg : term => do let srcI ← find_model src if Lean.Expr.hasLooseBVars tgt then throwError m!"Term {ef} is a dependent function, of type {etype}\n\ - Note: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one" + Hint: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one" let tgtI ← find_model tgt (src, srcI) -- TODO: check that `estype` and src are compatible/the same! return ← mkAppM ``MDifferentiableWithinAt #[srcI, tgtI, ef, es] @@ -286,7 +286,7 @@ elab:max "MDiffAt" t:term:arg : term => do let srcI ← find_model src if Lean.Expr.hasLooseBVars tgt then throwError m!"Term {e} is a dependent function, of type {etype}\n\ - Note: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one" + Hint: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one" let tgtI ← find_model tgt (src, srcI) return ← mkAppM ``MDifferentiableAt #[srcI, tgtI, e] | _ => throwError m!"Term {e} is not a function." @@ -304,7 +304,7 @@ elab:max "MDiffAt2" t:term:arg : term => do let srcI ← find_model src if Lean.Expr.occurs src tgt then throwError m!"Term {e} is a dependent function, of type {etype}\n\ - Note: you can use the 'T%' elaborator to convert a dependent function \ + Hint: you can use the 'T%' elaborator to convert a dependent function \ to a non-dependent one" let tgtI ← find_model tgt (src, srcI) return ← mkAppM ``MDifferentiableAt #[srcI, tgtI, e] @@ -323,7 +323,7 @@ elab:max "MDiff[" s:term:arg "]" t:term:arg : term => do let srcI ← find_model src if Lean.Expr.hasLooseBVars tgt then throwError m!"Term {et} is a dependent function, of type {etype}\n\ - Note: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one" + Hint: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one" let tgtI ← find_model tgt (src, srcI) -- TODO: check that `estype` and src are compatible/the same! return ← mkAppM ``MDifferentiableOn #[srcI, tgtI, et, es] @@ -339,7 +339,7 @@ elab:max "MDiff" t:term:arg : term => do let srcI ← find_model src if Lean.Expr.hasLooseBVars tgt then throwError m!"Term {e} is a dependent function, of type {etype}\n\ - Note: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one" + Hint: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one" let tgtI ← find_model tgt (src, srcI) return ← mkAppM ``MDifferentiable #[srcI, tgtI, e] | _ => throwError m!"Term {e} is not a function." @@ -360,7 +360,7 @@ elab:max "CMDiffAt[" s:term:arg "]" nt:term:arg f:term:arg : term => do let srcI ← find_model src if Lean.Expr.hasLooseBVars tgt then throwError m!"Term {ef} is a dependent function, of type {eftype}\n\ - Note: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one" + Hint: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one" let tgtI ← find_model tgt (src, srcI) -- TODO: check `estype` and src are compatible return ← mkAppM ``ContMDiffWithinAt #[srcI, tgtI, ne, ef, es] @@ -380,7 +380,7 @@ elab:max "CMDiffAt" nt:term:arg t:term:arg : term => do let srcI ← find_model src if Lean.Expr.hasLooseBVars tgt then throwError m!"Term {e} is a dependent function, of type {etype}\n\ - Note: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one" + Hint: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one" let tgtI ← find_model tgt (src, srcI) return ← mkAppM ``ContMDiffAt #[srcI, tgtI, ne, e] | _ => throwError m!"Term {e} is not a function." @@ -400,7 +400,7 @@ elab:max "CMDiff[" s:term:arg "]" nt:term:arg f:term:arg : term => do let srcI ← find_model src if Lean.Expr.hasLooseBVars tgt then throwError m!"Term {ef} is a dependent function, of type {eftype}\n\ - Note: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one" + Hint: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one" let tgtI ← find_model tgt (src, srcI) -- TODO: check `estype` and src are compatible return ← mkAppM ``ContMDiffOn #[srcI, tgtI, ne, ef, es] @@ -419,7 +419,7 @@ elab:max "CMDiff" nt:term:arg f:term:arg : term => do let srcI ← find_model src if Lean.Expr.hasLooseBVars tgt then throwError m!"Term {e} is a dependent function, of type {etype}\n\ - Note: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one" + Hint: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one" let tgtI ← find_model tgt (src, srcI) return ← mkAppM ``ContMDiff #[srcI, tgtI, ne, e] | _ => throwError m!"Term {e} is not a function." @@ -436,7 +436,7 @@ elab:max "mfderiv[" s:term:arg "]" t:term:arg : term => do let srcI ← find_model src if Lean.Expr.hasLooseBVars tgt then throwError m!"Term {e} is a dependent function, of type {etype}\n\ - Note: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one" + Hint: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one" let tgtI ← find_model tgt (src, srcI) -- TODO: check `estype` and src are compatible return ← mkAppM ``mfderivWithin #[srcI, tgtI, e, es] @@ -452,7 +452,7 @@ elab:max "mfderiv%" t:term:arg : term => do let srcI ← find_model src if Lean.Expr.hasLooseBVars tgt then throwError m!"Term {e} is a dependent function, of type {etype}\n\ - Note: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one" + Hint: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one" let tgtI ← find_model tgt (src, srcI) return ← mkAppM `mfderiv #[srcI, tgtI, e] | _ => throwError m!"Term {e} is not a function." diff --git a/MathlibTest/DifferentialGeometry/Elaborators.lean b/MathlibTest/DifferentialGeometry/Elaborators.lean index 766e004abe7e5c..31511733c5010d 100644 --- a/MathlibTest/DifferentialGeometry/Elaborators.lean +++ b/MathlibTest/DifferentialGeometry/Elaborators.lean @@ -323,63 +323,63 @@ section /-- error: Term X is a dependent function, of type (m : M) → TangentSpace I m -Note: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one +Hint: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one -/ #guard_msgs in #check MDiff X /-- error: Term σ is a dependent function, of type (x : M) → V x -Note: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one +Hint: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one -/ #guard_msgs in #check MDiff σ /-- error: Term σ' is a dependent function, of type (x : E) → Trivial E E' x -Note: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one +Hint: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one -/ #guard_msgs in #check MDiff σ' /-- error: Term σ' is a dependent function, of type (x : E) → Trivial E E' x -Note: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one +Hint: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one -/ #guard_msgs in #check MDiff[s] σ' /-- error: Term X is a dependent function, of type (m : M) → TangentSpace I m -Note: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one +Hint: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one -/ #guard_msgs in #check MDiffAt (X) /-- error: Term σ is a dependent function, of type (x : M) → V x -Note: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one +Hint: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one -/ #guard_msgs in #check MDiffAt ((σ)) /-- error: Term σ' is a dependent function, of type (x : E) → Trivial E E' x -Note: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one +Hint: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one -/ #guard_msgs in #check MDiff[s] σ' /-- error: Term σ' is a dependent function, of type (x : E) → Trivial E E' x -Note: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one +Hint: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one -/ #guard_msgs in #check MDiffAt σ' /-- error: Term σ' is a dependent function, of type (x : E) → Trivial E E' x -Note: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one +Hint: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one -/ #guard_msgs in #check MDiffAt[s] σ' @@ -592,63 +592,63 @@ variable (X : (m : M) → TangentSpace I m) [IsManifold I 1 M] /-- error: Term X is a dependent function, of type (m : M) → TangentSpace I m -Note: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one +Hint: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one -/ #guard_msgs in #check CMDiff 0 X /-- error: Term σ is a dependent function, of type (x : M) → V x -Note: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one +Hint: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one -/ #guard_msgs in #check CMDiff 0 σ /-- error: Term σ' is a dependent function, of type (x : E) → Trivial E E' x -Note: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one +Hint: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one -/ #guard_msgs in #check CMDiff 0 σ' /-- error: Term σ' is a dependent function, of type (x : E) → Trivial E E' x -Note: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one +Hint: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one -/ #guard_msgs in #check CMDiff[s] 0 σ' /-- error: Term X is a dependent function, of type (m : M) → TangentSpace I m -Note: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one +Hint: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one -/ #guard_msgs in #check CMDiffAt 0 (X) /-- error: Term σ is a dependent function, of type (x : M) → V x -Note: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one +Hint: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one -/ #guard_msgs in #check CMDiffAt 0 ((σ)) /-- error: Term σ' is a dependent function, of type (x : E) → Trivial E E' x -Note: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one +Hint: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one -/ #guard_msgs in #check CMDiff[s] 0 σ' /-- error: Term σ' is a dependent function, of type (x : E) → Trivial E E' x -Note: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one +Hint: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one -/ #guard_msgs in #check CMDiffAt 0 σ' /-- error: Term σ' is a dependent function, of type (x : E) → Trivial E E' x -Note: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one +Hint: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one -/ #guard_msgs in #check CMDiffAt[s] 0 σ' @@ -878,14 +878,14 @@ section /-- error: Term X is a dependent function, of type (m : M) → TangentSpace I m -Note: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one +Hint: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one -/ #guard_msgs in #check mfderiv% X x /-- error: Term σ is a dependent function, of type (x : M) → V x -Note: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one +Hint: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one -/ #guard_msgs in #check mfderiv% σ x @@ -894,14 +894,14 @@ variable {t : Set E} {p : E} /-- error: Term σ' is a dependent function, of type (x : E) → Trivial E E' x -Note: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one +Hint: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one -/ #guard_msgs in #check mfderiv[t] σ' p /-- error: Term σ' is a dependent function, of type (x : E) → Trivial E E' x -Note: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one +Hint: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one -/ #guard_msgs in #check mfderiv[t] σ' From 74432d5523ccaa1e5a8c0e0db54a5c493e45075a Mon Sep 17 00:00:00 2001 From: grunweg Date: Tue, 30 Sep 2025 18:07:59 +0200 Subject: [PATCH 034/106] Apply suggestions from code review Co-authored-by: Sebastien Gouezel --- Mathlib/Geometry/Manifold/Elaborators.lean | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Mathlib/Geometry/Manifold/Elaborators.lean b/Mathlib/Geometry/Manifold/Elaborators.lean index 67ed49c672c8be..2698a797410b53 100644 --- a/Mathlib/Geometry/Manifold/Elaborators.lean +++ b/Mathlib/Geometry/Manifold/Elaborators.lean @@ -30,11 +30,11 @@ The search for models with corners uses the local context and is (almost) only s hopefully fast enough to always run. This has no dedicated support for product manifolds (or product vector spaces) yet; -adding this is left for future changes. (It would make need to make a choice between e.g. the +adding this is left for future changes. (It would need to make a choice between e.g. the trivial model with corners on a product `E × F` and the product of the trivial models on `E` and `F`). -Secondly, this space adds an elaborator to ease working with sections in a fibre bundle, +Secondly, this file adds an elaborator to ease working with sections in a fibre bundle, converting a section `s : Π x : M, Π V x` to a non-dependent function into the total space of the bundle. ```lean @@ -67,9 +67,9 @@ the following. - extend the elaborators to support `PartialHomeomorph`s and `PartialEquiv`s - fix pretty-printing: currently, the `commandStart` linter expects some different formatting -- better error messages: forgetting e.g. the `T%` elaborator yields cryptic errors +- better error messages (as needed) - further testing and fixing of edge cases -- added tests for all of the above +- add tests for all of the above - add delaborators for these elaborators -/ @@ -424,7 +424,7 @@ elab:max "CMDiff" nt:term:arg f:term:arg : term => do return ← mkAppM ``ContMDiff #[srcI, tgtI, ne, e] | _ => throwError m!"Term {e} is not a function." -/-- `mfderiv[u] f x` elaborates to `mfderivWithin I J f x`, +/-- `mfderiv[u] f x` elaborates to `mfderivWithin I J f u x`, trying to determine `I` and `J` from the local context. -/ elab:max "mfderiv[" s:term:arg "]" t:term:arg : term => do let es ← Term.elabTerm s none From c68ce87c84381b693bf999a6a4e20149b2d78eca Mon Sep 17 00:00:00 2001 From: grunweg Date: Tue, 30 Sep 2025 18:08:20 +0200 Subject: [PATCH 035/106] Update MathlibTest/DifferentialGeometry/Elaborators.lean Co-authored-by: Sebastien Gouezel --- MathlibTest/DifferentialGeometry/Elaborators.lean | 1 - 1 file changed, 1 deletion(-) diff --git a/MathlibTest/DifferentialGeometry/Elaborators.lean b/MathlibTest/DifferentialGeometry/Elaborators.lean index 31511733c5010d..b09ce91696d630 100644 --- a/MathlibTest/DifferentialGeometry/Elaborators.lean +++ b/MathlibTest/DifferentialGeometry/Elaborators.lean @@ -1,5 +1,4 @@ import Mathlib.Geometry.Manifold.Elaborators - import Mathlib.Geometry.Manifold.VectorBundle.SmoothSection import Mathlib.Geometry.Manifold.VectorBundle.Tangent import Mathlib.Geometry.Manifold.MFDeriv.FDeriv From 4512cf672250eff3750f814eaa3ae22245691f70 Mon Sep 17 00:00:00 2001 From: Michael Rothgang Date: Tue, 30 Sep 2025 18:09:07 +0200 Subject: [PATCH 036/106] Stronger warning --- Mathlib/Geometry/Manifold/Elaborators.lean | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mathlib/Geometry/Manifold/Elaborators.lean b/Mathlib/Geometry/Manifold/Elaborators.lean index 2698a797410b53..8769e8d233c323 100644 --- a/Mathlib/Geometry/Manifold/Elaborators.lean +++ b/Mathlib/Geometry/Manifold/Elaborators.lean @@ -32,7 +32,7 @@ hopefully fast enough to always run. This has no dedicated support for product manifolds (or product vector spaces) yet; adding this is left for future changes. (It would need to make a choice between e.g. the trivial model with corners on a product `E × F` and the product of the trivial models on `E` and -`F`). +`F`). In these settings, the elaborators should be avoided (for now). Secondly, this file adds an elaborator to ease working with sections in a fibre bundle, converting a section `s : Π x : M, Π V x` to a non-dependent function into the total space of the From 9b41163eb5cd75dc89a7668ec07cbc494df3f9c9 Mon Sep 17 00:00:00 2001 From: Michael Rothgang Date: Tue, 30 Sep 2025 18:16:31 +0200 Subject: [PATCH 037/106] Use Hint more --- Mathlib/Geometry/Manifold/Elaborators.lean | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mathlib/Geometry/Manifold/Elaborators.lean b/Mathlib/Geometry/Manifold/Elaborators.lean index 8769e8d233c323..db9e818321ee1b 100644 --- a/Mathlib/Geometry/Manifold/Elaborators.lean +++ b/Mathlib/Geometry/Manifold/Elaborators.lean @@ -138,7 +138,7 @@ elab:max "T% " t:term:arg : term => do -- xxx: is this check fine or overzealous? if Lean.Expr.hasLooseBVars tgt then throwError m!"Term {tgt} has loose bound variables¬ - Note: applying the 'T%' elaborator twice makes no sense." + Hint: applying the 'T%' elaborator twice makes no sense." let trivBundle := mkAppN (.const `Bundle.Trivial [us, ut]) #[src, tgt] return ← withLocalDecl x BinderInfo.default src fun x ↦ do let body := mkAppN (.const ``Bundle.TotalSpace.mk' [us, ut, ut]) From 05c4860a742159eb7792bd89dcead26ce3531cb0 Mon Sep 17 00:00:00 2001 From: Michael Rothgang Date: Tue, 30 Sep 2025 18:25:49 +0200 Subject: [PATCH 038/106] Document and polish find_models better --- Mathlib/Geometry/Manifold/Elaborators.lean | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/Mathlib/Geometry/Manifold/Elaborators.lean b/Mathlib/Geometry/Manifold/Elaborators.lean index db9e818321ee1b..9dbb02b44294bb 100644 --- a/Mathlib/Geometry/Manifold/Elaborators.lean +++ b/Mathlib/Geometry/Manifold/Elaborators.lean @@ -147,8 +147,8 @@ elab:max "T% " t:term:arg : term => do | _ => pure () return e -/-- Try to find a `ModelWithCorners` instance on an expression `e`, using the local context -to infer the expected type. This supports the following cases: +/-- Try to find a `ModelWithCorners` instance on a type (represented by an expression `e`), +using the local context to infer the expected type. This supports the following cases: - the model with corners on the total space of a vector bundle - a model with corners on a manifold - the trivial model `𝓘(𝕜, E)` on a normed space @@ -156,9 +156,14 @@ to infer the expected type. This supports the following cases: and if successful, return `𝓘(𝕜)`. Further cases can be added as necessary. -This implementation is not maximally robust yet, but already useful. -TODO: document what `baseInfo` is and how to use it! +Return an expression describing the found model with corners. + +`baseInfo` is only used for the first case, a model with corners on the total space of the vector +bundle. In this case, it contains a pair of expressions `(e, i)` describing the type of the base +and the model with corners on the base: these are required to construct the right model with corners. + +This implementation is not maximally robust yet. -/ -- FIXME: better failure when trying to find a `NormedField` instance def find_model (e : Expr) (baseInfo : Option (Expr × Expr) := none) : TermElabM Expr := do @@ -197,7 +202,6 @@ def find_model (e : Expr) (baseInfo : Option (Expr × Expr) := none) : TermElabM let I ← Term.elabTerm iTerm none trace[MDiffElab] m!"Found model: {I}" return I - else throwError "Having a TotalSpace as source is not yet supported" let mut H : Expr := default @@ -245,7 +249,6 @@ def find_model (e : Expr) (baseInfo : Option (Expr × Expr) := none) : TermElabM trace[MDiffElab] m!"Found model: {decl}" return decl | _ => pure () - -- throwError m!"Couldn’t find models with corners with H = {H}" else trace[MDiffElab] m!"Hoping {e} is a normed field" let eT : Term ← PrettyPrinter.delab e @@ -253,7 +256,6 @@ def find_model (e : Expr) (baseInfo : Option (Expr × Expr) := none) : TermElabM let I ← Term.elabTerm iTerm none trace[MDiffElab] m!"Found model: {I}" return I - throwError "Couldn’t find models with corners" /-- `MDiffAt[s] f x` elaborates to `MDifferentiableWithinAt I J f s x`, From 48d79988ff0b6192f9e25e8415704b814c0291d9 Mon Sep 17 00:00:00 2001 From: Michael Rothgang Date: Tue, 30 Sep 2025 18:37:18 +0200 Subject: [PATCH 039/106] refactor: reduce duplication in the various small elaborators --- Mathlib/Geometry/Manifold/Elaborators.lean | 147 +++++++-------------- 1 file changed, 51 insertions(+), 96 deletions(-) diff --git a/Mathlib/Geometry/Manifold/Elaborators.lean b/Mathlib/Geometry/Manifold/Elaborators.lean index 9dbb02b44294bb..c5cb4eb20255ab 100644 --- a/Mathlib/Geometry/Manifold/Elaborators.lean +++ b/Mathlib/Geometry/Manifold/Elaborators.lean @@ -161,7 +161,8 @@ Return an expression describing the found model with corners. `baseInfo` is only used for the first case, a model with corners on the total space of the vector bundle. In this case, it contains a pair of expressions `(e, i)` describing the type of the base -and the model with corners on the base: these are required to construct the right model with corners. +and the model with corners on the base: these are required to construct the right model with +corners. This implementation is not maximally robust yet. -/ @@ -258,6 +259,25 @@ def find_model (e : Expr) (baseInfo : Option (Expr × Expr) := none) : TermElabM return I throwError "Couldn’t find models with corners" +/-- If `etype` is a non-dependent function between spaces `src` and `tgt`, try to find a model with +corners on both `src` and `tgt`. If successful, return both models. + +`ef` is the term having type `etype`: this is used only for better diagnostics. +If `estype` is `some`, we verify that `src` and `estype` are def-eq. (TODO: implement this!) -/ +-- TODO: pass in an additional type, to be checked equivalent to `src`, and validate this! +def _find_models (etype eterm : Expr) (_estype : Option Expr) : + TermElabM (Option (Expr × Expr)) := do + match etype with + | .forallE _ src tgt _ => + let srcI ← find_model src + if Lean.Expr.hasLooseBVars tgt then + throwError m!"Term {eterm} is a dependent function, of type {etype}\n\ + Hint: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one" + let tgtI ← find_model tgt (src, srcI) + -- TODO: check that `estype` and src are defeq! + return some (srcI, tgtI) + | _ => return none + /-- `MDiffAt[s] f x` elaborates to `MDifferentiableWithinAt I J f s x`, trying to determine `I` and `J` from the local context. The argument x can be omitted. -/ @@ -266,16 +286,9 @@ elab:max "MDiffAt[" s:term:arg "]" f:term:arg : term => do let ef ← Term.elabTerm f none let etype ← inferType ef >>= instantiateMVars let _estype ← inferType ef >>= instantiateMVars - match etype with - | .forallE _ src tgt _ => - let srcI ← find_model src - if Lean.Expr.hasLooseBVars tgt then - throwError m!"Term {ef} is a dependent function, of type {etype}\n\ - Hint: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one" - let tgtI ← find_model tgt (src, srcI) - -- TODO: check that `estype` and src are compatible/the same! - return ← mkAppM ``MDifferentiableWithinAt #[srcI, tgtI, ef, es] - | _ => throwError m!"Term {ef} is not a function." + match ← _find_models etype ef _estype with + | some (srcI, tgtI) => return ← mkAppM ``MDifferentiableWithinAt #[srcI, tgtI, ef, es] + | none => throwError m!"Term {ef} is not a function." /-- `MDiffAt f x` elaborates to `MDifferentiableAt I J f x`, trying to determine `I` and `J` from the local context. @@ -283,15 +296,9 @@ The argument `x` can be omitted. -/ elab:max "MDiffAt" t:term:arg : term => do let e ← Term.elabTerm t none let etype ← inferType e >>= instantiateMVars - match etype with - | .forallE _ src tgt _ => - let srcI ← find_model src - if Lean.Expr.hasLooseBVars tgt then - throwError m!"Term {e} is a dependent function, of type {etype}\n\ - Hint: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one" - let tgtI ← find_model tgt (src, srcI) - return ← mkAppM ``MDifferentiableAt #[srcI, tgtI, e] - | _ => throwError m!"Term {e} is not a function." + match ← _find_models etype e none with + | some (srcI, tgtI) => return ← mkAppM ``MDifferentiableAt #[srcI, tgtI, e] + | none => throwError m!"Term {e} is not a function." -- This implement is more robust (in theory), but currently fails tests. -- TODO: investigate why, fix this and replace `MDiffAt` by this one! @@ -320,31 +327,18 @@ elab:max "MDiff[" s:term:arg "]" t:term:arg : term => do let et ← Term.elabTerm t none let _estype ← inferType es >>= instantiateMVars let etype ← inferType et >>= instantiateMVars - match etype with - | .forallE _ src tgt _ => - let srcI ← find_model src - if Lean.Expr.hasLooseBVars tgt then - throwError m!"Term {et} is a dependent function, of type {etype}\n\ - Hint: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one" - let tgtI ← find_model tgt (src, srcI) - -- TODO: check that `estype` and src are compatible/the same! - return ← mkAppM ``MDifferentiableOn #[srcI, tgtI, et, es] - | _ => throwError m!"Term {et} is not a function." + match ← _find_models etype et _estype with + | some (srcI, tgtI) => return ← mkAppM ``MDifferentiableOn #[srcI, tgtI, et, es] + | none => throwError m!"Term {et} is not a function." /-- `MDiff f` elaborates to `MDifferentiable I J f`, trying to determine `I` and `J` from the local context. -/ elab:max "MDiff" t:term:arg : term => do let e ← Term.elabTerm t none let etype ← inferType e >>= instantiateMVars - match etype with - | .forallE _ src tgt _ => - let srcI ← find_model src - if Lean.Expr.hasLooseBVars tgt then - throwError m!"Term {e} is a dependent function, of type {etype}\n\ - Hint: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one" - let tgtI ← find_model tgt (src, srcI) - return ← mkAppM ``MDifferentiable #[srcI, tgtI, e] - | _ => throwError m!"Term {e} is not a function." + match ← _find_models etype e none with + | some (srcI, tgtI) => return ← mkAppM ``MDifferentiable #[srcI, tgtI, e] + | none => throwError m!"Term {e} is not a function." /-- `CMDiffAt[s] n f x` elaborates to `ContMDiffWithinAt I J n f s x`, trying to determine `I` and `J` from the local context. @@ -357,16 +351,9 @@ elab:max "CMDiffAt[" s:term:arg "]" nt:term:arg f:term:arg : term => do let ne ← Term.elabTermEnsuringType nt wtn let _estype ← inferType es >>= instantiateMVars let eftype ← inferType ef >>= instantiateMVars - match eftype with - | .forallE _ src tgt _ => - let srcI ← find_model src - if Lean.Expr.hasLooseBVars tgt then - throwError m!"Term {ef} is a dependent function, of type {eftype}\n\ - Hint: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one" - let tgtI ← find_model tgt (src, srcI) - -- TODO: check `estype` and src are compatible - return ← mkAppM ``ContMDiffWithinAt #[srcI, tgtI, ne, ef, es] - | _ => throwError m!"Term {ef} is not a function." + match ← _find_models eftype ef _estype with + | some (srcI, tgtI) => return ← mkAppM ``ContMDiffWithinAt #[srcI, tgtI, ne, ef, es] + | none => throwError m!"Term {ef} is not a function." /-- `CMDiffAt n f x` elaborates to `ContMDiffAt I J n f x` trying to determine `I` and `J` from the local context. @@ -377,15 +364,9 @@ elab:max "CMDiffAt" nt:term:arg t:term:arg : term => do let wtn ← Term.elabTerm (← ``(WithTop ℕ∞)) none let ne ← Term.elabTermEnsuringType nt wtn let etype ← inferType e >>= instantiateMVars - match etype with - | .forallE _ src tgt _ => - let srcI ← find_model src - if Lean.Expr.hasLooseBVars tgt then - throwError m!"Term {e} is a dependent function, of type {etype}\n\ - Hint: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one" - let tgtI ← find_model tgt (src, srcI) - return ← mkAppM ``ContMDiffAt #[srcI, tgtI, ne, e] - | _ => throwError m!"Term {e} is not a function." + match ← _find_models etype e none with + | some (srcI, tgtI) => return ← mkAppM ``ContMDiffAt #[srcI, tgtI, ne, e] + | none => throwError m!"Term {e} is not a function." /-- `CMDiff[s] n f` elaborates to `ContMDiffOn I J n f s`, trying to determine `I` and `J` from the local context. @@ -397,16 +378,9 @@ elab:max "CMDiff[" s:term:arg "]" nt:term:arg f:term:arg : term => do let ne ← Term.elabTermEnsuringType nt wtn let _estype ← inferType es >>= instantiateMVars let eftype ← inferType ef >>= instantiateMVars - match eftype with - | .forallE _ src tgt _ => - let srcI ← find_model src - if Lean.Expr.hasLooseBVars tgt then - throwError m!"Term {ef} is a dependent function, of type {eftype}\n\ - Hint: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one" - let tgtI ← find_model tgt (src, srcI) - -- TODO: check `estype` and src are compatible - return ← mkAppM ``ContMDiffOn #[srcI, tgtI, ne, ef, es] - | _ => throwError m!"Term {ef} is not a function." + match ← _find_models eftype ef _estype with + | some (srcI, tgtI) => return ← mkAppM ``ContMDiffOn #[srcI, tgtI, ne, ef, es] + | none => throwError m!"Term {ef} is not a function." /-- `CMDiff n f` elaborates to `ContMDiff I J n f`, trying to determine `I` and `J` from the local context. @@ -416,15 +390,9 @@ elab:max "CMDiff" nt:term:arg f:term:arg : term => do let wtn ← Term.elabTerm (← `(WithTop ℕ∞)) none let ne ← Term.elabTermEnsuringType nt wtn let etype ← inferType e >>= instantiateMVars - match etype with - | .forallE _ src tgt _ => - let srcI ← find_model src - if Lean.Expr.hasLooseBVars tgt then - throwError m!"Term {e} is a dependent function, of type {etype}\n\ - Hint: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one" - let tgtI ← find_model tgt (src, srcI) - return ← mkAppM ``ContMDiff #[srcI, tgtI, ne, e] - | _ => throwError m!"Term {e} is not a function." + match ← _find_models etype e none with + | some (srcI, tgtI) => return ← mkAppM ``ContMDiff #[srcI, tgtI, ne, e] + | none => throwError m!"Term {e} is not a function." /-- `mfderiv[u] f x` elaborates to `mfderivWithin I J f u x`, trying to determine `I` and `J` from the local context. -/ @@ -433,30 +401,17 @@ elab:max "mfderiv[" s:term:arg "]" t:term:arg : term => do let e ← Term.elabTerm t none let etype ← inferType e >>= instantiateMVars let _estype ← inferType es >>= instantiateMVars - match etype with - | .forallE _ src tgt _ => - let srcI ← find_model src - if Lean.Expr.hasLooseBVars tgt then - throwError m!"Term {e} is a dependent function, of type {etype}\n\ - Hint: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one" - let tgtI ← find_model tgt (src, srcI) - -- TODO: check `estype` and src are compatible - return ← mkAppM ``mfderivWithin #[srcI, tgtI, e, es] - | _ => throwError m!"Term {e} is not a function." + match ← _find_models etype e _estype with + | some (srcI, tgtI) => return ← mkAppM ``mfderivWithin #[srcI, tgtI, e, es] + | none => throwError m!"Term {e} is not a function." /-- `mfderiv% f x` elaborates to `mfderiv I J f x`, trying to determine `I` and `J` from the local context. -/ elab:max "mfderiv%" t:term:arg : term => do let e ← Term.elabTerm t none let etype ← inferType e >>= instantiateMVars - match etype with - | .forallE _ src tgt _ => - let srcI ← find_model src - if Lean.Expr.hasLooseBVars tgt then - throwError m!"Term {e} is a dependent function, of type {etype}\n\ - Hint: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one" - let tgtI ← find_model tgt (src, srcI) - return ← mkAppM `mfderiv #[srcI, tgtI, e] - | _ => throwError m!"Term {e} is not a function." + match ← _find_models etype e none with + | some (srcI, tgtI) => return ← mkAppM ``mfderiv #[srcI, tgtI, e] + | none => throwError m!"Term {e} is not a function." end Manifold From a7286210947c6b0c05d4ba361437a86d8ce6fb3f Mon Sep 17 00:00:00 2001 From: Michael Rothgang Date: Tue, 30 Sep 2025 19:33:04 +0200 Subject: [PATCH 040/106] chore: validate the types of s and src match This caught one typo, so this was useful! --- Mathlib/Geometry/Manifold/Elaborators.lean | 30 ++++++++++--------- .../DifferentialGeometry/Elaborators.lean | 4 +-- 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/Mathlib/Geometry/Manifold/Elaborators.lean b/Mathlib/Geometry/Manifold/Elaborators.lean index c5cb4eb20255ab..4db543b3fef11d 100644 --- a/Mathlib/Geometry/Manifold/Elaborators.lean +++ b/Mathlib/Geometry/Manifold/Elaborators.lean @@ -263,9 +263,8 @@ def find_model (e : Expr) (baseInfo : Option (Expr × Expr) := none) : TermElabM corners on both `src` and `tgt`. If successful, return both models. `ef` is the term having type `etype`: this is used only for better diagnostics. -If `estype` is `some`, we verify that `src` and `estype` are def-eq. (TODO: implement this!) -/ --- TODO: pass in an additional type, to be checked equivalent to `src`, and validate this! -def _find_models (etype eterm : Expr) (_estype : Option Expr) : +If `estype` is `some`, we verify that `src` and `estype` are def-eq. -/ +def _find_models (etype eterm : Expr) (estype : Option Expr) : TermElabM (Option (Expr × Expr)) := do match etype with | .forallE _ src tgt _ => @@ -273,8 +272,11 @@ def _find_models (etype eterm : Expr) (_estype : Option Expr) : if Lean.Expr.hasLooseBVars tgt then throwError m!"Term {eterm} is a dependent function, of type {etype}\n\ Hint: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one" + if let some es := estype then + if !(← isDefEq es (← mkAppM ``Set #[src])) then + throwError m!"The domain {src} of {eterm} is not definitionally equal to the carrier + of the type {es} of the set 's' passed in" let tgtI ← find_model tgt (src, srcI) - -- TODO: check that `estype` and src are defeq! return some (srcI, tgtI) | _ => return none @@ -285,8 +287,8 @@ elab:max "MDiffAt[" s:term:arg "]" f:term:arg : term => do let es ← Term.elabTerm s none let ef ← Term.elabTerm f none let etype ← inferType ef >>= instantiateMVars - let _estype ← inferType ef >>= instantiateMVars - match ← _find_models etype ef _estype with + let estype ← inferType es >>= instantiateMVars + match ← _find_models etype ef estype with | some (srcI, tgtI) => return ← mkAppM ``MDifferentiableWithinAt #[srcI, tgtI, ef, es] | none => throwError m!"Term {ef} is not a function." @@ -325,9 +327,9 @@ trying to determine `I` and `J` from the local context. -/ elab:max "MDiff[" s:term:arg "]" t:term:arg : term => do let es ← Term.elabTerm s none let et ← Term.elabTerm t none - let _estype ← inferType es >>= instantiateMVars + let estype ← inferType es >>= instantiateMVars let etype ← inferType et >>= instantiateMVars - match ← _find_models etype et _estype with + match ← _find_models etype et estype with | some (srcI, tgtI) => return ← mkAppM ``MDifferentiableOn #[srcI, tgtI, et, es] | none => throwError m!"Term {et} is not a function." @@ -349,9 +351,9 @@ elab:max "CMDiffAt[" s:term:arg "]" nt:term:arg f:term:arg : term => do let ef ← Term.elabTerm f none let wtn ← Term.elabTerm (← `(WithTop ℕ∞)) none let ne ← Term.elabTermEnsuringType nt wtn - let _estype ← inferType es >>= instantiateMVars + let estype ← inferType es >>= instantiateMVars let eftype ← inferType ef >>= instantiateMVars - match ← _find_models eftype ef _estype with + match ← _find_models eftype ef estype with | some (srcI, tgtI) => return ← mkAppM ``ContMDiffWithinAt #[srcI, tgtI, ne, ef, es] | none => throwError m!"Term {ef} is not a function." @@ -376,9 +378,9 @@ elab:max "CMDiff[" s:term:arg "]" nt:term:arg f:term:arg : term => do let ef ← Term.elabTerm f none let wtn ← Term.elabTerm (← ``(WithTop ℕ∞)) none let ne ← Term.elabTermEnsuringType nt wtn - let _estype ← inferType es >>= instantiateMVars + let estype ← inferType es >>= instantiateMVars let eftype ← inferType ef >>= instantiateMVars - match ← _find_models eftype ef _estype with + match ← _find_models eftype ef estype with | some (srcI, tgtI) => return ← mkAppM ``ContMDiffOn #[srcI, tgtI, ne, ef, es] | none => throwError m!"Term {ef} is not a function." @@ -400,8 +402,8 @@ elab:max "mfderiv[" s:term:arg "]" t:term:arg : term => do let es ← Term.elabTerm s none let e ← Term.elabTerm t none let etype ← inferType e >>= instantiateMVars - let _estype ← inferType es >>= instantiateMVars - match ← _find_models etype e _estype with + let estype ← inferType es >>= instantiateMVars + match ← _find_models etype e estype with | some (srcI, tgtI) => return ← mkAppM ``mfderivWithin #[srcI, tgtI, e, es] | none => throwError m!"Term {e} is not a function." diff --git a/MathlibTest/DifferentialGeometry/Elaborators.lean b/MathlibTest/DifferentialGeometry/Elaborators.lean index b09ce91696d630..f02e2a07860cdb 100644 --- a/MathlibTest/DifferentialGeometry/Elaborators.lean +++ b/MathlibTest/DifferentialGeometry/Elaborators.lean @@ -119,8 +119,8 @@ error: Application type mismatch: The argument has type M of sort `Type u_4` but is expected to have type - Type ?u.63950 -of sort `Type (?u.63950 + 1)` in the application + Type ?u.63952 +of sort `Type (?u.63952 + 1)` in the application @modelWithCornersSelf a✝ -/ #guard_msgs in From 04c188ade4fea6fb39c97e12f1d40bcf2b253fa7 Mon Sep 17 00:00:00 2001 From: Michael Rothgang Date: Tue, 30 Sep 2025 20:34:34 +0200 Subject: [PATCH 041/106] fix(Elaborators): pretty-print the new elaborated notation correctly --- Mathlib/Geometry/Manifold/Elaborators.lean | 23 +++++++++++----------- 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/Mathlib/Geometry/Manifold/Elaborators.lean b/Mathlib/Geometry/Manifold/Elaborators.lean index 4db543b3fef11d..613198c869d563 100644 --- a/Mathlib/Geometry/Manifold/Elaborators.lean +++ b/Mathlib/Geometry/Manifold/Elaborators.lean @@ -66,7 +66,6 @@ the following. the model in `E × F` and the product of the models on `E` and `F`. - extend the elaborators to support `PartialHomeomorph`s and `PartialEquiv`s -- fix pretty-printing: currently, the `commandStart` linter expects some different formatting - better error messages (as needed) - further testing and fixing of edge cases - add tests for all of the above @@ -283,7 +282,7 @@ def _find_models (etype eterm : Expr) (estype : Option Expr) : /-- `MDiffAt[s] f x` elaborates to `MDifferentiableWithinAt I J f s x`, trying to determine `I` and `J` from the local context. The argument x can be omitted. -/ -elab:max "MDiffAt[" s:term:arg "]" f:term:arg : term => do +elab:max "MDiffAt[" s:term:arg "]" ppSpace f:term:arg : term => do let es ← Term.elabTerm s none let ef ← Term.elabTerm f none let etype ← inferType ef >>= instantiateMVars @@ -295,7 +294,7 @@ elab:max "MDiffAt[" s:term:arg "]" f:term:arg : term => do /-- `MDiffAt f x` elaborates to `MDifferentiableAt I J f x`, trying to determine `I` and `J` from the local context. The argument `x` can be omitted. -/ -elab:max "MDiffAt" t:term:arg : term => do +elab:max "MDiffAt" ppSpace t:term:arg : term => do let e ← Term.elabTerm t none let etype ← inferType e >>= instantiateMVars match ← _find_models etype e none with @@ -307,7 +306,7 @@ elab:max "MDiffAt" t:term:arg : term => do /-- `MDiffAt2 f x` elaborates to `MDifferentiableAt I J f x`, trying to determine `I` and `J` from the local context. The argument `x` can be omitted. -/ -elab:max "MDiffAt2" t:term:arg : term => do +elab:max "MDiffAt2" ppSpace t:term:arg : term => do let e ← Term.elabTerm t none let etype ← inferType e >>= instantiateMVars forallBoundedTelescope etype (some 1) fun src tgt ↦ do @@ -324,7 +323,7 @@ elab:max "MDiffAt2" t:term:arg : term => do /-- `MDiff[s] f` elaborates to `MDifferentiableOn I J f s`, trying to determine `I` and `J` from the local context. -/ -elab:max "MDiff[" s:term:arg "]" t:term:arg : term => do +elab:max "MDiff[" s:term:arg "]" ppSpace t:term:arg : term => do let es ← Term.elabTerm s none let et ← Term.elabTerm t none let estype ← inferType es >>= instantiateMVars @@ -335,7 +334,7 @@ elab:max "MDiff[" s:term:arg "]" t:term:arg : term => do /-- `MDiff f` elaborates to `MDifferentiable I J f`, trying to determine `I` and `J` from the local context. -/ -elab:max "MDiff" t:term:arg : term => do +elab:max "MDiff" ppSpace t:term:arg : term => do let e ← Term.elabTerm t none let etype ← inferType e >>= instantiateMVars match ← _find_models etype e none with @@ -346,7 +345,7 @@ elab:max "MDiff" t:term:arg : term => do trying to determine `I` and `J` from the local context. `n` is coerced to `WithTop ℕ∞` if necessary (so passing a `ℕ`, `∞` or `ω` are all supported). The argument `x` can be omitted. -/ -elab:max "CMDiffAt[" s:term:arg "]" nt:term:arg f:term:arg : term => do +elab:max "CMDiffAt[" s:term:arg "]" ppSpace nt:term:arg ppSpace f:term:arg : term => do let es ← Term.elabTerm s none let ef ← Term.elabTerm f none let wtn ← Term.elabTerm (← `(WithTop ℕ∞)) none @@ -361,7 +360,7 @@ elab:max "CMDiffAt[" s:term:arg "]" nt:term:arg f:term:arg : term => do trying to determine `I` and `J` from the local context. `n` is coerced to `WithTop ℕ∞` if necessary (so passing a `ℕ`, `∞` or `ω` are all supported). The argument `x` can be omitted. -/ -elab:max "CMDiffAt" nt:term:arg t:term:arg : term => do +elab:max "CMDiffAt" ppSpace nt:term:arg ppSpace t:term:arg : term => do let e ← Term.elabTerm t none let wtn ← Term.elabTerm (← ``(WithTop ℕ∞)) none let ne ← Term.elabTermEnsuringType nt wtn @@ -373,7 +372,7 @@ elab:max "CMDiffAt" nt:term:arg t:term:arg : term => do /-- `CMDiff[s] n f` elaborates to `ContMDiffOn I J n f s`, trying to determine `I` and `J` from the local context. `n` is coerced to `WithTop ℕ∞` if necessary (so passing a `ℕ`, `∞` or `ω` are all supported). -/ -elab:max "CMDiff[" s:term:arg "]" nt:term:arg f:term:arg : term => do +elab:max "CMDiff[" s:term:arg "]" ppSpace nt:term:arg ppSpace f:term:arg : term => do let es ← Term.elabTerm s none let ef ← Term.elabTerm f none let wtn ← Term.elabTerm (← ``(WithTop ℕ∞)) none @@ -387,7 +386,7 @@ elab:max "CMDiff[" s:term:arg "]" nt:term:arg f:term:arg : term => do /-- `CMDiff n f` elaborates to `ContMDiff I J n f`, trying to determine `I` and `J` from the local context. `n` is coerced to `WithTop ℕ∞` if necessary (so passing a `ℕ`, `∞` or `ω` are all supported). -/ -elab:max "CMDiff" nt:term:arg f:term:arg : term => do +elab:max "CMDiff" ppSpace nt:term:arg ppSpace f:term:arg : term => do let e ← Term.elabTerm f none let wtn ← Term.elabTerm (← `(WithTop ℕ∞)) none let ne ← Term.elabTermEnsuringType nt wtn @@ -398,7 +397,7 @@ elab:max "CMDiff" nt:term:arg f:term:arg : term => do /-- `mfderiv[u] f x` elaborates to `mfderivWithin I J f u x`, trying to determine `I` and `J` from the local context. -/ -elab:max "mfderiv[" s:term:arg "]" t:term:arg : term => do +elab:max "mfderiv[" s:term:arg "]" ppSpace t:term:arg : term => do let es ← Term.elabTerm s none let e ← Term.elabTerm t none let etype ← inferType e >>= instantiateMVars @@ -409,7 +408,7 @@ elab:max "mfderiv[" s:term:arg "]" t:term:arg : term => do /-- `mfderiv% f x` elaborates to `mfderiv I J f x`, trying to determine `I` and `J` from the local context. -/ -elab:max "mfderiv%" t:term:arg : term => do +elab:max "mfderiv%" ppSpace t:term:arg : term => do let e ← Term.elabTerm t none let etype ← inferType e >>= instantiateMVars match ← _find_models etype e none with From 52e0ee02133affaaf250e9535e5a91978029429a Mon Sep 17 00:00:00 2001 From: Michael Rothgang Date: Fri, 3 Oct 2025 11:22:30 +0200 Subject: [PATCH 042/106] chore: move mkApp12 to a Lean --- Mathlib/Geometry/Manifold/Elaborators.lean | 4 ---- Mathlib/Lean/Expr/Basic.lean | 4 ++++ 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Mathlib/Geometry/Manifold/Elaborators.lean b/Mathlib/Geometry/Manifold/Elaborators.lean index 613198c869d563..69cb7322d50b16 100644 --- a/Mathlib/Geometry/Manifold/Elaborators.lean +++ b/Mathlib/Geometry/Manifold/Elaborators.lean @@ -85,10 +85,6 @@ def _root_.Lean.Expr.getUniverse (e : Expr) : TermElabM (Level) := do else throwError m!"Could not find universe of {e}." -/-- Call `mkApp` recursively with 12 arguments -/ -@[match_pattern] def mkApp12 (f a b c d e g e₁ e₂ e₃ e₄ e₅ e₆ : Expr) := - mkApp6 (mkApp6 f a b c d e g) e₁ e₂ e₃ e₄ e₅ e₆ - namespace Manifold /-- Elaborator for sections in a fibre bundle: converts a section as a dependent function diff --git a/Mathlib/Lean/Expr/Basic.lean b/Mathlib/Lean/Expr/Basic.lean index 298f55a98b1f53..9bc1707e0aac0d 100644 --- a/Mathlib/Lean/Expr/Basic.lean +++ b/Mathlib/Lean/Expr/Basic.lean @@ -166,6 +166,10 @@ namespace Expr /-! ### Declarations about `Expr` -/ +/-- Call `mkApp` recursively with 12 arguments -/ +@[match_pattern] def mkApp12 (f a b c d e g e₁ e₂ e₃ e₄ e₅ e₆ : Expr) := + mkApp6 (mkApp6 f a b c d e g) e₁ e₂ e₃ e₄ e₅ e₆ + def bvarIdx? : Expr → Option Nat | bvar idx => some idx | _ => none From 74cfff3f867da83b158eb34628a08ef72bb38354 Mon Sep 17 00:00:00 2001 From: Michael Rothgang Date: Fri, 3 Oct 2025 11:26:25 +0200 Subject: [PATCH 043/106] chore: move getUniverse to Lean/Meta/ElabTerm --- Mathlib/Geometry/Manifold/Elaborators.lean | 7 ------- Mathlib/Lean/Elab/Term.lean | 11 ++++++++++- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/Mathlib/Geometry/Manifold/Elaborators.lean b/Mathlib/Geometry/Manifold/Elaborators.lean index 69cb7322d50b16..6c1fecde19f1bc 100644 --- a/Mathlib/Geometry/Manifold/Elaborators.lean +++ b/Mathlib/Geometry/Manifold/Elaborators.lean @@ -78,13 +78,6 @@ open scoped Bundle Manifold ContDiff open Lean Meta Elab Tactic open Mathlib.Tactic -/-- Try to infer the universe of an expression `e` -/ -def _root_.Lean.Expr.getUniverse (e : Expr) : TermElabM (Level) := do - if let .sort (.succ u) ← inferType e >>= instantiateMVars then - return u - else - throwError m!"Could not find universe of {e}." - namespace Manifold /-- Elaborator for sections in a fibre bundle: converts a section as a dependent function diff --git a/Mathlib/Lean/Elab/Term.lean b/Mathlib/Lean/Elab/Term.lean index d536cad0358b2b..c0686023880829 100644 --- a/Mathlib/Lean/Elab/Term.lean +++ b/Mathlib/Lean/Elab/Term.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Kyle Miller -/ import Mathlib.Init -import Lean.Elab.SyntheticMVars +import Lean.Elab.Term /-! # Additions to `Lean.Elab.Term` @@ -23,4 +23,13 @@ def elabPattern (patt : Term) (expectedType? : Option Expr) : TermElabM Expr := synthesizeSyntheticMVars (postpone := .no) (ignoreStuckTC := true) instantiateMVars t +open Meta + +/-- Try to infer the universe of an expression `e` -/ +def _root_.Lean.Expr.getUniverse (e : Expr) : TermElabM (Level) := do + if let .sort (.succ u) ← inferType e >>= instantiateMVars then + return u + else + throwError m!"Could not find universe of {e}." + end Lean.Elab.Term From 3abe5ed16c5eff02947f01a4db81a283c74c90d4 Mon Sep 17 00:00:00 2001 From: Michael Rothgang Date: Fri, 3 Oct 2025 12:38:14 +0200 Subject: [PATCH 044/106] Fix --- Mathlib/Lean/Expr/Basic.lean | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mathlib/Lean/Expr/Basic.lean b/Mathlib/Lean/Expr/Basic.lean index 9bc1707e0aac0d..aefef7774fdef5 100644 --- a/Mathlib/Lean/Expr/Basic.lean +++ b/Mathlib/Lean/Expr/Basic.lean @@ -167,7 +167,7 @@ namespace Expr /-! ### Declarations about `Expr` -/ /-- Call `mkApp` recursively with 12 arguments -/ -@[match_pattern] def mkApp12 (f a b c d e g e₁ e₂ e₃ e₄ e₅ e₆ : Expr) := +@[match_pattern] def _root_.mkApp12 (f a b c d e g e₁ e₂ e₃ e₄ e₅ e₆ : Expr) := mkApp6 (mkApp6 f a b c d e g) e₁ e₂ e₃ e₄ e₅ e₆ def bvarIdx? : Expr → Option Nat From b3bf6090fffd577afb9a4f39c02d5b32d64f9f0b Mon Sep 17 00:00:00 2001 From: Michael Rothgang Date: Fri, 3 Oct 2025 14:39:36 +0200 Subject: [PATCH 045/106] Fix test; tweak error message XXX do I like the new defeq check, or are other checks better? --- Mathlib/Geometry/Manifold/Elaborators.lean | 4 ++-- .../DifferentialGeometry/Elaborators.lean | 18 ++++++++---------- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/Mathlib/Geometry/Manifold/Elaborators.lean b/Mathlib/Geometry/Manifold/Elaborators.lean index 6c1fecde19f1bc..b59c27846e3705 100644 --- a/Mathlib/Geometry/Manifold/Elaborators.lean +++ b/Mathlib/Geometry/Manifold/Elaborators.lean @@ -262,8 +262,8 @@ def _find_models (etype eterm : Expr) (estype : Option Expr) : Hint: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one" if let some es := estype then if !(← isDefEq es (← mkAppM ``Set #[src])) then - throwError m!"The domain {src} of {eterm} is not definitionally equal to the carrier - of the type {es} of the set 's' passed in" + throwError m!"The domain {src} of {eterm} is not definitionally equal to the carrier \ + of the type '{es}' of the set 's' passed in" let tgtI ← find_model tgt (src, srcI) return some (srcI, tgtI) | _ => return none diff --git a/MathlibTest/DifferentialGeometry/Elaborators.lean b/MathlibTest/DifferentialGeometry/Elaborators.lean index f02e2a07860cdb..37fce684ce61a6 100644 --- a/MathlibTest/DifferentialGeometry/Elaborators.lean +++ b/MathlibTest/DifferentialGeometry/Elaborators.lean @@ -844,8 +844,8 @@ info: mfderiv 𝓘(𝕜, E) 𝓘(𝕜, EM') f sorry : TangentSpace 𝓘(𝕜, E) #guard_msgs in #check mfderiv% f m' --- Error messages: argument s has mismatched type. -/-- +-- TODO: is the old error message better? +/- error: Application type mismatch: The argument s' has type @@ -855,18 +855,16 @@ of sort `Type u_4` but is expected to have type of sort `Type u_2` in the application mfderivWithin 𝓘(𝕜, E) 𝓘(𝕜, EM') f s' -/ + +-- Error messages: argument s has mismatched type. +/-- +error: The domain E of f is not definitionally equal to the carrier of the type 'Set M' of the set 's' passed in +-/ #guard_msgs in #check mfderiv[s'] f /-- -error: Application type mismatch: The argument - s' -has type - Set.{u_4} M -of sort `Type u_4` but is expected to have type - Set.{u_2} E -of sort `Type u_2` in the application - mfderivWithin 𝓘(𝕜, E) 𝓘(𝕜, EM') f s' +error: The domain E of f is not definitionally equal to the carrier of the type 'Set M' of the set 's' passed in -/ #guard_msgs in #check mfderiv[s'] f m From c08a5c06ab9b931b6a1af1d26cad77a22f803b8a Mon Sep 17 00:00:00 2001 From: thorimur <68410468+thorimur@users.noreply.github.com> Date: Sat, 4 Oct 2025 15:30:18 -0400 Subject: [PATCH 046/106] (Git wrangling) Revert "Fix test; tweak error message" This reverts commit b3bf6090fffd577afb9a4f39c02d5b32d64f9f0b. --- Mathlib/Geometry/Manifold/Elaborators.lean | 4 ++-- .../DifferentialGeometry/Elaborators.lean | 18 ++++++++++-------- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/Mathlib/Geometry/Manifold/Elaborators.lean b/Mathlib/Geometry/Manifold/Elaborators.lean index b59c27846e3705..6c1fecde19f1bc 100644 --- a/Mathlib/Geometry/Manifold/Elaborators.lean +++ b/Mathlib/Geometry/Manifold/Elaborators.lean @@ -262,8 +262,8 @@ def _find_models (etype eterm : Expr) (estype : Option Expr) : Hint: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one" if let some es := estype then if !(← isDefEq es (← mkAppM ``Set #[src])) then - throwError m!"The domain {src} of {eterm} is not definitionally equal to the carrier \ - of the type '{es}' of the set 's' passed in" + throwError m!"The domain {src} of {eterm} is not definitionally equal to the carrier + of the type {es} of the set 's' passed in" let tgtI ← find_model tgt (src, srcI) return some (srcI, tgtI) | _ => return none diff --git a/MathlibTest/DifferentialGeometry/Elaborators.lean b/MathlibTest/DifferentialGeometry/Elaborators.lean index 37fce684ce61a6..f02e2a07860cdb 100644 --- a/MathlibTest/DifferentialGeometry/Elaborators.lean +++ b/MathlibTest/DifferentialGeometry/Elaborators.lean @@ -844,8 +844,8 @@ info: mfderiv 𝓘(𝕜, E) 𝓘(𝕜, EM') f sorry : TangentSpace 𝓘(𝕜, E) #guard_msgs in #check mfderiv% f m' --- TODO: is the old error message better? -/- +-- Error messages: argument s has mismatched type. +/-- error: Application type mismatch: The argument s' has type @@ -855,16 +855,18 @@ of sort `Type u_4` but is expected to have type of sort `Type u_2` in the application mfderivWithin 𝓘(𝕜, E) 𝓘(𝕜, EM') f s' -/ - --- Error messages: argument s has mismatched type. -/-- -error: The domain E of f is not definitionally equal to the carrier of the type 'Set M' of the set 's' passed in --/ #guard_msgs in #check mfderiv[s'] f /-- -error: The domain E of f is not definitionally equal to the carrier of the type 'Set M' of the set 's' passed in +error: Application type mismatch: The argument + s' +has type + Set.{u_4} M +of sort `Type u_4` but is expected to have type + Set.{u_2} E +of sort `Type u_2` in the application + mfderivWithin 𝓘(𝕜, E) 𝓘(𝕜, EM') f s' -/ #guard_msgs in #check mfderiv[s'] f m From 5c4484982c7214062fd32744e2400f6353483884 Mon Sep 17 00:00:00 2001 From: thorimur <68410468+thorimur@users.noreply.github.com> Date: Sat, 4 Oct 2025 15:31:05 -0400 Subject: [PATCH 047/106] (Git wrangling) Revert "Fix" This reverts commit 3abe5ed16c5eff02947f01a4db81a283c74c90d4. --- Mathlib/Lean/Expr/Basic.lean | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mathlib/Lean/Expr/Basic.lean b/Mathlib/Lean/Expr/Basic.lean index ac3b8279a27cd6..405425f8592d1d 100644 --- a/Mathlib/Lean/Expr/Basic.lean +++ b/Mathlib/Lean/Expr/Basic.lean @@ -165,7 +165,7 @@ namespace Expr /-! ### Declarations about `Expr` -/ /-- Call `mkApp` recursively with 12 arguments -/ -@[match_pattern] def _root_.mkApp12 (f a b c d e g e₁ e₂ e₃ e₄ e₅ e₆ : Expr) := +@[match_pattern] def mkApp12 (f a b c d e g e₁ e₂ e₃ e₄ e₅ e₆ : Expr) := mkApp6 (mkApp6 f a b c d e g) e₁ e₂ e₃ e₄ e₅ e₆ def bvarIdx? : Expr → Option Nat From 66c7cdbefccfb7231e1a12d78cc3ab5555000fad Mon Sep 17 00:00:00 2001 From: thorimur <68410468+thorimur@users.noreply.github.com> Date: Sat, 4 Oct 2025 15:31:27 -0400 Subject: [PATCH 048/106] (Git wrangling) Revert "chore: move getUniverse to Lean/Meta/ElabTerm" This reverts commit 74cfff3f867da83b158eb34628a08ef72bb38354. --- Mathlib/Geometry/Manifold/Elaborators.lean | 7 +++++++ Mathlib/Lean/Elab/Term.lean | 11 +---------- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/Mathlib/Geometry/Manifold/Elaborators.lean b/Mathlib/Geometry/Manifold/Elaborators.lean index 6c1fecde19f1bc..69cb7322d50b16 100644 --- a/Mathlib/Geometry/Manifold/Elaborators.lean +++ b/Mathlib/Geometry/Manifold/Elaborators.lean @@ -78,6 +78,13 @@ open scoped Bundle Manifold ContDiff open Lean Meta Elab Tactic open Mathlib.Tactic +/-- Try to infer the universe of an expression `e` -/ +def _root_.Lean.Expr.getUniverse (e : Expr) : TermElabM (Level) := do + if let .sort (.succ u) ← inferType e >>= instantiateMVars then + return u + else + throwError m!"Could not find universe of {e}." + namespace Manifold /-- Elaborator for sections in a fibre bundle: converts a section as a dependent function diff --git a/Mathlib/Lean/Elab/Term.lean b/Mathlib/Lean/Elab/Term.lean index c0686023880829..d536cad0358b2b 100644 --- a/Mathlib/Lean/Elab/Term.lean +++ b/Mathlib/Lean/Elab/Term.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Kyle Miller -/ import Mathlib.Init -import Lean.Elab.Term +import Lean.Elab.SyntheticMVars /-! # Additions to `Lean.Elab.Term` @@ -23,13 +23,4 @@ def elabPattern (patt : Term) (expectedType? : Option Expr) : TermElabM Expr := synthesizeSyntheticMVars (postpone := .no) (ignoreStuckTC := true) instantiateMVars t -open Meta - -/-- Try to infer the universe of an expression `e` -/ -def _root_.Lean.Expr.getUniverse (e : Expr) : TermElabM (Level) := do - if let .sort (.succ u) ← inferType e >>= instantiateMVars then - return u - else - throwError m!"Could not find universe of {e}." - end Lean.Elab.Term From aa083bda71662aa1c2688170bb807432011ac317 Mon Sep 17 00:00:00 2001 From: thorimur <68410468+thorimur@users.noreply.github.com> Date: Sat, 4 Oct 2025 15:31:46 -0400 Subject: [PATCH 049/106] (Git wrangling) Revert "chore: move mkApp12 to a Lean" This reverts commit 52e0ee02133affaaf250e9535e5a91978029429a. --- Mathlib/Geometry/Manifold/Elaborators.lean | 4 ++++ Mathlib/Lean/Expr/Basic.lean | 4 ---- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Mathlib/Geometry/Manifold/Elaborators.lean b/Mathlib/Geometry/Manifold/Elaborators.lean index 69cb7322d50b16..613198c869d563 100644 --- a/Mathlib/Geometry/Manifold/Elaborators.lean +++ b/Mathlib/Geometry/Manifold/Elaborators.lean @@ -85,6 +85,10 @@ def _root_.Lean.Expr.getUniverse (e : Expr) : TermElabM (Level) := do else throwError m!"Could not find universe of {e}." +/-- Call `mkApp` recursively with 12 arguments -/ +@[match_pattern] def mkApp12 (f a b c d e g e₁ e₂ e₃ e₄ e₅ e₆ : Expr) := + mkApp6 (mkApp6 f a b c d e g) e₁ e₂ e₃ e₄ e₅ e₆ + namespace Manifold /-- Elaborator for sections in a fibre bundle: converts a section as a dependent function diff --git a/Mathlib/Lean/Expr/Basic.lean b/Mathlib/Lean/Expr/Basic.lean index 405425f8592d1d..9e4566f242162b 100644 --- a/Mathlib/Lean/Expr/Basic.lean +++ b/Mathlib/Lean/Expr/Basic.lean @@ -164,10 +164,6 @@ namespace Expr /-! ### Declarations about `Expr` -/ -/-- Call `mkApp` recursively with 12 arguments -/ -@[match_pattern] def mkApp12 (f a b c d e g e₁ e₂ e₃ e₄ e₅ e₆ : Expr) := - mkApp6 (mkApp6 f a b c d e g) e₁ e₂ e₃ e₄ e₅ e₆ - def bvarIdx? : Expr → Option Nat | bvar idx => some idx | _ => none From e0bea749ddde6641ef7ced0fc0df2ce1e58e16ca Mon Sep 17 00:00:00 2001 From: thorimur <68410468+thorimur@users.noreply.github.com> Date: Wed, 1 Oct 2025 19:20:58 -0400 Subject: [PATCH 050/106] style: remove `>>=` --- Mathlib/Geometry/Manifold/Elaborators.lean | 44 +++++++++++----------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/Mathlib/Geometry/Manifold/Elaborators.lean b/Mathlib/Geometry/Manifold/Elaborators.lean index 613198c869d563..7921e7a3602d5a 100644 --- a/Mathlib/Geometry/Manifold/Elaborators.lean +++ b/Mathlib/Geometry/Manifold/Elaborators.lean @@ -80,7 +80,7 @@ open Mathlib.Tactic /-- Try to infer the universe of an expression `e` -/ def _root_.Lean.Expr.getUniverse (e : Expr) : TermElabM (Level) := do - if let .sort (.succ u) ← inferType e >>= instantiateMVars then + if let .sort (.succ u) ← instantiateMVars <|← inferType e then return u else throwError m!"Could not find universe of {e}." @@ -104,7 +104,7 @@ hypothesis for the above cases. Therefore, it is (hopefully) fast enough to alwa -- TODO: document how this elaborator works, any gotchas, etc. elab:max "T% " t:term:arg : term => do let e ← Term.elabTerm t none - let etype ← inferType e >>= instantiateMVars + let etype ← instantiateMVars <|← inferType e match etype with | .forallE x base (mkApp3 (.const ``Bundle.Trivial _) E E' _) _ => trace[TotalSpaceMk] "Section of a trivial bundle" @@ -120,7 +120,7 @@ elab:max "T% " t:term:arg : term => do | .forallE x base (.app V _) _ => trace[TotalSpaceMk] "Section of a bundle as a dependent function" for decl in ← getLocalHyps do - let decltype ← inferType decl >>= instantiateMVars + let decltype ← instantiateMVars <|← inferType decl match decltype with | mkApp7 (.const `FiberBundle _) _ F _ _ E _ _ => if ← withReducible (isDefEq E V) then @@ -183,7 +183,7 @@ def find_model (e : Expr) (baseInfo : Option (Expr × Expr) := none) : TermElabM let mut normedSpaceInst : Expr := default let mut Kok : Bool := false for decl in ← getLocalHyps do - let decltype ← inferType decl >>= instantiateMVars + let decltype ← instantiateMVars <|← inferType decl match decltype with | mkApp4 (.const ``NormedSpace _) K' E _ _ => if E == F then @@ -210,7 +210,7 @@ def find_model (e : Expr) (baseInfo : Option (Expr × Expr) := none) : TermElabM let mut normedSpaceInst : Expr := default let mut Kok : Bool := false for decl in ← getLocalHyps do - let decltype ← inferType decl >>= instantiateMVars + let decltype ← instantiateMVars <|← inferType decl match decltype with | mkApp4 (.const ``ChartedSpace _) H' _ M _ => if M == e then @@ -242,7 +242,7 @@ def find_model (e : Expr) (baseInfo : Option (Expr × Expr) := none) : TermElabM -- #[K, normedFieldK, e, normedGroupE, normedSpaceInst] else if Hok then for decl in ← getLocalHyps do - let decltype ← inferType decl >>= instantiateMVars + let decltype ← instantiateMVars <|← inferType decl match decltype with | mkApp7 (.const ``ModelWithCorners _) _ _ _ _ _ H' _ => if H' == H then @@ -285,8 +285,8 @@ The argument x can be omitted. -/ elab:max "MDiffAt[" s:term:arg "]" ppSpace f:term:arg : term => do let es ← Term.elabTerm s none let ef ← Term.elabTerm f none - let etype ← inferType ef >>= instantiateMVars - let estype ← inferType es >>= instantiateMVars + let etype ← instantiateMVars <|← inferType ef + let estype ← instantiateMVars <|← inferType es match ← _find_models etype ef estype with | some (srcI, tgtI) => return ← mkAppM ``MDifferentiableWithinAt #[srcI, tgtI, ef, es] | none => throwError m!"Term {ef} is not a function." @@ -296,7 +296,7 @@ trying to determine `I` and `J` from the local context. The argument `x` can be omitted. -/ elab:max "MDiffAt" ppSpace t:term:arg : term => do let e ← Term.elabTerm t none - let etype ← inferType e >>= instantiateMVars + let etype ← instantiateMVars <|← inferType e match ← _find_models etype e none with | some (srcI, tgtI) => return ← mkAppM ``MDifferentiableAt #[srcI, tgtI, e] | none => throwError m!"Term {e} is not a function." @@ -308,7 +308,7 @@ trying to determine `I` and `J` from the local context. The argument `x` can be omitted. -/ elab:max "MDiffAt2" ppSpace t:term:arg : term => do let e ← Term.elabTerm t none - let etype ← inferType e >>= instantiateMVars + let etype ← instantiateMVars <|← inferType e forallBoundedTelescope etype (some 1) fun src tgt ↦ do if let some src := src[0]? then let srcI ← find_model src @@ -326,8 +326,8 @@ trying to determine `I` and `J` from the local context. -/ elab:max "MDiff[" s:term:arg "]" ppSpace t:term:arg : term => do let es ← Term.elabTerm s none let et ← Term.elabTerm t none - let estype ← inferType es >>= instantiateMVars - let etype ← inferType et >>= instantiateMVars + let estype ← instantiateMVars <|← inferType es + let etype ← instantiateMVars <|← inferType et match ← _find_models etype et estype with | some (srcI, tgtI) => return ← mkAppM ``MDifferentiableOn #[srcI, tgtI, et, es] | none => throwError m!"Term {et} is not a function." @@ -336,7 +336,7 @@ elab:max "MDiff[" s:term:arg "]" ppSpace t:term:arg : term => do trying to determine `I` and `J` from the local context. -/ elab:max "MDiff" ppSpace t:term:arg : term => do let e ← Term.elabTerm t none - let etype ← inferType e >>= instantiateMVars + let etype ← instantiateMVars <|← inferType e match ← _find_models etype e none with | some (srcI, tgtI) => return ← mkAppM ``MDifferentiable #[srcI, tgtI, e] | none => throwError m!"Term {e} is not a function." @@ -350,8 +350,8 @@ elab:max "CMDiffAt[" s:term:arg "]" ppSpace nt:term:arg ppSpace f:term:arg : ter let ef ← Term.elabTerm f none let wtn ← Term.elabTerm (← `(WithTop ℕ∞)) none let ne ← Term.elabTermEnsuringType nt wtn - let estype ← inferType es >>= instantiateMVars - let eftype ← inferType ef >>= instantiateMVars + let estype ← instantiateMVars <|← inferType es + let eftype ← instantiateMVars <|← inferType ef match ← _find_models eftype ef estype with | some (srcI, tgtI) => return ← mkAppM ``ContMDiffWithinAt #[srcI, tgtI, ne, ef, es] | none => throwError m!"Term {ef} is not a function." @@ -364,7 +364,7 @@ elab:max "CMDiffAt" ppSpace nt:term:arg ppSpace t:term:arg : term => do let e ← Term.elabTerm t none let wtn ← Term.elabTerm (← ``(WithTop ℕ∞)) none let ne ← Term.elabTermEnsuringType nt wtn - let etype ← inferType e >>= instantiateMVars + let etype ← instantiateMVars <|← inferType e match ← _find_models etype e none with | some (srcI, tgtI) => return ← mkAppM ``ContMDiffAt #[srcI, tgtI, ne, e] | none => throwError m!"Term {e} is not a function." @@ -377,8 +377,8 @@ elab:max "CMDiff[" s:term:arg "]" ppSpace nt:term:arg ppSpace f:term:arg : term let ef ← Term.elabTerm f none let wtn ← Term.elabTerm (← ``(WithTop ℕ∞)) none let ne ← Term.elabTermEnsuringType nt wtn - let estype ← inferType es >>= instantiateMVars - let eftype ← inferType ef >>= instantiateMVars + let estype ← instantiateMVars <|← inferType es + let eftype ← instantiateMVars <|← inferType ef match ← _find_models eftype ef estype with | some (srcI, tgtI) => return ← mkAppM ``ContMDiffOn #[srcI, tgtI, ne, ef, es] | none => throwError m!"Term {ef} is not a function." @@ -390,7 +390,7 @@ elab:max "CMDiff" ppSpace nt:term:arg ppSpace f:term:arg : term => do let e ← Term.elabTerm f none let wtn ← Term.elabTerm (← `(WithTop ℕ∞)) none let ne ← Term.elabTermEnsuringType nt wtn - let etype ← inferType e >>= instantiateMVars + let etype ← instantiateMVars <|← inferType e match ← _find_models etype e none with | some (srcI, tgtI) => return ← mkAppM ``ContMDiff #[srcI, tgtI, ne, e] | none => throwError m!"Term {e} is not a function." @@ -400,8 +400,8 @@ trying to determine `I` and `J` from the local context. -/ elab:max "mfderiv[" s:term:arg "]" ppSpace t:term:arg : term => do let es ← Term.elabTerm s none let e ← Term.elabTerm t none - let etype ← inferType e >>= instantiateMVars - let estype ← inferType es >>= instantiateMVars + let etype ← instantiateMVars <|← inferType e + let estype ← instantiateMVars <|← inferType es match ← _find_models etype e estype with | some (srcI, tgtI) => return ← mkAppM ``mfderivWithin #[srcI, tgtI, e, es] | none => throwError m!"Term {e} is not a function." @@ -410,7 +410,7 @@ elab:max "mfderiv[" s:term:arg "]" ppSpace t:term:arg : term => do trying to determine `I` and `J` from the local context. -/ elab:max "mfderiv%" ppSpace t:term:arg : term => do let e ← Term.elabTerm t none - let etype ← inferType e >>= instantiateMVars + let etype ← instantiateMVars <|← inferType e match ← _find_models etype e none with | some (srcI, tgtI) => return ← mkAppM ``mfderiv #[srcI, tgtI, e] | none => throwError m!"Term {e} is not a function." From 45b061929359445723ebd49eec39f6631b49c18e Mon Sep 17 00:00:00 2001 From: thorimur <68410468+thorimur@users.noreply.github.com> Date: Sat, 4 Oct 2025 19:33:30 -0400 Subject: [PATCH 051/106] chore: reduce `etype` to get `.forallE` --- Mathlib/Geometry/Manifold/Elaborators.lean | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mathlib/Geometry/Manifold/Elaborators.lean b/Mathlib/Geometry/Manifold/Elaborators.lean index 7921e7a3602d5a..7997b1c9248267 100644 --- a/Mathlib/Geometry/Manifold/Elaborators.lean +++ b/Mathlib/Geometry/Manifold/Elaborators.lean @@ -104,7 +104,7 @@ hypothesis for the above cases. Therefore, it is (hopefully) fast enough to alwa -- TODO: document how this elaborator works, any gotchas, etc. elab:max "T% " t:term:arg : term => do let e ← Term.elabTerm t none - let etype ← instantiateMVars <|← inferType e + let etype ← whnf <|← instantiateMVars <|← inferType e match etype with | .forallE x base (mkApp3 (.const ``Bundle.Trivial _) E E' _) _ => trace[TotalSpaceMk] "Section of a trivial bundle" From 76765aa2b131944dbccfedec568b1bfa42d0f82a Mon Sep 17 00:00:00 2001 From: thorimur <68410468+thorimur@users.noreply.github.com> Date: Wed, 1 Oct 2025 19:22:41 -0400 Subject: [PATCH 052/106] chore: `whnfR` after `instantiateMVars` --- Mathlib/Geometry/Manifold/Elaborators.lean | 42 +++++++++++----------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/Mathlib/Geometry/Manifold/Elaborators.lean b/Mathlib/Geometry/Manifold/Elaborators.lean index 7997b1c9248267..3e7ee91d123879 100644 --- a/Mathlib/Geometry/Manifold/Elaborators.lean +++ b/Mathlib/Geometry/Manifold/Elaborators.lean @@ -80,7 +80,7 @@ open Mathlib.Tactic /-- Try to infer the universe of an expression `e` -/ def _root_.Lean.Expr.getUniverse (e : Expr) : TermElabM (Level) := do - if let .sort (.succ u) ← instantiateMVars <|← inferType e then + if let .sort (.succ u) ← whnfR <|← instantiateMVars <|← inferType e then return u else throwError m!"Could not find universe of {e}." @@ -120,7 +120,7 @@ elab:max "T% " t:term:arg : term => do | .forallE x base (.app V _) _ => trace[TotalSpaceMk] "Section of a bundle as a dependent function" for decl in ← getLocalHyps do - let decltype ← instantiateMVars <|← inferType decl + let decltype ← whnfR <|← instantiateMVars <|← inferType decl match decltype with | mkApp7 (.const `FiberBundle _) _ F _ _ E _ _ => if ← withReducible (isDefEq E V) then @@ -183,7 +183,7 @@ def find_model (e : Expr) (baseInfo : Option (Expr × Expr) := none) : TermElabM let mut normedSpaceInst : Expr := default let mut Kok : Bool := false for decl in ← getLocalHyps do - let decltype ← instantiateMVars <|← inferType decl + let decltype ← whnfR <|← instantiateMVars <|← inferType decl match decltype with | mkApp4 (.const ``NormedSpace _) K' E _ _ => if E == F then @@ -210,7 +210,7 @@ def find_model (e : Expr) (baseInfo : Option (Expr × Expr) := none) : TermElabM let mut normedSpaceInst : Expr := default let mut Kok : Bool := false for decl in ← getLocalHyps do - let decltype ← instantiateMVars <|← inferType decl + let decltype ← whnfR <|← instantiateMVars <|← inferType decl match decltype with | mkApp4 (.const ``ChartedSpace _) H' _ M _ => if M == e then @@ -242,7 +242,7 @@ def find_model (e : Expr) (baseInfo : Option (Expr × Expr) := none) : TermElabM -- #[K, normedFieldK, e, normedGroupE, normedSpaceInst] else if Hok then for decl in ← getLocalHyps do - let decltype ← instantiateMVars <|← inferType decl + let decltype ← whnfR <|← instantiateMVars <|← inferType decl match decltype with | mkApp7 (.const ``ModelWithCorners _) _ _ _ _ _ H' _ => if H' == H then @@ -285,8 +285,8 @@ The argument x can be omitted. -/ elab:max "MDiffAt[" s:term:arg "]" ppSpace f:term:arg : term => do let es ← Term.elabTerm s none let ef ← Term.elabTerm f none - let etype ← instantiateMVars <|← inferType ef - let estype ← instantiateMVars <|← inferType es + let etype ← whnfR <|← instantiateMVars <|← inferType ef + let estype ← whnfR <|← instantiateMVars <|← inferType es match ← _find_models etype ef estype with | some (srcI, tgtI) => return ← mkAppM ``MDifferentiableWithinAt #[srcI, tgtI, ef, es] | none => throwError m!"Term {ef} is not a function." @@ -296,7 +296,7 @@ trying to determine `I` and `J` from the local context. The argument `x` can be omitted. -/ elab:max "MDiffAt" ppSpace t:term:arg : term => do let e ← Term.elabTerm t none - let etype ← instantiateMVars <|← inferType e + let etype ← whnfR <|← instantiateMVars <|← inferType e match ← _find_models etype e none with | some (srcI, tgtI) => return ← mkAppM ``MDifferentiableAt #[srcI, tgtI, e] | none => throwError m!"Term {e} is not a function." @@ -308,7 +308,7 @@ trying to determine `I` and `J` from the local context. The argument `x` can be omitted. -/ elab:max "MDiffAt2" ppSpace t:term:arg : term => do let e ← Term.elabTerm t none - let etype ← instantiateMVars <|← inferType e + let etype ← whnfR <|← instantiateMVars <|← inferType e forallBoundedTelescope etype (some 1) fun src tgt ↦ do if let some src := src[0]? then let srcI ← find_model src @@ -326,8 +326,8 @@ trying to determine `I` and `J` from the local context. -/ elab:max "MDiff[" s:term:arg "]" ppSpace t:term:arg : term => do let es ← Term.elabTerm s none let et ← Term.elabTerm t none - let estype ← instantiateMVars <|← inferType es - let etype ← instantiateMVars <|← inferType et + let estype ← whnfR <|← instantiateMVars <|← inferType es + let etype ← whnfR <|← instantiateMVars <|← inferType et match ← _find_models etype et estype with | some (srcI, tgtI) => return ← mkAppM ``MDifferentiableOn #[srcI, tgtI, et, es] | none => throwError m!"Term {et} is not a function." @@ -336,7 +336,7 @@ elab:max "MDiff[" s:term:arg "]" ppSpace t:term:arg : term => do trying to determine `I` and `J` from the local context. -/ elab:max "MDiff" ppSpace t:term:arg : term => do let e ← Term.elabTerm t none - let etype ← instantiateMVars <|← inferType e + let etype ← whnfR <|← instantiateMVars <|← inferType e match ← _find_models etype e none with | some (srcI, tgtI) => return ← mkAppM ``MDifferentiable #[srcI, tgtI, e] | none => throwError m!"Term {e} is not a function." @@ -350,8 +350,8 @@ elab:max "CMDiffAt[" s:term:arg "]" ppSpace nt:term:arg ppSpace f:term:arg : ter let ef ← Term.elabTerm f none let wtn ← Term.elabTerm (← `(WithTop ℕ∞)) none let ne ← Term.elabTermEnsuringType nt wtn - let estype ← instantiateMVars <|← inferType es - let eftype ← instantiateMVars <|← inferType ef + let estype ← whnfR <|← instantiateMVars <|← inferType es + let eftype ← whnfR <|← instantiateMVars <|← inferType ef match ← _find_models eftype ef estype with | some (srcI, tgtI) => return ← mkAppM ``ContMDiffWithinAt #[srcI, tgtI, ne, ef, es] | none => throwError m!"Term {ef} is not a function." @@ -364,7 +364,7 @@ elab:max "CMDiffAt" ppSpace nt:term:arg ppSpace t:term:arg : term => do let e ← Term.elabTerm t none let wtn ← Term.elabTerm (← ``(WithTop ℕ∞)) none let ne ← Term.elabTermEnsuringType nt wtn - let etype ← instantiateMVars <|← inferType e + let etype ← whnfR <|← instantiateMVars <|← inferType e match ← _find_models etype e none with | some (srcI, tgtI) => return ← mkAppM ``ContMDiffAt #[srcI, tgtI, ne, e] | none => throwError m!"Term {e} is not a function." @@ -377,8 +377,8 @@ elab:max "CMDiff[" s:term:arg "]" ppSpace nt:term:arg ppSpace f:term:arg : term let ef ← Term.elabTerm f none let wtn ← Term.elabTerm (← ``(WithTop ℕ∞)) none let ne ← Term.elabTermEnsuringType nt wtn - let estype ← instantiateMVars <|← inferType es - let eftype ← instantiateMVars <|← inferType ef + let estype ← whnfR <|← instantiateMVars <|← inferType es + let eftype ← whnfR <|← instantiateMVars <|← inferType ef match ← _find_models eftype ef estype with | some (srcI, tgtI) => return ← mkAppM ``ContMDiffOn #[srcI, tgtI, ne, ef, es] | none => throwError m!"Term {ef} is not a function." @@ -390,7 +390,7 @@ elab:max "CMDiff" ppSpace nt:term:arg ppSpace f:term:arg : term => do let e ← Term.elabTerm f none let wtn ← Term.elabTerm (← `(WithTop ℕ∞)) none let ne ← Term.elabTermEnsuringType nt wtn - let etype ← instantiateMVars <|← inferType e + let etype ← whnfR <|← instantiateMVars <|← inferType e match ← _find_models etype e none with | some (srcI, tgtI) => return ← mkAppM ``ContMDiff #[srcI, tgtI, ne, e] | none => throwError m!"Term {e} is not a function." @@ -400,8 +400,8 @@ trying to determine `I` and `J` from the local context. -/ elab:max "mfderiv[" s:term:arg "]" ppSpace t:term:arg : term => do let es ← Term.elabTerm s none let e ← Term.elabTerm t none - let etype ← instantiateMVars <|← inferType e - let estype ← instantiateMVars <|← inferType es + let etype ← whnfR <|← instantiateMVars <|← inferType e + let estype ← whnfR <|← instantiateMVars <|← inferType es match ← _find_models etype e estype with | some (srcI, tgtI) => return ← mkAppM ``mfderivWithin #[srcI, tgtI, e, es] | none => throwError m!"Term {e} is not a function." @@ -410,7 +410,7 @@ elab:max "mfderiv[" s:term:arg "]" ppSpace t:term:arg : term => do trying to determine `I` and `J` from the local context. -/ elab:max "mfderiv%" ppSpace t:term:arg : term => do let e ← Term.elabTerm t none - let etype ← instantiateMVars <|← inferType e + let etype ← whnfR <|← instantiateMVars <|← inferType e match ← _find_models etype e none with | some (srcI, tgtI) => return ← mkAppM ``mfderiv #[srcI, tgtI, e] | none => throwError m!"Term {e} is not a function." From 753bf7748c5e7182e8cc382a4bc863ef3fe70e06 Mon Sep 17 00:00:00 2001 From: thorimur <68410468+thorimur@users.noreply.github.com> Date: Wed, 1 Oct 2025 19:25:48 -0400 Subject: [PATCH 053/106] chore: remove `getUniverse` in favor of `mkAppOptM` --- Mathlib/Geometry/Manifold/Elaborators.lean | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/Mathlib/Geometry/Manifold/Elaborators.lean b/Mathlib/Geometry/Manifold/Elaborators.lean index 3e7ee91d123879..423ca24945a6cb 100644 --- a/Mathlib/Geometry/Manifold/Elaborators.lean +++ b/Mathlib/Geometry/Manifold/Elaborators.lean @@ -78,13 +78,6 @@ open scoped Bundle Manifold ContDiff open Lean Meta Elab Tactic open Mathlib.Tactic -/-- Try to infer the universe of an expression `e` -/ -def _root_.Lean.Expr.getUniverse (e : Expr) : TermElabM (Level) := do - if let .sort (.succ u) ← whnfR <|← instantiateMVars <|← inferType e then - return u - else - throwError m!"Could not find universe of {e}." - /-- Call `mkApp` recursively with 12 arguments -/ @[match_pattern] def mkApp12 (f a b c d e g e₁ e₂ e₃ e₄ e₅ e₆ : Expr) := mkApp6 (mkApp6 f a b c d e g) e₁ e₂ e₃ e₄ e₅ e₆ @@ -130,18 +123,15 @@ elab:max "T% " t:term:arg : term => do | _ => pure () | .forallE x src tgt _ => trace[TotalSpaceMk] "Section of a trivial bundle as a non-dependent function" - let us ← src.getUniverse - let ut ← tgt.getUniverse -- TODO: can `tgt` depend on `x` in a way that is not a function application? -- Check that `x` is not a bound variable in `tgt`! -- xxx: is this check fine or overzealous? if Lean.Expr.hasLooseBVars tgt then throwError m!"Term {tgt} has loose bound variables¬ Hint: applying the 'T%' elaborator twice makes no sense." - let trivBundle := mkAppN (.const `Bundle.Trivial [us, ut]) #[src, tgt] + let trivBundle ← mkAppOptM ``Bundle.Trivial #[src, tgt] return ← withLocalDecl x BinderInfo.default src fun x ↦ do - let body := mkAppN (.const ``Bundle.TotalSpace.mk' [us, ut, ut]) - #[src, trivBundle, tgt, x, .app e x] + let body ← mkAppOptM ``Bundle.TotalSpace.mk' #[src, trivBundle, tgt, x, e.app x] mkLambdaFVars #[x] body | _ => pure () return e From 54d24faec0e8855c51d396bfad741b4eacb1c4e2 Mon Sep 17 00:00:00 2001 From: thorimur <68410468+thorimur@users.noreply.github.com> Date: Wed, 1 Oct 2025 21:44:02 -0400 Subject: [PATCH 054/106] chore: `PrettyPrinter.delab` -> `Term.exprToSyntax` --- Mathlib/Geometry/Manifold/Elaborators.lean | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Mathlib/Geometry/Manifold/Elaborators.lean b/Mathlib/Geometry/Manifold/Elaborators.lean index 423ca24945a6cb..2ba55c69a52c0b 100644 --- a/Mathlib/Geometry/Manifold/Elaborators.lean +++ b/Mathlib/Geometry/Manifold/Elaborators.lean @@ -161,7 +161,7 @@ def find_model (e : Expr) (baseInfo : Option (Expr × Expr) := none) : TermElabM if let mkApp3 (.const ``Bundle.TotalSpace _) _ F V := e then if let mkApp12 (.const ``TangentSpace _) _k _ _E _ _ _H _ I M _ _ _x := V then trace[MDiffElab] m!"This is the total space of the tangent bundle of {M}" - let srcIT : Term ← PrettyPrinter.delab I + let srcIT : Term ← Term.exprToSyntax I let resTerm : Term ← ``(ModelWithCorners.prod $srcIT ModelWithCorners.tangent $srcIT) let res ← Term.elabTerm resTerm none trace[MDiffElab] m!"Found model: {res}" @@ -185,9 +185,9 @@ def find_model (e : Expr) (baseInfo : Option (Expr × Expr) := none) : TermElabM if Kok then break unless Kok do throwError m!"Couldn’t find a normed space structure on {F} in local context" - let kT : Term ← PrettyPrinter.delab K - let srcIT : Term ← PrettyPrinter.delab srcI - let FT : Term ← PrettyPrinter.delab F + let kT : Term ← Term.exprToSyntax K + let srcIT : Term ← Term.exprToSyntax srcI + let FT : Term ← Term.exprToSyntax F let iTerm : Term ← ``(ModelWithCorners.prod $srcIT 𝓘($kT, $FT)) let I ← Term.elabTerm iTerm none trace[MDiffElab] m!"Found model: {I}" @@ -216,8 +216,8 @@ def find_model (e : Expr) (baseInfo : Option (Expr × Expr) := none) : TermElabM | _ => pure () if Hok || Kok then break if Kok then - let eT : Term ← PrettyPrinter.delab e - let eK : Term ← PrettyPrinter.delab K + let eT : Term ← Term.exprToSyntax e + let eK : Term ← Term.exprToSyntax K let iTerm : Term ← ``(𝓘($eK, $eT)) let I ← Term.elabTerm iTerm none trace[MDiffElab] m!"Found model: {I}" @@ -241,7 +241,7 @@ def find_model (e : Expr) (baseInfo : Option (Expr × Expr) := none) : TermElabM | _ => pure () else trace[MDiffElab] m!"Hoping {e} is a normed field" - let eT : Term ← PrettyPrinter.delab e + let eT : Term ← Term.exprToSyntax e let iTerm : Term ← `(𝓘($eT, $eT)) let I ← Term.elabTerm iTerm none trace[MDiffElab] m!"Found model: {I}" From 39195b9b00f3b7c93901eb87eb0b4010ca793d96 Mon Sep 17 00:00:00 2001 From: thorimur <68410468+thorimur@users.noreply.github.com> Date: Wed, 1 Oct 2025 21:48:50 -0400 Subject: [PATCH 055/106] chore(Elaborators): change trace class names --- Mathlib/Geometry/Manifold/Elaborators.lean | 36 +++++++++++----------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/Mathlib/Geometry/Manifold/Elaborators.lean b/Mathlib/Geometry/Manifold/Elaborators.lean index 2ba55c69a52c0b..bb6502a417034b 100644 --- a/Mathlib/Geometry/Manifold/Elaborators.lean +++ b/Mathlib/Geometry/Manifold/Elaborators.lean @@ -100,18 +100,18 @@ elab:max "T% " t:term:arg : term => do let etype ← whnf <|← instantiateMVars <|← inferType e match etype with | .forallE x base (mkApp3 (.const ``Bundle.Trivial _) E E' _) _ => - trace[TotalSpaceMk] "Section of a trivial bundle" + trace[Elab.DiffGeo.TotalSpaceMk] "Section of a trivial bundle" if ← withReducible (isDefEq E base) then return ← withLocalDecl x BinderInfo.default base fun x ↦ do let body ← mkAppM ``Bundle.TotalSpace.mk' #[E', x, .app e x] mkLambdaFVars #[x] body | .forallE x base (mkApp12 (.const ``TangentSpace _) _k _ E _ _ _H _ _I _M _ _ _x) _ => - trace[TotalSpaceMk] "Vector field" + trace[Elab.DiffGeo.TotalSpaceMk] "Vector field" return ← withLocalDecl x BinderInfo.default base fun x ↦ do let body ← mkAppM ``Bundle.TotalSpace.mk' #[E, x, .app e x] mkLambdaFVars #[x] body | .forallE x base (.app V _) _ => - trace[TotalSpaceMk] "Section of a bundle as a dependent function" + trace[Elab.DiffGeo.TotalSpaceMk] "Section of a bundle as a dependent function" for decl in ← getLocalHyps do let decltype ← whnfR <|← instantiateMVars <|← inferType decl match decltype with @@ -122,7 +122,7 @@ elab:max "T% " t:term:arg : term => do mkLambdaFVars #[x] body | _ => pure () | .forallE x src tgt _ => - trace[TotalSpaceMk] "Section of a trivial bundle as a non-dependent function" + trace[Elab.DiffGeo.TotalSpaceMk] "Section of a trivial bundle as a non-dependent function" -- TODO: can `tgt` depend on `x` in a way that is not a function application? -- Check that `x` is not a bound variable in `tgt`! -- xxx: is this check fine or overzealous? @@ -157,17 +157,17 @@ This implementation is not maximally robust yet. -/ -- FIXME: better failure when trying to find a `NormedField` instance def find_model (e : Expr) (baseInfo : Option (Expr × Expr) := none) : TermElabM Expr := do - trace[MDiffElab] m!"Searching a model for: {e}" + trace[Elab.DiffGeo.MDiff] m!"Searching a model for: {e}" if let mkApp3 (.const ``Bundle.TotalSpace _) _ F V := e then if let mkApp12 (.const ``TangentSpace _) _k _ _E _ _ _H _ I M _ _ _x := V then - trace[MDiffElab] m!"This is the total space of the tangent bundle of {M}" + trace[Elab.DiffGeo.MDiff] m!"This is the total space of the tangent bundle of {M}" let srcIT : Term ← Term.exprToSyntax I let resTerm : Term ← ``(ModelWithCorners.prod $srcIT ModelWithCorners.tangent $srcIT) let res ← Term.elabTerm resTerm none - trace[MDiffElab] m!"Found model: {res}" + trace[Elab.DiffGeo.MDiff] m!"Found model: {res}" return res - trace[MDiffElab] m!"This is a total space with fiber {F}" + trace[Elab.DiffGeo.MDiff] m!"This is a total space with fiber {F}" if let some (_src, srcI) := baseInfo then let mut K : Expr := default let mut normedSpaceInst : Expr := default @@ -178,7 +178,7 @@ def find_model (e : Expr) (baseInfo : Option (Expr × Expr) := none) : TermElabM | mkApp4 (.const ``NormedSpace _) K' E _ _ => if E == F then K := K' - trace[MDiffElab] m!"{F} is a normed field over {K}" + trace[Elab.DiffGeo.MDiff] m!"{F} is a normed field over {K}" normedSpaceInst := decl Kok := true | _ => pure () @@ -190,7 +190,7 @@ def find_model (e : Expr) (baseInfo : Option (Expr × Expr) := none) : TermElabM let FT : Term ← Term.exprToSyntax F let iTerm : Term ← ``(ModelWithCorners.prod $srcIT 𝓘($kT, $FT)) let I ← Term.elabTerm iTerm none - trace[MDiffElab] m!"Found model: {I}" + trace[Elab.DiffGeo.MDiff] m!"Found model: {I}" return I else throwError "Having a TotalSpace as source is not yet supported" @@ -205,12 +205,12 @@ def find_model (e : Expr) (baseInfo : Option (Expr × Expr) := none) : TermElabM | mkApp4 (.const ``ChartedSpace _) H' _ M _ => if M == e then H := H' - trace[MDiffElab] m!"H is: {H}" + trace[Elab.DiffGeo.MDiff] m!"H is: {H}" Hok := true | mkApp4 (.const ``NormedSpace _) K' E _ _ => if E == e then K := K' - trace[MDiffElab] m!"Field is: {K}" + trace[Elab.DiffGeo.MDiff] m!"Field is: {K}" normedSpaceInst := decl Kok := true | _ => pure () @@ -220,14 +220,14 @@ def find_model (e : Expr) (baseInfo : Option (Expr × Expr) := none) : TermElabM let eK : Term ← Term.exprToSyntax K let iTerm : Term ← ``(𝓘($eK, $eT)) let I ← Term.elabTerm iTerm none - trace[MDiffElab] m!"Found model: {I}" + trace[Elab.DiffGeo.MDiff] m!"Found model: {I}" return I -- let uK ← K.getUniverse -- let normedFieldK ← synthInstance (.app (.const ``NontriviallyNormedField [uK]) K) - -- trace[MDiffElab] m!"NontriviallyNormedField instance is: {normedFieldK}" + -- trace[Elab.DiffGeo.MDiff] m!"NontriviallyNormedField instance is: {normedFieldK}" -- let ue ← e.getUniverse -- let normedGroupE ← synthInstance (.app (.const ``NormedAddCommGroup [ue]) e) - -- trace[MDiffElab] m!"NormedAddCommGroup instance is: {normedGroupE}" + -- trace[Elab.DiffGeo.MDiff] m!"NormedAddCommGroup instance is: {normedGroupE}" -- return mkAppN (.const `modelWithCornersSelf [uK, ue]) -- #[K, normedFieldK, e, normedGroupE, normedSpaceInst] else if Hok then @@ -236,15 +236,15 @@ def find_model (e : Expr) (baseInfo : Option (Expr × Expr) := none) : TermElabM match decltype with | mkApp7 (.const ``ModelWithCorners _) _ _ _ _ _ H' _ => if H' == H then - trace[MDiffElab] m!"Found model: {decl}" + trace[Elab.DiffGeo.MDiff] m!"Found model: {decl}" return decl | _ => pure () else - trace[MDiffElab] m!"Hoping {e} is a normed field" + trace[Elab.DiffGeo.MDiff] m!"Hoping {e} is a normed field" let eT : Term ← Term.exprToSyntax e let iTerm : Term ← `(𝓘($eT, $eT)) let I ← Term.elabTerm iTerm none - trace[MDiffElab] m!"Found model: {I}" + trace[Elab.DiffGeo.MDiff] m!"Found model: {I}" return I throwError "Couldn’t find models with corners" From 55134885be5bb72b08b450587a751275beee58ed Mon Sep 17 00:00:00 2001 From: thorimur <68410468+thorimur@users.noreply.github.com> Date: Wed, 1 Oct 2025 22:08:34 -0400 Subject: [PATCH 056/106] feat: move trace classes into main file; make collective trace class; make descriptions into docstrings --- Mathlib.lean | 1 - Mathlib/Geometry/Manifold/Elaborators.lean | 31 +++++++++++++++++++++- Mathlib/Geometry/Manifold/Traces.lean | 25 ----------------- scripts/noshake.json | 1 - 4 files changed, 30 insertions(+), 28 deletions(-) delete mode 100644 Mathlib/Geometry/Manifold/Traces.lean diff --git a/Mathlib.lean b/Mathlib.lean index b164589ad62537..7dccd338c376ea 100644 --- a/Mathlib.lean +++ b/Mathlib.lean @@ -3936,7 +3936,6 @@ import Mathlib.Geometry.Manifold.Riemannian.PathELength import Mathlib.Geometry.Manifold.Sheaf.Basic import Mathlib.Geometry.Manifold.Sheaf.LocallyRingedSpace import Mathlib.Geometry.Manifold.Sheaf.Smooth -import Mathlib.Geometry.Manifold.Traces import Mathlib.Geometry.Manifold.VectorBundle.Basic import Mathlib.Geometry.Manifold.VectorBundle.FiberwiseLinear import Mathlib.Geometry.Manifold.VectorBundle.Hom diff --git a/Mathlib/Geometry/Manifold/Elaborators.lean b/Mathlib/Geometry/Manifold/Elaborators.lean index bb6502a417034b..780a75eeb52f55 100644 --- a/Mathlib/Geometry/Manifold/Elaborators.lean +++ b/Mathlib/Geometry/Manifold/Elaborators.lean @@ -5,7 +5,6 @@ Authors: Patrick Massot, Michael Rothgang -/ import Mathlib.Geometry.Manifold.ContMDiff.Defs import Mathlib.Geometry.Manifold.MFDeriv.Defs -import Mathlib.Geometry.Manifold.Traces /-! # Elaborators for differential geometry @@ -406,3 +405,33 @@ elab:max "mfderiv%" ppSpace t:term:arg : term => do | none => throwError m!"Term {e} is not a function." end Manifold + +section trace + +/-! +### Trace classes + +Note that the overall `Elab` trace class does not inherit the trace classes defined in this +section, since they provide verbose information. +-/ + +/-- +Trace class for differential geometry elaborators. Setting this to `true` traces elaboration +for the `T%` elaborator (`trace.Elab.DiffGeo.TotalSpaceMk`) and the family of `MDiff`-like +elaborators (`trace.Elab.DiffGeo.MDiff`). +-/ +initialize registerTraceClass `Elab.DiffGeo + +/-- +Trace class for the `T%` elaborator, which converts a section of a vector bundle as a dependent +function to a non-dependent function into the total space. +-/ +initialize registerTraceClass `Elab.DiffGeo.TotalSpaceMk (inherited := true) + +/-- +Trace class for the `MDiff` elaborator and friends, which infer a model with corners on the domain +(resp. codomain) of the map in question. +-/ +initialize registerTraceClass `Elab.DiffGeo.MDiff (inherited := true) + +end trace diff --git a/Mathlib/Geometry/Manifold/Traces.lean b/Mathlib/Geometry/Manifold/Traces.lean deleted file mode 100644 index 83cdf708992932..00000000000000 --- a/Mathlib/Geometry/Manifold/Traces.lean +++ /dev/null @@ -1,25 +0,0 @@ -/- -Copyright (c) 2025 Patrick Massot. All rights reserved. -Released under Apache 2.0 license as described in the file LICENSE. -Authors: Patrick Massot, Michael Rothgang --/ -import Lean.Util.Trace - -/-! -# Trace classes for differential geometry elaborators - -This file defines custom trace classes for the differential geometry elaborators in -`Mathlib.Geometry.Manifold.Elaborators.lean`. These need to be in a different file for technical -reasons. - -The `TotalSpaceMk` trace class is associated to the `T%` elaborator, which converts a section -of a vector bundle as a dependent function to a non-dependent function into the total space. - -The `MDiffElab` trace class corresponds to the elaborators `CMDiff` and friends, and provides -tracing information about inferring a model with corners on the domain (resp. codomain) of the -map in question. --/ -open Lean - -initialize registerTraceClass `TotalSpaceMk -initialize registerTraceClass `MDiffElab diff --git a/scripts/noshake.json b/scripts/noshake.json index 99609d4075c6ca..ff19c31cadcd7e 100644 --- a/scripts/noshake.json +++ b/scripts/noshake.json @@ -51,7 +51,6 @@ "Mathlib.Data.Vector.Basic", "Mathlib.Geometry.Manifold.Instances.Real", "Mathlib.Geometry.Manifold.Elaborators", - "Mathlib.Geometry.Manifold.Traces", "Mathlib.Init", "Mathlib.LinearAlgebra.AffineSpace.Basic", "Mathlib.LinearAlgebra.Matrix.Notation", From bd08a3da4702889477c1edd7caebe5524f2ad478 Mon Sep 17 00:00:00 2001 From: thorimur <68410468+thorimur@users.noreply.github.com> Date: Wed, 1 Oct 2025 22:12:53 -0400 Subject: [PATCH 057/106] chore: rename `find_model` -> `findModel`, `_find_models` -> `findModels` --- Mathlib/Geometry/Manifold/Elaborators.lean | 32 +++++++++++----------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/Mathlib/Geometry/Manifold/Elaborators.lean b/Mathlib/Geometry/Manifold/Elaborators.lean index 780a75eeb52f55..007fa82f68d842 100644 --- a/Mathlib/Geometry/Manifold/Elaborators.lean +++ b/Mathlib/Geometry/Manifold/Elaborators.lean @@ -155,7 +155,7 @@ corners. This implementation is not maximally robust yet. -/ -- FIXME: better failure when trying to find a `NormedField` instance -def find_model (e : Expr) (baseInfo : Option (Expr × Expr) := none) : TermElabM Expr := do +def findModel (e : Expr) (baseInfo : Option (Expr × Expr) := none) : TermElabM Expr := do trace[Elab.DiffGeo.MDiff] m!"Searching a model for: {e}" if let mkApp3 (.const ``Bundle.TotalSpace _) _ F V := e then if let mkApp12 (.const ``TangentSpace _) _k _ _E _ _ _H _ I M _ _ _x := V then @@ -252,11 +252,11 @@ corners on both `src` and `tgt`. If successful, return both models. `ef` is the term having type `etype`: this is used only for better diagnostics. If `estype` is `some`, we verify that `src` and `estype` are def-eq. -/ -def _find_models (etype eterm : Expr) (estype : Option Expr) : +def findModels (etype eterm : Expr) (estype : Option Expr) : TermElabM (Option (Expr × Expr)) := do match etype with | .forallE _ src tgt _ => - let srcI ← find_model src + let srcI ← findModel src if Lean.Expr.hasLooseBVars tgt then throwError m!"Term {eterm} is a dependent function, of type {etype}\n\ Hint: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one" @@ -264,7 +264,7 @@ def _find_models (etype eterm : Expr) (estype : Option Expr) : if !(← isDefEq es (← mkAppM ``Set #[src])) then throwError m!"The domain {src} of {eterm} is not definitionally equal to the carrier of the type {es} of the set 's' passed in" - let tgtI ← find_model tgt (src, srcI) + let tgtI ← findModel tgt (src, srcI) return some (srcI, tgtI) | _ => return none @@ -276,7 +276,7 @@ elab:max "MDiffAt[" s:term:arg "]" ppSpace f:term:arg : term => do let ef ← Term.elabTerm f none let etype ← whnfR <|← instantiateMVars <|← inferType ef let estype ← whnfR <|← instantiateMVars <|← inferType es - match ← _find_models etype ef estype with + match ← findModels etype ef estype with | some (srcI, tgtI) => return ← mkAppM ``MDifferentiableWithinAt #[srcI, tgtI, ef, es] | none => throwError m!"Term {ef} is not a function." @@ -286,7 +286,7 @@ The argument `x` can be omitted. -/ elab:max "MDiffAt" ppSpace t:term:arg : term => do let e ← Term.elabTerm t none let etype ← whnfR <|← instantiateMVars <|← inferType e - match ← _find_models etype e none with + match ← findModels etype e none with | some (srcI, tgtI) => return ← mkAppM ``MDifferentiableAt #[srcI, tgtI, e] | none => throwError m!"Term {e} is not a function." @@ -300,12 +300,12 @@ elab:max "MDiffAt2" ppSpace t:term:arg : term => do let etype ← whnfR <|← instantiateMVars <|← inferType e forallBoundedTelescope etype (some 1) fun src tgt ↦ do if let some src := src[0]? then - let srcI ← find_model src + let srcI ← findModel src if Lean.Expr.occurs src tgt then throwError m!"Term {e} is a dependent function, of type {etype}\n\ Hint: you can use the 'T%' elaborator to convert a dependent function \ to a non-dependent one" - let tgtI ← find_model tgt (src, srcI) + let tgtI ← findModel tgt (src, srcI) return ← mkAppM ``MDifferentiableAt #[srcI, tgtI, e] else throwError m!"Term {e} is not a function." @@ -317,7 +317,7 @@ elab:max "MDiff[" s:term:arg "]" ppSpace t:term:arg : term => do let et ← Term.elabTerm t none let estype ← whnfR <|← instantiateMVars <|← inferType es let etype ← whnfR <|← instantiateMVars <|← inferType et - match ← _find_models etype et estype with + match ← findModels etype et estype with | some (srcI, tgtI) => return ← mkAppM ``MDifferentiableOn #[srcI, tgtI, et, es] | none => throwError m!"Term {et} is not a function." @@ -326,7 +326,7 @@ trying to determine `I` and `J` from the local context. -/ elab:max "MDiff" ppSpace t:term:arg : term => do let e ← Term.elabTerm t none let etype ← whnfR <|← instantiateMVars <|← inferType e - match ← _find_models etype e none with + match ← findModels etype e none with | some (srcI, tgtI) => return ← mkAppM ``MDifferentiable #[srcI, tgtI, e] | none => throwError m!"Term {e} is not a function." @@ -341,7 +341,7 @@ elab:max "CMDiffAt[" s:term:arg "]" ppSpace nt:term:arg ppSpace f:term:arg : ter let ne ← Term.elabTermEnsuringType nt wtn let estype ← whnfR <|← instantiateMVars <|← inferType es let eftype ← whnfR <|← instantiateMVars <|← inferType ef - match ← _find_models eftype ef estype with + match ← findModels eftype ef estype with | some (srcI, tgtI) => return ← mkAppM ``ContMDiffWithinAt #[srcI, tgtI, ne, ef, es] | none => throwError m!"Term {ef} is not a function." @@ -354,7 +354,7 @@ elab:max "CMDiffAt" ppSpace nt:term:arg ppSpace t:term:arg : term => do let wtn ← Term.elabTerm (← ``(WithTop ℕ∞)) none let ne ← Term.elabTermEnsuringType nt wtn let etype ← whnfR <|← instantiateMVars <|← inferType e - match ← _find_models etype e none with + match ← findModels etype e none with | some (srcI, tgtI) => return ← mkAppM ``ContMDiffAt #[srcI, tgtI, ne, e] | none => throwError m!"Term {e} is not a function." @@ -368,7 +368,7 @@ elab:max "CMDiff[" s:term:arg "]" ppSpace nt:term:arg ppSpace f:term:arg : term let ne ← Term.elabTermEnsuringType nt wtn let estype ← whnfR <|← instantiateMVars <|← inferType es let eftype ← whnfR <|← instantiateMVars <|← inferType ef - match ← _find_models eftype ef estype with + match ← findModels eftype ef estype with | some (srcI, tgtI) => return ← mkAppM ``ContMDiffOn #[srcI, tgtI, ne, ef, es] | none => throwError m!"Term {ef} is not a function." @@ -380,7 +380,7 @@ elab:max "CMDiff" ppSpace nt:term:arg ppSpace f:term:arg : term => do let wtn ← Term.elabTerm (← `(WithTop ℕ∞)) none let ne ← Term.elabTermEnsuringType nt wtn let etype ← whnfR <|← instantiateMVars <|← inferType e - match ← _find_models etype e none with + match ← findModels etype e none with | some (srcI, tgtI) => return ← mkAppM ``ContMDiff #[srcI, tgtI, ne, e] | none => throwError m!"Term {e} is not a function." @@ -391,7 +391,7 @@ elab:max "mfderiv[" s:term:arg "]" ppSpace t:term:arg : term => do let e ← Term.elabTerm t none let etype ← whnfR <|← instantiateMVars <|← inferType e let estype ← whnfR <|← instantiateMVars <|← inferType es - match ← _find_models etype e estype with + match ← findModels etype e estype with | some (srcI, tgtI) => return ← mkAppM ``mfderivWithin #[srcI, tgtI, e, es] | none => throwError m!"Term {e} is not a function." @@ -400,7 +400,7 @@ trying to determine `I` and `J` from the local context. -/ elab:max "mfderiv%" ppSpace t:term:arg : term => do let e ← Term.elabTerm t none let etype ← whnfR <|← instantiateMVars <|← inferType e - match ← _find_models etype e none with + match ← findModels etype e none with | some (srcI, tgtI) => return ← mkAppM ``mfderiv #[srcI, tgtI, e] | none => throwError m!"Term {e} is not a function." From 61b350b8816ae639092be9c72fc8967b507e6330 Mon Sep 17 00:00:00 2001 From: thorimur <68410468+thorimur@users.noreply.github.com> Date: Wed, 1 Oct 2025 22:40:42 -0400 Subject: [PATCH 058/106] =?UTF-8?q?chore:=20use=20Qq=20to=20construct=20`W?= =?UTF-8?q?ithTop=20=E2=84=95=E2=88=9E`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Mathlib/Geometry/Manifold/Elaborators.lean | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/Mathlib/Geometry/Manifold/Elaborators.lean b/Mathlib/Geometry/Manifold/Elaborators.lean index 007fa82f68d842..78e2cb2a88f87c 100644 --- a/Mathlib/Geometry/Manifold/Elaborators.lean +++ b/Mathlib/Geometry/Manifold/Elaborators.lean @@ -76,6 +76,7 @@ open scoped Bundle Manifold ContDiff open Lean Meta Elab Tactic open Mathlib.Tactic +open Qq /-- Call `mkApp` recursively with 12 arguments -/ @[match_pattern] def mkApp12 (f a b c d e g e₁ e₂ e₃ e₄ e₅ e₆ : Expr) := @@ -337,8 +338,7 @@ The argument `x` can be omitted. -/ elab:max "CMDiffAt[" s:term:arg "]" ppSpace nt:term:arg ppSpace f:term:arg : term => do let es ← Term.elabTerm s none let ef ← Term.elabTerm f none - let wtn ← Term.elabTerm (← `(WithTop ℕ∞)) none - let ne ← Term.elabTermEnsuringType nt wtn + let ne ← Term.elabTermEnsuringType nt q(WithTop ℕ∞) let estype ← whnfR <|← instantiateMVars <|← inferType es let eftype ← whnfR <|← instantiateMVars <|← inferType ef match ← findModels eftype ef estype with @@ -351,8 +351,7 @@ trying to determine `I` and `J` from the local context. The argument `x` can be omitted. -/ elab:max "CMDiffAt" ppSpace nt:term:arg ppSpace t:term:arg : term => do let e ← Term.elabTerm t none - let wtn ← Term.elabTerm (← ``(WithTop ℕ∞)) none - let ne ← Term.elabTermEnsuringType nt wtn + let ne ← Term.elabTermEnsuringType nt q(WithTop ℕ∞) let etype ← whnfR <|← instantiateMVars <|← inferType e match ← findModels etype e none with | some (srcI, tgtI) => return ← mkAppM ``ContMDiffAt #[srcI, tgtI, ne, e] @@ -364,8 +363,7 @@ trying to determine `I` and `J` from the local context. elab:max "CMDiff[" s:term:arg "]" ppSpace nt:term:arg ppSpace f:term:arg : term => do let es ← Term.elabTerm s none let ef ← Term.elabTerm f none - let wtn ← Term.elabTerm (← ``(WithTop ℕ∞)) none - let ne ← Term.elabTermEnsuringType nt wtn + let ne ← Term.elabTermEnsuringType nt q(WithTop ℕ∞) let estype ← whnfR <|← instantiateMVars <|← inferType es let eftype ← whnfR <|← instantiateMVars <|← inferType ef match ← findModels eftype ef estype with @@ -377,8 +375,7 @@ trying to determine `I` and `J` from the local context. `n` is coerced to `WithTop ℕ∞` if necessary (so passing a `ℕ`, `∞` or `ω` are all supported). -/ elab:max "CMDiff" ppSpace nt:term:arg ppSpace f:term:arg : term => do let e ← Term.elabTerm f none - let wtn ← Term.elabTerm (← `(WithTop ℕ∞)) none - let ne ← Term.elabTermEnsuringType nt wtn + let ne ← Term.elabTermEnsuringType nt q(WithTop ℕ∞) let etype ← whnfR <|← instantiateMVars <|← inferType e match ← findModels etype e none with | some (srcI, tgtI) => return ← mkAppM ``ContMDiff #[srcI, tgtI, ne, e] From a0587dfb734ccda3b4cf7b4fda3b608f5701db96 Mon Sep 17 00:00:00 2001 From: thorimur <68410468+thorimur@users.noreply.github.com> Date: Thu, 2 Oct 2025 12:20:37 -0400 Subject: [PATCH 059/106] refactor: factor out loops into (private) definitions for readability; search local instances for classes instead of whole context --- Mathlib/Geometry/Manifold/Elaborators.lean | 96 +++++++++++----------- 1 file changed, 49 insertions(+), 47 deletions(-) diff --git a/Mathlib/Geometry/Manifold/Elaborators.lean b/Mathlib/Geometry/Manifold/Elaborators.lean index 78e2cb2a88f87c..93505a3dcbfdbe 100644 --- a/Mathlib/Geometry/Manifold/Elaborators.lean +++ b/Mathlib/Geometry/Manifold/Elaborators.lean @@ -136,6 +136,26 @@ elab:max "T% " t:term:arg : term => do | _ => pure () return e +/-- Finds the first local instance of class `c` for which `p inst type` produces `some a`. +Instantiates mvars in and runs `whnfR` on `type` before passing it to `p`. (Does not validate that +`c` resolves to a class.) -/ +private def findSomeLocalInstanceOf? (c : Name) {α} (p : Expr → Expr → MetaM (Option α)) : + MetaM (Option α) := do + (← getLocalInstances).findSomeM? fun inst ↦ do + if inst.className == c then + let type ← whnfR <|← instantiateMVars <|← inferType inst.fvar + p inst.fvar type + else return none + +/-- Finds the most recent local declaration for which `p fvar type` produces `some a`. +Skips implementation details; instantiates mvars in and runs `whnfR` on `type` before providing it +to `p`. -/ +private def findSomeLocalHyp? {α} (p : Expr → Expr → MetaM (Option α)) : MetaM (Option α) := do + (← getLCtx).findDeclRevM? fun decl ↦ do + if decl.isImplementationDetail then return none + let type ← whnfR <|← instantiateMVars decl.type + p decl.toExpr type + /-- Try to find a `ModelWithCorners` instance on a type (represented by an expression `e`), using the local context to infer the expected type. This supports the following cases: - the model with corners on the total space of a vector bundle @@ -169,22 +189,13 @@ def findModel (e : Expr) (baseInfo : Option (Expr × Expr) := none) : TermElabM trace[Elab.DiffGeo.MDiff] m!"This is a total space with fiber {F}" if let some (_src, srcI) := baseInfo then - let mut K : Expr := default - let mut normedSpaceInst : Expr := default - let mut Kok : Bool := false - for decl in ← getLocalHyps do - let decltype ← whnfR <|← instantiateMVars <|← inferType decl - match decltype with - | mkApp4 (.const ``NormedSpace _) K' E _ _ => - if E == F then - K := K' - trace[Elab.DiffGeo.MDiff] m!"{F} is a normed field over {K}" - normedSpaceInst := decl - Kok := true - | _ => pure () - if Kok then break - unless Kok do throwError - m!"Couldn’t find a normed space structure on {F} in local context" + let some K ← findSomeLocalInstanceOf? ``NormedSpace fun _ type ↦ do + match_expr type with + | NormedSpace K E _ _ => + if E == F then return some K else return none + | _ => return none + | throwError "Couldn't find a `NormedSpace` structure on {F} in the local instances." + trace[Elab.DiffGeo.MDiff] m!"{F} is a normed field over {K}" let kT : Term ← Term.exprToSyntax K let srcIT : Term ← Term.exprToSyntax srcI let FT : Term ← Term.exprToSyntax F @@ -194,28 +205,13 @@ def findModel (e : Expr) (baseInfo : Option (Expr × Expr) := none) : TermElabM return I else throwError "Having a TotalSpace as source is not yet supported" - let mut H : Expr := default - let mut Hok : Bool := false - let mut K : Expr := default - let mut normedSpaceInst : Expr := default - let mut Kok : Bool := false - for decl in ← getLocalHyps do - let decltype ← whnfR <|← instantiateMVars <|← inferType decl - match decltype with - | mkApp4 (.const ``ChartedSpace _) H' _ M _ => - if M == e then - H := H' - trace[Elab.DiffGeo.MDiff] m!"H is: {H}" - Hok := true - | mkApp4 (.const ``NormedSpace _) K' E _ _ => - if E == e then - K := K' - trace[Elab.DiffGeo.MDiff] m!"Field is: {K}" - normedSpaceInst := decl - Kok := true - | _ => pure () - if Hok || Kok then break - if Kok then + let K? ← findSomeLocalInstanceOf? ``NormedSpace fun _ type ↦ do + match_expr type with + | NormedSpace K E _ _ => + if E == e then return some K else return none + | _ => return none + if let some K := K? then + trace[Elab.DiffGeo.MDiff] "Field is: {K}" let eT : Term ← Term.exprToSyntax e let eK : Term ← Term.exprToSyntax K let iTerm : Term ← ``(𝓘($eK, $eT)) @@ -230,15 +226,21 @@ def findModel (e : Expr) (baseInfo : Option (Expr × Expr) := none) : TermElabM -- trace[Elab.DiffGeo.MDiff] m!"NormedAddCommGroup instance is: {normedGroupE}" -- return mkAppN (.const `modelWithCornersSelf [uK, ue]) -- #[K, normedFieldK, e, normedGroupE, normedSpaceInst] - else if Hok then - for decl in ← getLocalHyps do - let decltype ← whnfR <|← instantiateMVars <|← inferType decl - match decltype with - | mkApp7 (.const ``ModelWithCorners _) _ _ _ _ _ H' _ => - if H' == H then - trace[Elab.DiffGeo.MDiff] m!"Found model: {decl}" - return decl - | _ => pure () + let H? ← findSomeLocalInstanceOf? ``ChartedSpace fun _ type ↦ do + match_expr type with + | ChartedSpace H _ M _ => + if M == e then return some H else return none + | _ => return none + if let some H := H? then + trace[Elab.DiffGeo.MDiff] "H is: {H}" + let some m ← findSomeLocalHyp? fun fvar type ↦ do + match_expr type with + | ModelWithCorners _ _ _ _ _ H' _ => do + if H' == H then return some fvar else return none + | _ => return none + | pure + trace[Elab.DiffGeo.MDiff] m!"Found model: {m}" + return m else trace[Elab.DiffGeo.MDiff] m!"Hoping {e} is a normed field" let eT : Term ← Term.exprToSyntax e From 38b2737880aabe6251faaf83a6d555c129362441 Mon Sep 17 00:00:00 2001 From: thorimur <68410468+thorimur@users.noreply.github.com> Date: Thu, 2 Oct 2025 12:26:40 -0400 Subject: [PATCH 060/106] chore: remove unnecessary `m!`s --- Mathlib/Geometry/Manifold/Elaborators.lean | 54 +++++++++++----------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/Mathlib/Geometry/Manifold/Elaborators.lean b/Mathlib/Geometry/Manifold/Elaborators.lean index 93505a3dcbfdbe..3de739da8dfde7 100644 --- a/Mathlib/Geometry/Manifold/Elaborators.lean +++ b/Mathlib/Geometry/Manifold/Elaborators.lean @@ -127,7 +127,7 @@ elab:max "T% " t:term:arg : term => do -- Check that `x` is not a bound variable in `tgt`! -- xxx: is this check fine or overzealous? if Lean.Expr.hasLooseBVars tgt then - throwError m!"Term {tgt} has loose bound variables¬ + throwError "Term {tgt} has loose bound variables¬ Hint: applying the 'T%' elaborator twice makes no sense." let trivBundle ← mkAppOptM ``Bundle.Trivial #[src, tgt] return ← withLocalDecl x BinderInfo.default src fun x ↦ do @@ -177,17 +177,17 @@ This implementation is not maximally robust yet. -/ -- FIXME: better failure when trying to find a `NormedField` instance def findModel (e : Expr) (baseInfo : Option (Expr × Expr) := none) : TermElabM Expr := do - trace[Elab.DiffGeo.MDiff] m!"Searching a model for: {e}" + trace[Elab.DiffGeo.MDiff] "Searching a model for: {e}" if let mkApp3 (.const ``Bundle.TotalSpace _) _ F V := e then if let mkApp12 (.const ``TangentSpace _) _k _ _E _ _ _H _ I M _ _ _x := V then - trace[Elab.DiffGeo.MDiff] m!"This is the total space of the tangent bundle of {M}" + trace[Elab.DiffGeo.MDiff] "This is the total space of the tangent bundle of {M}" let srcIT : Term ← Term.exprToSyntax I let resTerm : Term ← ``(ModelWithCorners.prod $srcIT ModelWithCorners.tangent $srcIT) let res ← Term.elabTerm resTerm none - trace[Elab.DiffGeo.MDiff] m!"Found model: {res}" + trace[Elab.DiffGeo.MDiff] "Found model: {res}" return res - trace[Elab.DiffGeo.MDiff] m!"This is a total space with fiber {F}" + trace[Elab.DiffGeo.MDiff] "This is a total space with fiber {F}" if let some (_src, srcI) := baseInfo then let some K ← findSomeLocalInstanceOf? ``NormedSpace fun _ type ↦ do match_expr type with @@ -195,13 +195,13 @@ def findModel (e : Expr) (baseInfo : Option (Expr × Expr) := none) : TermElabM if E == F then return some K else return none | _ => return none | throwError "Couldn't find a `NormedSpace` structure on {F} in the local instances." - trace[Elab.DiffGeo.MDiff] m!"{F} is a normed field over {K}" + trace[Elab.DiffGeo.MDiff] "{F} is a normed field over {K}" let kT : Term ← Term.exprToSyntax K let srcIT : Term ← Term.exprToSyntax srcI let FT : Term ← Term.exprToSyntax F let iTerm : Term ← ``(ModelWithCorners.prod $srcIT 𝓘($kT, $FT)) let I ← Term.elabTerm iTerm none - trace[Elab.DiffGeo.MDiff] m!"Found model: {I}" + trace[Elab.DiffGeo.MDiff] "Found model: {I}" return I else throwError "Having a TotalSpace as source is not yet supported" @@ -216,14 +216,14 @@ def findModel (e : Expr) (baseInfo : Option (Expr × Expr) := none) : TermElabM let eK : Term ← Term.exprToSyntax K let iTerm : Term ← ``(𝓘($eK, $eT)) let I ← Term.elabTerm iTerm none - trace[Elab.DiffGeo.MDiff] m!"Found model: {I}" + trace[Elab.DiffGeo.MDiff] "Found model: {I}" return I -- let uK ← K.getUniverse -- let normedFieldK ← synthInstance (.app (.const ``NontriviallyNormedField [uK]) K) - -- trace[Elab.DiffGeo.MDiff] m!"NontriviallyNormedField instance is: {normedFieldK}" + -- trace[Elab.DiffGeo.MDiff] "NontriviallyNormedField instance is: {normedFieldK}" -- let ue ← e.getUniverse -- let normedGroupE ← synthInstance (.app (.const ``NormedAddCommGroup [ue]) e) - -- trace[Elab.DiffGeo.MDiff] m!"NormedAddCommGroup instance is: {normedGroupE}" + -- trace[Elab.DiffGeo.MDiff] "NormedAddCommGroup instance is: {normedGroupE}" -- return mkAppN (.const `modelWithCornersSelf [uK, ue]) -- #[K, normedFieldK, e, normedGroupE, normedSpaceInst] let H? ← findSomeLocalInstanceOf? ``ChartedSpace fun _ type ↦ do @@ -239,14 +239,14 @@ def findModel (e : Expr) (baseInfo : Option (Expr × Expr) := none) : TermElabM if H' == H then return some fvar else return none | _ => return none | pure - trace[Elab.DiffGeo.MDiff] m!"Found model: {m}" + trace[Elab.DiffGeo.MDiff] "Found model: {m}" return m else - trace[Elab.DiffGeo.MDiff] m!"Hoping {e} is a normed field" + trace[Elab.DiffGeo.MDiff] "Hoping {e} is a normed field" let eT : Term ← Term.exprToSyntax e let iTerm : Term ← `(𝓘($eT, $eT)) let I ← Term.elabTerm iTerm none - trace[Elab.DiffGeo.MDiff] m!"Found model: {I}" + trace[Elab.DiffGeo.MDiff] "Found model: {I}" return I throwError "Couldn’t find models with corners" @@ -261,11 +261,11 @@ def findModels (etype eterm : Expr) (estype : Option Expr) : | .forallE _ src tgt _ => let srcI ← findModel src if Lean.Expr.hasLooseBVars tgt then - throwError m!"Term {eterm} is a dependent function, of type {etype}\n\ + throwError "Term {eterm} is a dependent function, of type {etype}\n\ Hint: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one" if let some es := estype then if !(← isDefEq es (← mkAppM ``Set #[src])) then - throwError m!"The domain {src} of {eterm} is not definitionally equal to the carrier + throwError "The domain {src} of {eterm} is not definitionally equal to the carrier of the type {es} of the set 's' passed in" let tgtI ← findModel tgt (src, srcI) return some (srcI, tgtI) @@ -281,7 +281,7 @@ elab:max "MDiffAt[" s:term:arg "]" ppSpace f:term:arg : term => do let estype ← whnfR <|← instantiateMVars <|← inferType es match ← findModels etype ef estype with | some (srcI, tgtI) => return ← mkAppM ``MDifferentiableWithinAt #[srcI, tgtI, ef, es] - | none => throwError m!"Term {ef} is not a function." + | none => throwError "Term {ef} is not a function." /-- `MDiffAt f x` elaborates to `MDifferentiableAt I J f x`, trying to determine `I` and `J` from the local context. @@ -291,7 +291,7 @@ elab:max "MDiffAt" ppSpace t:term:arg : term => do let etype ← whnfR <|← instantiateMVars <|← inferType e match ← findModels etype e none with | some (srcI, tgtI) => return ← mkAppM ``MDifferentiableAt #[srcI, tgtI, e] - | none => throwError m!"Term {e} is not a function." + | none => throwError "Term {e} is not a function." -- This implement is more robust (in theory), but currently fails tests. -- TODO: investigate why, fix this and replace `MDiffAt` by this one! @@ -305,13 +305,13 @@ elab:max "MDiffAt2" ppSpace t:term:arg : term => do if let some src := src[0]? then let srcI ← findModel src if Lean.Expr.occurs src tgt then - throwError m!"Term {e} is a dependent function, of type {etype}\n\ + throwError "Term {e} is a dependent function, of type {etype}\n\ Hint: you can use the 'T%' elaborator to convert a dependent function \ to a non-dependent one" let tgtI ← findModel tgt (src, srcI) return ← mkAppM ``MDifferentiableAt #[srcI, tgtI, e] else - throwError m!"Term {e} is not a function." + throwError "Term {e} is not a function." /-- `MDiff[s] f` elaborates to `MDifferentiableOn I J f s`, trying to determine `I` and `J` from the local context. -/ @@ -322,7 +322,7 @@ elab:max "MDiff[" s:term:arg "]" ppSpace t:term:arg : term => do let etype ← whnfR <|← instantiateMVars <|← inferType et match ← findModels etype et estype with | some (srcI, tgtI) => return ← mkAppM ``MDifferentiableOn #[srcI, tgtI, et, es] - | none => throwError m!"Term {et} is not a function." + | none => throwError "Term {et} is not a function." /-- `MDiff f` elaborates to `MDifferentiable I J f`, trying to determine `I` and `J` from the local context. -/ @@ -331,7 +331,7 @@ elab:max "MDiff" ppSpace t:term:arg : term => do let etype ← whnfR <|← instantiateMVars <|← inferType e match ← findModels etype e none with | some (srcI, tgtI) => return ← mkAppM ``MDifferentiable #[srcI, tgtI, e] - | none => throwError m!"Term {e} is not a function." + | none => throwError "Term {e} is not a function." /-- `CMDiffAt[s] n f x` elaborates to `ContMDiffWithinAt I J n f s x`, trying to determine `I` and `J` from the local context. @@ -345,7 +345,7 @@ elab:max "CMDiffAt[" s:term:arg "]" ppSpace nt:term:arg ppSpace f:term:arg : ter let eftype ← whnfR <|← instantiateMVars <|← inferType ef match ← findModels eftype ef estype with | some (srcI, tgtI) => return ← mkAppM ``ContMDiffWithinAt #[srcI, tgtI, ne, ef, es] - | none => throwError m!"Term {ef} is not a function." + | none => throwError "Term {ef} is not a function." /-- `CMDiffAt n f x` elaborates to `ContMDiffAt I J n f x` trying to determine `I` and `J` from the local context. @@ -357,7 +357,7 @@ elab:max "CMDiffAt" ppSpace nt:term:arg ppSpace t:term:arg : term => do let etype ← whnfR <|← instantiateMVars <|← inferType e match ← findModels etype e none with | some (srcI, tgtI) => return ← mkAppM ``ContMDiffAt #[srcI, tgtI, ne, e] - | none => throwError m!"Term {e} is not a function." + | none => throwError "Term {e} is not a function." /-- `CMDiff[s] n f` elaborates to `ContMDiffOn I J n f s`, trying to determine `I` and `J` from the local context. @@ -370,7 +370,7 @@ elab:max "CMDiff[" s:term:arg "]" ppSpace nt:term:arg ppSpace f:term:arg : term let eftype ← whnfR <|← instantiateMVars <|← inferType ef match ← findModels eftype ef estype with | some (srcI, tgtI) => return ← mkAppM ``ContMDiffOn #[srcI, tgtI, ne, ef, es] - | none => throwError m!"Term {ef} is not a function." + | none => throwError "Term {ef} is not a function." /-- `CMDiff n f` elaborates to `ContMDiff I J n f`, trying to determine `I` and `J` from the local context. @@ -381,7 +381,7 @@ elab:max "CMDiff" ppSpace nt:term:arg ppSpace f:term:arg : term => do let etype ← whnfR <|← instantiateMVars <|← inferType e match ← findModels etype e none with | some (srcI, tgtI) => return ← mkAppM ``ContMDiff #[srcI, tgtI, ne, e] - | none => throwError m!"Term {e} is not a function." + | none => throwError "Term {e} is not a function." /-- `mfderiv[u] f x` elaborates to `mfderivWithin I J f u x`, trying to determine `I` and `J` from the local context. -/ @@ -392,7 +392,7 @@ elab:max "mfderiv[" s:term:arg "]" ppSpace t:term:arg : term => do let estype ← whnfR <|← instantiateMVars <|← inferType es match ← findModels etype e estype with | some (srcI, tgtI) => return ← mkAppM ``mfderivWithin #[srcI, tgtI, e, es] - | none => throwError m!"Term {e} is not a function." + | none => throwError "Term {e} is not a function." /-- `mfderiv% f x` elaborates to `mfderiv I J f x`, trying to determine `I` and `J` from the local context. -/ @@ -401,7 +401,7 @@ elab:max "mfderiv%" ppSpace t:term:arg : term => do let etype ← whnfR <|← instantiateMVars <|← inferType e match ← findModels etype e none with | some (srcI, tgtI) => return ← mkAppM ``mfderiv #[srcI, tgtI, e] - | none => throwError m!"Term {e} is not a function." + | none => throwError "Term {e} is not a function." end Manifold From 73c361fe5eae34622a520bc7ee2af29ffa947731 Mon Sep 17 00:00:00 2001 From: thorimur <68410468+thorimur@users.noreply.github.com> Date: Thu, 2 Oct 2025 12:46:02 -0400 Subject: [PATCH 061/106] style: use `withLocalDeclD` --- Mathlib/Geometry/Manifold/Elaborators.lean | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Mathlib/Geometry/Manifold/Elaborators.lean b/Mathlib/Geometry/Manifold/Elaborators.lean index 3de739da8dfde7..36370bdd053027 100644 --- a/Mathlib/Geometry/Manifold/Elaborators.lean +++ b/Mathlib/Geometry/Manifold/Elaborators.lean @@ -102,12 +102,12 @@ elab:max "T% " t:term:arg : term => do | .forallE x base (mkApp3 (.const ``Bundle.Trivial _) E E' _) _ => trace[Elab.DiffGeo.TotalSpaceMk] "Section of a trivial bundle" if ← withReducible (isDefEq E base) then - return ← withLocalDecl x BinderInfo.default base fun x ↦ do + return ← withLocalDeclD x base fun x ↦ do let body ← mkAppM ``Bundle.TotalSpace.mk' #[E', x, .app e x] mkLambdaFVars #[x] body | .forallE x base (mkApp12 (.const ``TangentSpace _) _k _ E _ _ _H _ _I _M _ _ _x) _ => trace[Elab.DiffGeo.TotalSpaceMk] "Vector field" - return ← withLocalDecl x BinderInfo.default base fun x ↦ do + return ← withLocalDeclD x base fun x ↦ do let body ← mkAppM ``Bundle.TotalSpace.mk' #[E, x, .app e x] mkLambdaFVars #[x] body | .forallE x base (.app V _) _ => @@ -117,7 +117,7 @@ elab:max "T% " t:term:arg : term => do match decltype with | mkApp7 (.const `FiberBundle _) _ F _ _ E _ _ => if ← withReducible (isDefEq E V) then - return ← withLocalDecl x BinderInfo.default base fun x ↦ do + return ← withLocalDeclD x base fun x ↦ do let body ← mkAppM ``Bundle.TotalSpace.mk' #[F, x, .app e x] mkLambdaFVars #[x] body | _ => pure () @@ -130,7 +130,7 @@ elab:max "T% " t:term:arg : term => do throwError "Term {tgt} has loose bound variables¬ Hint: applying the 'T%' elaborator twice makes no sense." let trivBundle ← mkAppOptM ``Bundle.Trivial #[src, tgt] - return ← withLocalDecl x BinderInfo.default src fun x ↦ do + return ← withLocalDeclD x src fun x ↦ do let body ← mkAppOptM ``Bundle.TotalSpace.mk' #[src, trivBundle, tgt, x, e.app x] mkLambdaFVars #[x] body | _ => pure () From c5c51c5a1247611e6ba753b4bf03b2ebd6d2b853 Mon Sep 17 00:00:00 2001 From: thorimur <68410468+thorimur@users.noreply.github.com> Date: Thu, 2 Oct 2025 12:49:06 -0400 Subject: [PATCH 062/106] chore: append `Elab` namespace --- Mathlib/Geometry/Manifold/Elaborators.lean | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Mathlib/Geometry/Manifold/Elaborators.lean b/Mathlib/Geometry/Manifold/Elaborators.lean index 36370bdd053027..c8780ff4c95105 100644 --- a/Mathlib/Geometry/Manifold/Elaborators.lean +++ b/Mathlib/Geometry/Manifold/Elaborators.lean @@ -82,7 +82,7 @@ open Qq @[match_pattern] def mkApp12 (f a b c d e g e₁ e₂ e₃ e₄ e₅ e₆ : Expr) := mkApp6 (mkApp6 f a b c d e g) e₁ e₂ e₃ e₄ e₅ e₆ -namespace Manifold +namespace Manifold.Elab /-- Elaborator for sections in a fibre bundle: converts a section as a dependent function to a non-dependent function into the total space. This handles the cases of @@ -403,7 +403,7 @@ elab:max "mfderiv%" ppSpace t:term:arg : term => do | some (srcI, tgtI) => return ← mkAppM ``mfderiv #[srcI, tgtI, e] | none => throwError "Term {e} is not a function." -end Manifold +end Manifold.Elab section trace From 3b34391ae4d2059dd52ade7d959bc4e1c19e66a1 Mon Sep 17 00:00:00 2001 From: thorimur <68410468+thorimur@users.noreply.github.com> Date: Thu, 2 Oct 2025 12:55:22 -0400 Subject: [PATCH 063/106] style: fix `findModel` body indentation --- Mathlib/Geometry/Manifold/Elaborators.lean | 134 ++++++++++----------- 1 file changed, 67 insertions(+), 67 deletions(-) diff --git a/Mathlib/Geometry/Manifold/Elaborators.lean b/Mathlib/Geometry/Manifold/Elaborators.lean index c8780ff4c95105..6524710cacf5f3 100644 --- a/Mathlib/Geometry/Manifold/Elaborators.lean +++ b/Mathlib/Geometry/Manifold/Elaborators.lean @@ -177,78 +177,78 @@ This implementation is not maximally robust yet. -/ -- FIXME: better failure when trying to find a `NormedField` instance def findModel (e : Expr) (baseInfo : Option (Expr × Expr) := none) : TermElabM Expr := do - trace[Elab.DiffGeo.MDiff] "Searching a model for: {e}" - if let mkApp3 (.const ``Bundle.TotalSpace _) _ F V := e then - if let mkApp12 (.const ``TangentSpace _) _k _ _E _ _ _H _ I M _ _ _x := V then - trace[Elab.DiffGeo.MDiff] "This is the total space of the tangent bundle of {M}" - let srcIT : Term ← Term.exprToSyntax I - let resTerm : Term ← ``(ModelWithCorners.prod $srcIT ModelWithCorners.tangent $srcIT) - let res ← Term.elabTerm resTerm none - trace[Elab.DiffGeo.MDiff] "Found model: {res}" - return res - - trace[Elab.DiffGeo.MDiff] "This is a total space with fiber {F}" - if let some (_src, srcI) := baseInfo then - let some K ← findSomeLocalInstanceOf? ``NormedSpace fun _ type ↦ do - match_expr type with - | NormedSpace K E _ _ => - if E == F then return some K else return none - | _ => return none - | throwError "Couldn't find a `NormedSpace` structure on {F} in the local instances." - trace[Elab.DiffGeo.MDiff] "{F} is a normed field over {K}" - let kT : Term ← Term.exprToSyntax K - let srcIT : Term ← Term.exprToSyntax srcI - let FT : Term ← Term.exprToSyntax F - let iTerm : Term ← ``(ModelWithCorners.prod $srcIT 𝓘($kT, $FT)) - let I ← Term.elabTerm iTerm none - trace[Elab.DiffGeo.MDiff] "Found model: {I}" - return I - else - throwError "Having a TotalSpace as source is not yet supported" - let K? ← findSomeLocalInstanceOf? ``NormedSpace fun _ type ↦ do - match_expr type with - | NormedSpace K E _ _ => - if E == e then return some K else return none - | _ => return none - if let some K := K? then - trace[Elab.DiffGeo.MDiff] "Field is: {K}" - let eT : Term ← Term.exprToSyntax e - let eK : Term ← Term.exprToSyntax K - let iTerm : Term ← ``(𝓘($eK, $eT)) - let I ← Term.elabTerm iTerm none - trace[Elab.DiffGeo.MDiff] "Found model: {I}" - return I - -- let uK ← K.getUniverse - -- let normedFieldK ← synthInstance (.app (.const ``NontriviallyNormedField [uK]) K) - -- trace[Elab.DiffGeo.MDiff] "NontriviallyNormedField instance is: {normedFieldK}" - -- let ue ← e.getUniverse - -- let normedGroupE ← synthInstance (.app (.const ``NormedAddCommGroup [ue]) e) - -- trace[Elab.DiffGeo.MDiff] "NormedAddCommGroup instance is: {normedGroupE}" - -- return mkAppN (.const `modelWithCornersSelf [uK, ue]) - -- #[K, normedFieldK, e, normedGroupE, normedSpaceInst] - let H? ← findSomeLocalInstanceOf? ``ChartedSpace fun _ type ↦ do - match_expr type with - | ChartedSpace H _ M _ => - if M == e then return some H else return none - | _ => return none - if let some H := H? then - trace[Elab.DiffGeo.MDiff] "H is: {H}" - let some m ← findSomeLocalHyp? fun fvar type ↦ do + trace[Elab.DiffGeo.MDiff] "Searching a model for: {e}" + if let mkApp3 (.const ``Bundle.TotalSpace _) _ F V := e then + if let mkApp12 (.const ``TangentSpace _) _k _ _E _ _ _H _ I M _ _ _x := V then + trace[Elab.DiffGeo.MDiff] "This is the total space of the tangent bundle of {M}" + let srcIT : Term ← Term.exprToSyntax I + let resTerm : Term ← ``(ModelWithCorners.prod $srcIT ModelWithCorners.tangent $srcIT) + let res ← Term.elabTerm resTerm none + trace[Elab.DiffGeo.MDiff] "Found model: {res}" + return res + + trace[Elab.DiffGeo.MDiff] "This is a total space with fiber {F}" + if let some (_src, srcI) := baseInfo then + let some K ← findSomeLocalInstanceOf? ``NormedSpace fun _ type ↦ do match_expr type with - | ModelWithCorners _ _ _ _ _ H' _ => do - if H' == H then return some fvar else return none + | NormedSpace K E _ _ => + if E == F then return some K else return none | _ => return none - | pure - trace[Elab.DiffGeo.MDiff] "Found model: {m}" - return m - else - trace[Elab.DiffGeo.MDiff] "Hoping {e} is a normed field" - let eT : Term ← Term.exprToSyntax e - let iTerm : Term ← `(𝓘($eT, $eT)) + | throwError "Couldn't find a `NormedSpace` structure on {F} in the local instances." + trace[Elab.DiffGeo.MDiff] "{F} is a normed field over {K}" + let kT : Term ← Term.exprToSyntax K + let srcIT : Term ← Term.exprToSyntax srcI + let FT : Term ← Term.exprToSyntax F + let iTerm : Term ← ``(ModelWithCorners.prod $srcIT 𝓘($kT, $FT)) let I ← Term.elabTerm iTerm none trace[Elab.DiffGeo.MDiff] "Found model: {I}" return I - throwError "Couldn’t find models with corners" + else + throwError "Having a TotalSpace as source is not yet supported" + let K? ← findSomeLocalInstanceOf? ``NormedSpace fun _ type ↦ do + match_expr type with + | NormedSpace K E _ _ => + if E == e then return some K else return none + | _ => return none + if let some K := K? then + trace[Elab.DiffGeo.MDiff] "Field is: {K}" + let eT : Term ← Term.exprToSyntax e + let eK : Term ← Term.exprToSyntax K + let iTerm : Term ← ``(𝓘($eK, $eT)) + let I ← Term.elabTerm iTerm none + trace[Elab.DiffGeo.MDiff] "Found model: {I}" + return I + -- let uK ← K.getUniverse + -- let normedFieldK ← synthInstance (.app (.const ``NontriviallyNormedField [uK]) K) + -- trace[Elab.DiffGeo.MDiff] "NontriviallyNormedField instance is: {normedFieldK}" + -- let ue ← e.getUniverse + -- let normedGroupE ← synthInstance (.app (.const ``NormedAddCommGroup [ue]) e) + -- trace[Elab.DiffGeo.MDiff] "NormedAddCommGroup instance is: {normedGroupE}" + -- return mkAppN (.const `modelWithCornersSelf [uK, ue]) + -- #[K, normedFieldK, e, normedGroupE, normedSpaceInst] + let H? ← findSomeLocalInstanceOf? ``ChartedSpace fun _ type ↦ do + match_expr type with + | ChartedSpace H _ M _ => + if M == e then return some H else return none + | _ => return none + if let some H := H? then + trace[Elab.DiffGeo.MDiff] "H is: {H}" + let some m ← findSomeLocalHyp? fun fvar type ↦ do + match_expr type with + | ModelWithCorners _ _ _ _ _ H' _ => do + if H' == H then return some fvar else return none + | _ => return none + | pure + trace[Elab.DiffGeo.MDiff] "Found model: {m}" + return m + else + trace[Elab.DiffGeo.MDiff] "Hoping {e} is a normed field" + let eT : Term ← Term.exprToSyntax e + let iTerm : Term ← ``(𝓘($eT, $eT)) + let I ← Term.elabTerm iTerm none + trace[Elab.DiffGeo.MDiff] "Found model: {I}" + return I + throwError "Couldn’t find models with corners" /-- If `etype` is a non-dependent function between spaces `src` and `tgt`, try to find a model with corners on both `src` and `tgt`. If successful, return both models. From f4a788dc82876240b080bc486140dafb38c026a0 Mon Sep 17 00:00:00 2001 From: thorimur <68410468+thorimur@users.noreply.github.com> Date: Thu, 2 Oct 2025 12:56:02 -0400 Subject: [PATCH 064/106] chore: grammar --- Mathlib/Geometry/Manifold/Elaborators.lean | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mathlib/Geometry/Manifold/Elaborators.lean b/Mathlib/Geometry/Manifold/Elaborators.lean index 6524710cacf5f3..54c3eaabf47555 100644 --- a/Mathlib/Geometry/Manifold/Elaborators.lean +++ b/Mathlib/Geometry/Manifold/Elaborators.lean @@ -177,7 +177,7 @@ This implementation is not maximally robust yet. -/ -- FIXME: better failure when trying to find a `NormedField` instance def findModel (e : Expr) (baseInfo : Option (Expr × Expr) := none) : TermElabM Expr := do - trace[Elab.DiffGeo.MDiff] "Searching a model for: {e}" + trace[Elab.DiffGeo.MDiff] "Finding a model for: {e}" if let mkApp3 (.const ``Bundle.TotalSpace _) _ F V := e then if let mkApp12 (.const ``TangentSpace _) _k _ _E _ _ _H _ I M _ _ _x := V then trace[Elab.DiffGeo.MDiff] "This is the total space of the tangent bundle of {M}" From d2be1b9da63b90b2664b511c0c4b00054c1ba679 Mon Sep 17 00:00:00 2001 From: thorimur <68410468+thorimur@users.noreply.github.com> Date: Thu, 2 Oct 2025 12:57:58 -0400 Subject: [PATCH 065/106] style: code fencing instead of quotes in messages --- Mathlib/Geometry/Manifold/Elaborators.lean | 8 ++-- .../DifferentialGeometry/Elaborators.lean | 44 +++++++++---------- 2 files changed, 26 insertions(+), 26 deletions(-) diff --git a/Mathlib/Geometry/Manifold/Elaborators.lean b/Mathlib/Geometry/Manifold/Elaborators.lean index 54c3eaabf47555..7a7b5550de2a4f 100644 --- a/Mathlib/Geometry/Manifold/Elaborators.lean +++ b/Mathlib/Geometry/Manifold/Elaborators.lean @@ -128,7 +128,7 @@ elab:max "T% " t:term:arg : term => do -- xxx: is this check fine or overzealous? if Lean.Expr.hasLooseBVars tgt then throwError "Term {tgt} has loose bound variables¬ - Hint: applying the 'T%' elaborator twice makes no sense." + Hint: applying the `T%` elaborator twice makes no sense." let trivBundle ← mkAppOptM ``Bundle.Trivial #[src, tgt] return ← withLocalDeclD x src fun x ↦ do let body ← mkAppOptM ``Bundle.TotalSpace.mk' #[src, trivBundle, tgt, x, e.app x] @@ -262,11 +262,11 @@ def findModels (etype eterm : Expr) (estype : Option Expr) : let srcI ← findModel src if Lean.Expr.hasLooseBVars tgt then throwError "Term {eterm} is a dependent function, of type {etype}\n\ - Hint: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one" + Hint: you can use the `T%` elaborator to convert a dependent function to a non-dependent one" if let some es := estype then if !(← isDefEq es (← mkAppM ``Set #[src])) then throwError "The domain {src} of {eterm} is not definitionally equal to the carrier - of the type {es} of the set 's' passed in" + of the type {es} of the set `s` passed in" let tgtI ← findModel tgt (src, srcI) return some (srcI, tgtI) | _ => return none @@ -306,7 +306,7 @@ elab:max "MDiffAt2" ppSpace t:term:arg : term => do let srcI ← findModel src if Lean.Expr.occurs src tgt then throwError "Term {e} is a dependent function, of type {etype}\n\ - Hint: you can use the 'T%' elaborator to convert a dependent function \ + Hint: you can use the `T%` elaborator to convert a dependent function \ to a non-dependent one" let tgtI ← findModel tgt (src, srcI) return ← mkAppM ``MDifferentiableAt #[srcI, tgtI, e] diff --git a/MathlibTest/DifferentialGeometry/Elaborators.lean b/MathlibTest/DifferentialGeometry/Elaborators.lean index f02e2a07860cdb..b741b66bc150aa 100644 --- a/MathlibTest/DifferentialGeometry/Elaborators.lean +++ b/MathlibTest/DifferentialGeometry/Elaborators.lean @@ -322,63 +322,63 @@ section /-- error: Term X is a dependent function, of type (m : M) → TangentSpace I m -Hint: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one +Hint: you can use the `T%` elaborator to convert a dependent function to a non-dependent one -/ #guard_msgs in #check MDiff X /-- error: Term σ is a dependent function, of type (x : M) → V x -Hint: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one +Hint: you can use the `T%` elaborator to convert a dependent function to a non-dependent one -/ #guard_msgs in #check MDiff σ /-- error: Term σ' is a dependent function, of type (x : E) → Trivial E E' x -Hint: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one +Hint: you can use the `T%` elaborator to convert a dependent function to a non-dependent one -/ #guard_msgs in #check MDiff σ' /-- error: Term σ' is a dependent function, of type (x : E) → Trivial E E' x -Hint: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one +Hint: you can use the `T%` elaborator to convert a dependent function to a non-dependent one -/ #guard_msgs in #check MDiff[s] σ' /-- error: Term X is a dependent function, of type (m : M) → TangentSpace I m -Hint: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one +Hint: you can use the `T%` elaborator to convert a dependent function to a non-dependent one -/ #guard_msgs in #check MDiffAt (X) /-- error: Term σ is a dependent function, of type (x : M) → V x -Hint: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one +Hint: you can use the `T%` elaborator to convert a dependent function to a non-dependent one -/ #guard_msgs in #check MDiffAt ((σ)) /-- error: Term σ' is a dependent function, of type (x : E) → Trivial E E' x -Hint: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one +Hint: you can use the `T%` elaborator to convert a dependent function to a non-dependent one -/ #guard_msgs in #check MDiff[s] σ' /-- error: Term σ' is a dependent function, of type (x : E) → Trivial E E' x -Hint: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one +Hint: you can use the `T%` elaborator to convert a dependent function to a non-dependent one -/ #guard_msgs in #check MDiffAt σ' /-- error: Term σ' is a dependent function, of type (x : E) → Trivial E E' x -Hint: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one +Hint: you can use the `T%` elaborator to convert a dependent function to a non-dependent one -/ #guard_msgs in #check MDiffAt[s] σ' @@ -591,63 +591,63 @@ variable (X : (m : M) → TangentSpace I m) [IsManifold I 1 M] /-- error: Term X is a dependent function, of type (m : M) → TangentSpace I m -Hint: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one +Hint: you can use the `T%` elaborator to convert a dependent function to a non-dependent one -/ #guard_msgs in #check CMDiff 0 X /-- error: Term σ is a dependent function, of type (x : M) → V x -Hint: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one +Hint: you can use the `T%` elaborator to convert a dependent function to a non-dependent one -/ #guard_msgs in #check CMDiff 0 σ /-- error: Term σ' is a dependent function, of type (x : E) → Trivial E E' x -Hint: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one +Hint: you can use the `T%` elaborator to convert a dependent function to a non-dependent one -/ #guard_msgs in #check CMDiff 0 σ' /-- error: Term σ' is a dependent function, of type (x : E) → Trivial E E' x -Hint: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one +Hint: you can use the `T%` elaborator to convert a dependent function to a non-dependent one -/ #guard_msgs in #check CMDiff[s] 0 σ' /-- error: Term X is a dependent function, of type (m : M) → TangentSpace I m -Hint: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one +Hint: you can use the `T%` elaborator to convert a dependent function to a non-dependent one -/ #guard_msgs in #check CMDiffAt 0 (X) /-- error: Term σ is a dependent function, of type (x : M) → V x -Hint: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one +Hint: you can use the `T%` elaborator to convert a dependent function to a non-dependent one -/ #guard_msgs in #check CMDiffAt 0 ((σ)) /-- error: Term σ' is a dependent function, of type (x : E) → Trivial E E' x -Hint: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one +Hint: you can use the `T%` elaborator to convert a dependent function to a non-dependent one -/ #guard_msgs in #check CMDiff[s] 0 σ' /-- error: Term σ' is a dependent function, of type (x : E) → Trivial E E' x -Hint: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one +Hint: you can use the `T%` elaborator to convert a dependent function to a non-dependent one -/ #guard_msgs in #check CMDiffAt 0 σ' /-- error: Term σ' is a dependent function, of type (x : E) → Trivial E E' x -Hint: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one +Hint: you can use the `T%` elaborator to convert a dependent function to a non-dependent one -/ #guard_msgs in #check CMDiffAt[s] 0 σ' @@ -877,14 +877,14 @@ section /-- error: Term X is a dependent function, of type (m : M) → TangentSpace I m -Hint: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one +Hint: you can use the `T%` elaborator to convert a dependent function to a non-dependent one -/ #guard_msgs in #check mfderiv% X x /-- error: Term σ is a dependent function, of type (x : M) → V x -Hint: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one +Hint: you can use the `T%` elaborator to convert a dependent function to a non-dependent one -/ #guard_msgs in #check mfderiv% σ x @@ -893,14 +893,14 @@ variable {t : Set E} {p : E} /-- error: Term σ' is a dependent function, of type (x : E) → Trivial E E' x -Hint: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one +Hint: you can use the `T%` elaborator to convert a dependent function to a non-dependent one -/ #guard_msgs in #check mfderiv[t] σ' p /-- error: Term σ' is a dependent function, of type (x : E) → Trivial E E' x -Hint: you can use the 'T%' elaborator to convert a dependent function to a non-dependent one +Hint: you can use the `T%` elaborator to convert a dependent function to a non-dependent one -/ #guard_msgs in #check mfderiv[t] σ' From 98d4eaf4ea51338905635e2df3e8e14f60c9eebf Mon Sep 17 00:00:00 2001 From: thorimur <68410468+thorimur@users.noreply.github.com> Date: Thu, 2 Oct 2025 12:59:04 -0400 Subject: [PATCH 066/106] chore: typo --- Mathlib/Geometry/Manifold/Elaborators.lean | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mathlib/Geometry/Manifold/Elaborators.lean b/Mathlib/Geometry/Manifold/Elaborators.lean index 7a7b5550de2a4f..fac6ce53712dfd 100644 --- a/Mathlib/Geometry/Manifold/Elaborators.lean +++ b/Mathlib/Geometry/Manifold/Elaborators.lean @@ -127,7 +127,7 @@ elab:max "T% " t:term:arg : term => do -- Check that `x` is not a bound variable in `tgt`! -- xxx: is this check fine or overzealous? if Lean.Expr.hasLooseBVars tgt then - throwError "Term {tgt} has loose bound variables¬ + throwError "Term {tgt} has loose bound variables\n\ Hint: applying the `T%` elaborator twice makes no sense." let trivBundle ← mkAppOptM ``Bundle.Trivial #[src, tgt] return ← withLocalDeclD x src fun x ↦ do From 8c304103466472f58d3b904fb8dfa395ccc48b56 Mon Sep 17 00:00:00 2001 From: thorimur <68410468+thorimur@users.noreply.github.com> Date: Thu, 2 Oct 2025 13:36:50 -0400 Subject: [PATCH 067/106] fix: don't use `BEq` to compare expressions --- Mathlib/Geometry/Manifold/Elaborators.lean | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Mathlib/Geometry/Manifold/Elaborators.lean b/Mathlib/Geometry/Manifold/Elaborators.lean index fac6ce53712dfd..63ffd1350acdc1 100644 --- a/Mathlib/Geometry/Manifold/Elaborators.lean +++ b/Mathlib/Geometry/Manifold/Elaborators.lean @@ -192,7 +192,7 @@ def findModel (e : Expr) (baseInfo : Option (Expr × Expr) := none) : TermElabM let some K ← findSomeLocalInstanceOf? ``NormedSpace fun _ type ↦ do match_expr type with | NormedSpace K E _ _ => - if E == F then return some K else return none + if ← withReducible (pureIsDefEq E F) then return some K else return none | _ => return none | throwError "Couldn't find a `NormedSpace` structure on {F} in the local instances." trace[Elab.DiffGeo.MDiff] "{F} is a normed field over {K}" @@ -208,7 +208,7 @@ def findModel (e : Expr) (baseInfo : Option (Expr × Expr) := none) : TermElabM let K? ← findSomeLocalInstanceOf? ``NormedSpace fun _ type ↦ do match_expr type with | NormedSpace K E _ _ => - if E == e then return some K else return none + if ← withReducible (pureIsDefEq E e) then return some K else return none | _ => return none if let some K := K? then trace[Elab.DiffGeo.MDiff] "Field is: {K}" @@ -229,14 +229,14 @@ def findModel (e : Expr) (baseInfo : Option (Expr × Expr) := none) : TermElabM let H? ← findSomeLocalInstanceOf? ``ChartedSpace fun _ type ↦ do match_expr type with | ChartedSpace H _ M _ => - if M == e then return some H else return none + if ← withReducible (pureIsDefEq M e) then return some H else return none | _ => return none if let some H := H? then trace[Elab.DiffGeo.MDiff] "H is: {H}" let some m ← findSomeLocalHyp? fun fvar type ↦ do match_expr type with | ModelWithCorners _ _ _ _ _ H' _ => do - if H' == H then return some fvar else return none + if ← withReducible (pureIsDefEq H' H) then return some fvar else return none | _ => return none | pure trace[Elab.DiffGeo.MDiff] "Found model: {m}" From 0f85d742a78403c9676447789d18a0a4171dc6af Mon Sep 17 00:00:00 2001 From: thorimur <68410468+thorimur@users.noreply.github.com> Date: Thu, 2 Oct 2025 13:38:29 -0400 Subject: [PATCH 068/106] fix: do not use `arg` precedence in brackets --- Mathlib/Geometry/Manifold/Elaborators.lean | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Mathlib/Geometry/Manifold/Elaborators.lean b/Mathlib/Geometry/Manifold/Elaborators.lean index 63ffd1350acdc1..4ed639982c2113 100644 --- a/Mathlib/Geometry/Manifold/Elaborators.lean +++ b/Mathlib/Geometry/Manifold/Elaborators.lean @@ -274,7 +274,7 @@ def findModels (etype eterm : Expr) (estype : Option Expr) : /-- `MDiffAt[s] f x` elaborates to `MDifferentiableWithinAt I J f s x`, trying to determine `I` and `J` from the local context. The argument x can be omitted. -/ -elab:max "MDiffAt[" s:term:arg "]" ppSpace f:term:arg : term => do +elab:max "MDiffAt[" s:term "]" ppSpace f:term:arg : term => do let es ← Term.elabTerm s none let ef ← Term.elabTerm f none let etype ← whnfR <|← instantiateMVars <|← inferType ef @@ -315,7 +315,7 @@ elab:max "MDiffAt2" ppSpace t:term:arg : term => do /-- `MDiff[s] f` elaborates to `MDifferentiableOn I J f s`, trying to determine `I` and `J` from the local context. -/ -elab:max "MDiff[" s:term:arg "]" ppSpace t:term:arg : term => do +elab:max "MDiff[" s:term "]" ppSpace t:term:arg : term => do let es ← Term.elabTerm s none let et ← Term.elabTerm t none let estype ← whnfR <|← instantiateMVars <|← inferType es @@ -337,7 +337,7 @@ elab:max "MDiff" ppSpace t:term:arg : term => do trying to determine `I` and `J` from the local context. `n` is coerced to `WithTop ℕ∞` if necessary (so passing a `ℕ`, `∞` or `ω` are all supported). The argument `x` can be omitted. -/ -elab:max "CMDiffAt[" s:term:arg "]" ppSpace nt:term:arg ppSpace f:term:arg : term => do +elab:max "CMDiffAt[" s:term "]" ppSpace nt:term:arg ppSpace f:term:arg : term => do let es ← Term.elabTerm s none let ef ← Term.elabTerm f none let ne ← Term.elabTermEnsuringType nt q(WithTop ℕ∞) @@ -362,7 +362,7 @@ elab:max "CMDiffAt" ppSpace nt:term:arg ppSpace t:term:arg : term => do /-- `CMDiff[s] n f` elaborates to `ContMDiffOn I J n f s`, trying to determine `I` and `J` from the local context. `n` is coerced to `WithTop ℕ∞` if necessary (so passing a `ℕ`, `∞` or `ω` are all supported). -/ -elab:max "CMDiff[" s:term:arg "]" ppSpace nt:term:arg ppSpace f:term:arg : term => do +elab:max "CMDiff[" s:term "]" ppSpace nt:term:arg ppSpace f:term:arg : term => do let es ← Term.elabTerm s none let ef ← Term.elabTerm f none let ne ← Term.elabTermEnsuringType nt q(WithTop ℕ∞) @@ -385,7 +385,7 @@ elab:max "CMDiff" ppSpace nt:term:arg ppSpace f:term:arg : term => do /-- `mfderiv[u] f x` elaborates to `mfderivWithin I J f u x`, trying to determine `I` and `J` from the local context. -/ -elab:max "mfderiv[" s:term:arg "]" ppSpace t:term:arg : term => do +elab:max "mfderiv[" s:term "]" ppSpace t:term:arg : term => do let es ← Term.elabTerm s none let e ← Term.elabTerm t none let etype ← whnfR <|← instantiateMVars <|← inferType e From d61a7edc9042c4c868f4cdbf4c9236b3f599dfb6 Mon Sep 17 00:00:00 2001 From: thorimur <68410468+thorimur@users.noreply.github.com> Date: Thu, 2 Oct 2025 20:27:44 -0400 Subject: [PATCH 069/106] fix: reset `TermElabM` state in `findModel` appropriately when trying different strategies; refactor `findModel` to make this possible. * Note that the control flow changes slightly as a result of this commit. `TotalSpace`s will not cause top-level errors when both `TotalSpace` strategies fail; rather, the remaining strategies will be tried just in case. The given error message is demoted to a trace message. Better error messages for `findModel` can be provided in subsequent PRs. --- Mathlib/Geometry/Manifold/Elaborators.lean | 113 ++++++++++++++------- 1 file changed, 76 insertions(+), 37 deletions(-) diff --git a/Mathlib/Geometry/Manifold/Elaborators.lean b/Mathlib/Geometry/Manifold/Elaborators.lean index 4ed639982c2113..52a956ebacb94f 100644 --- a/Mathlib/Geometry/Manifold/Elaborators.lean +++ b/Mathlib/Geometry/Manifold/Elaborators.lean @@ -156,6 +156,37 @@ private def findSomeLocalHyp? {α} (p : Expr → Expr → MetaM (Option α)) : M let type ← whnfR <|← instantiateMVars decl.type p decl.toExpr type +/-- Try a strategy `x : TermElabM` which either successfully produces some `Expr` or fails. On +failure in `x`, exceptions are caught, traced (`trace.Elab.DiffGeo.MDiff`), and `none` is +successfully returned. + +We run `x` with `errToSorry == false` to convert elaboration errors into +exceptions, and under `withSynthesize` in order to force typeclass synthesis errors to appear and +be caught. + +Trace messages produced during the execution of `x` are wrapped in a collapsible trace node titled +with `strategyDescr` and an indicator of success. -/ +private def tryStrategy (strategyDescr : MessageData) (x : TermElabM Expr) : + TermElabM (Option Expr) := do + let s ← saveState + try + withTraceNode `Elab.DiffGeo.MDiff (fun e => pure m!"{e.emoji} {strategyDescr}") do + let e ← + try + Term.withoutErrToSorry <| Term.withSynthesize x + /- Catch the exception so that we can trace it, then throw it again to inform + `withTraceNode` of the result. -/ + catch ex => + trace[Elab.DiffGeo.MDiff] "Failed with error:\n{ex.toMessageData}" + throw ex + trace[Elab.DiffGeo.MDiff] "Found model: {e}" + return e + catch _ => + -- Restore infotrees to prevent any stale hovers, code actions, etc. + -- Note that this does not break tracing, which saves each trace message's context. + s.restore true + return none + /-- Try to find a `ModelWithCorners` instance on a type (represented by an expression `e`), using the local context to infer the expected type. This supports the following cases: - the model with corners on the total space of a vector bundle @@ -175,49 +206,61 @@ corners. This implementation is not maximally robust yet. -/ --- FIXME: better failure when trying to find a `NormedField` instance +-- TODO: better error messages when all strategies fail def findModel (e : Expr) (baseInfo : Option (Expr × Expr) := none) : TermElabM Expr := do trace[Elab.DiffGeo.MDiff] "Finding a model for: {e}" - if let mkApp3 (.const ``Bundle.TotalSpace _) _ F V := e then + if let some m ← tryStrategy m!"TotalSpace" fromTotalSpace then return m + if let some m ← tryStrategy m!"NormedSpace" fromNormedSpace then return m + if let some m ← tryStrategy m!"ChartedSpace" fromChartedSpace then return m + if let some m ← tryStrategy m!"NormedField" fromNormedField then return m + throwError "Could not find models with corners for {e}" +where + /- Note that errors thrown in the following are caught by `tryStrategy` and converted to trace + messages. -/ + fromTotalSpace : TermElabM Expr := do + if let mkApp3 (.const ``Bundle.TotalSpace _) _ F V := e then + if let some m ← tryStrategy m!"TangentSpace" (fromTotalSpace.tangentSpace V) then return m + if let some m ← tryStrategy m!"From base info" (fromTotalSpace.fromBaseInfo F) then return m + throwError "Having a TotalSpace as source is not yet supported" + else + throwError "{e} is not a `Bundle.TotalSpace`." + fromTotalSpace.tangentSpace (V : Expr) : TermElabM Expr := do if let mkApp12 (.const ``TangentSpace _) _k _ _E _ _ _H _ I M _ _ _x := V then trace[Elab.DiffGeo.MDiff] "This is the total space of the tangent bundle of {M}" let srcIT : Term ← Term.exprToSyntax I let resTerm : Term ← ``(ModelWithCorners.prod $srcIT ModelWithCorners.tangent $srcIT) - let res ← Term.elabTerm resTerm none - trace[Elab.DiffGeo.MDiff] "Found model: {res}" - return res - - trace[Elab.DiffGeo.MDiff] "This is a total space with fiber {F}" - if let some (_src, srcI) := baseInfo then + Term.elabTerm resTerm none + else + throwError "{V} is not a `TangentSpace`" + fromTotalSpace.fromBaseInfo (F : Expr) : TermElabM Expr := do + if let some (src, srcI) := baseInfo then + trace[Elab.DiffGeo.MDiff] "Using base info {src}, {srcI}" let some K ← findSomeLocalInstanceOf? ``NormedSpace fun _ type ↦ do match_expr type with | NormedSpace K E _ _ => if ← withReducible (pureIsDefEq E F) then return some K else return none | _ => return none - | throwError "Couldn't find a `NormedSpace` structure on {F} in the local instances." + | throwError "Couldn't find a `NormedSpace` structure on {F} among local instances." trace[Elab.DiffGeo.MDiff] "{F} is a normed field over {K}" let kT : Term ← Term.exprToSyntax K let srcIT : Term ← Term.exprToSyntax srcI let FT : Term ← Term.exprToSyntax F let iTerm : Term ← ``(ModelWithCorners.prod $srcIT 𝓘($kT, $FT)) - let I ← Term.elabTerm iTerm none - trace[Elab.DiffGeo.MDiff] "Found model: {I}" - return I + Term.elabTerm iTerm none else - throwError "Having a TotalSpace as source is not yet supported" - let K? ← findSomeLocalInstanceOf? ``NormedSpace fun _ type ↦ do - match_expr type with - | NormedSpace K E _ _ => - if ← withReducible (pureIsDefEq E e) then return some K else return none - | _ => return none - if let some K := K? then + throwError "No `baseInfo` provided" + fromNormedSpace : TermElabM Expr := do + let some K ← findSomeLocalInstanceOf? ``NormedSpace fun _ type ↦ do + match_expr type with + | NormedSpace K E _ _ => + if ← withReducible (pureIsDefEq E e) then return some K else return none + | _ => return none + | throwError "Couldn't find a `NormedSpace` structure on {e} among local instances." trace[Elab.DiffGeo.MDiff] "Field is: {K}" let eT : Term ← Term.exprToSyntax e let eK : Term ← Term.exprToSyntax K let iTerm : Term ← ``(𝓘($eK, $eT)) - let I ← Term.elabTerm iTerm none - trace[Elab.DiffGeo.MDiff] "Found model: {I}" - return I + Term.elabTerm iTerm none -- let uK ← K.getUniverse -- let normedFieldK ← synthInstance (.app (.const ``NontriviallyNormedField [uK]) K) -- trace[Elab.DiffGeo.MDiff] "NontriviallyNormedField instance is: {normedFieldK}" @@ -226,29 +269,25 @@ def findModel (e : Expr) (baseInfo : Option (Expr × Expr) := none) : TermElabM -- trace[Elab.DiffGeo.MDiff] "NormedAddCommGroup instance is: {normedGroupE}" -- return mkAppN (.const `modelWithCornersSelf [uK, ue]) -- #[K, normedFieldK, e, normedGroupE, normedSpaceInst] - let H? ← findSomeLocalInstanceOf? ``ChartedSpace fun _ type ↦ do - match_expr type with - | ChartedSpace H _ M _ => - if ← withReducible (pureIsDefEq M e) then return some H else return none - | _ => return none - if let some H := H? then + fromChartedSpace : TermElabM Expr := do + let some H ← findSomeLocalInstanceOf? ``ChartedSpace fun _ type ↦ do + match_expr type with + | ChartedSpace H _ M _ => + if ← withReducible (pureIsDefEq M e) then return some H else return none + | _ => return none + | throwError "Couldn't find a `ChartedSpace` structure on {e} among local instances." trace[Elab.DiffGeo.MDiff] "H is: {H}" let some m ← findSomeLocalHyp? fun fvar type ↦ do match_expr type with | ModelWithCorners _ _ _ _ _ H' _ => do if ← withReducible (pureIsDefEq H' H) then return some fvar else return none | _ => return none - | pure - trace[Elab.DiffGeo.MDiff] "Found model: {m}" - return m - else - trace[Elab.DiffGeo.MDiff] "Hoping {e} is a normed field" + | throwError "Couldn't find a `ModelWithCorners` with model space {H} in the local context." + return m + fromNormedField : TermElabM Expr := do let eT : Term ← Term.exprToSyntax e let iTerm : Term ← ``(𝓘($eT, $eT)) - let I ← Term.elabTerm iTerm none - trace[Elab.DiffGeo.MDiff] "Found model: {I}" - return I - throwError "Couldn’t find models with corners" + Term.elabTerm iTerm none /-- If `etype` is a non-dependent function between spaces `src` and `tgt`, try to find a model with corners on both `src` and `tgt`. If successful, return both models. From 9148311d50be7b0050e4793e560bf036eab37d04 Mon Sep 17 00:00:00 2001 From: thorimur <68410468+thorimur@users.noreply.github.com> Date: Thu, 2 Oct 2025 20:34:02 -0400 Subject: [PATCH 070/106] chore: use `match_expr` in `findModel` --- Mathlib/Geometry/Manifold/Elaborators.lean | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Mathlib/Geometry/Manifold/Elaborators.lean b/Mathlib/Geometry/Manifold/Elaborators.lean index 52a956ebacb94f..b5ef0dcb18255f 100644 --- a/Mathlib/Geometry/Manifold/Elaborators.lean +++ b/Mathlib/Geometry/Manifold/Elaborators.lean @@ -218,20 +218,20 @@ where /- Note that errors thrown in the following are caught by `tryStrategy` and converted to trace messages. -/ fromTotalSpace : TermElabM Expr := do - if let mkApp3 (.const ``Bundle.TotalSpace _) _ F V := e then + match_expr e with + | Bundle.TotalSpace _ F V => do if let some m ← tryStrategy m!"TangentSpace" (fromTotalSpace.tangentSpace V) then return m if let some m ← tryStrategy m!"From base info" (fromTotalSpace.fromBaseInfo F) then return m throwError "Having a TotalSpace as source is not yet supported" - else - throwError "{e} is not a `Bundle.TotalSpace`." + | _ => throwError "{e} is not a `Bundle.TotalSpace`." fromTotalSpace.tangentSpace (V : Expr) : TermElabM Expr := do - if let mkApp12 (.const ``TangentSpace _) _k _ _E _ _ _H _ I M _ _ _x := V then + match_expr V with + | TangentSpace _k _ _E _ _ _H _ I M _ _ _x => do trace[Elab.DiffGeo.MDiff] "This is the total space of the tangent bundle of {M}" let srcIT : Term ← Term.exprToSyntax I let resTerm : Term ← ``(ModelWithCorners.prod $srcIT ModelWithCorners.tangent $srcIT) Term.elabTerm resTerm none - else - throwError "{V} is not a `TangentSpace`" + | _ => throwError "{V} is not a `TangentSpace`" fromTotalSpace.fromBaseInfo (F : Expr) : TermElabM Expr := do if let some (src, srcI) := baseInfo then trace[Elab.DiffGeo.MDiff] "Using base info {src}, {srcI}" From 542daa261af94d54998a869e39e2e2fa15175cda Mon Sep 17 00:00:00 2001 From: thorimur <68410468+thorimur@users.noreply.github.com> Date: Thu, 2 Oct 2025 20:52:23 -0400 Subject: [PATCH 071/106] chore: use `match_expr` in `T%` --- Mathlib/Geometry/Manifold/Elaborators.lean | 67 +++++++++++----------- 1 file changed, 35 insertions(+), 32 deletions(-) diff --git a/Mathlib/Geometry/Manifold/Elaborators.lean b/Mathlib/Geometry/Manifold/Elaborators.lean index b5ef0dcb18255f..641bf6db2c3145 100644 --- a/Mathlib/Geometry/Manifold/Elaborators.lean +++ b/Mathlib/Geometry/Manifold/Elaborators.lean @@ -99,40 +99,43 @@ elab:max "T% " t:term:arg : term => do let e ← Term.elabTerm t none let etype ← whnf <|← instantiateMVars <|← inferType e match etype with - | .forallE x base (mkApp3 (.const ``Bundle.Trivial _) E E' _) _ => - trace[Elab.DiffGeo.TotalSpaceMk] "Section of a trivial bundle" - if ← withReducible (isDefEq E base) then + | .forallE x base tgt _ => + match_expr tgt with + | Bundle.Trivial E E' _ => + trace[Elab.DiffGeo.TotalSpaceMk] "Section of a trivial bundle" + if ← withReducible (isDefEq E base) then + return ← withLocalDeclD x base fun x ↦ do + let body ← mkAppM ``Bundle.TotalSpace.mk' #[E', x, .app e x] + mkLambdaFVars #[x] body + | TangentSpace _k _ E _ _ _H _ _I _M _ _ _x => + trace[Elab.DiffGeo.TotalSpaceMk] "Vector field" return ← withLocalDeclD x base fun x ↦ do - let body ← mkAppM ``Bundle.TotalSpace.mk' #[E', x, .app e x] + let body ← mkAppM ``Bundle.TotalSpace.mk' #[E, x, .app e x] mkLambdaFVars #[x] body - | .forallE x base (mkApp12 (.const ``TangentSpace _) _k _ E _ _ _H _ _I _M _ _ _x) _ => - trace[Elab.DiffGeo.TotalSpaceMk] "Vector field" - return ← withLocalDeclD x base fun x ↦ do - let body ← mkAppM ``Bundle.TotalSpace.mk' #[E, x, .app e x] - mkLambdaFVars #[x] body - | .forallE x base (.app V _) _ => - trace[Elab.DiffGeo.TotalSpaceMk] "Section of a bundle as a dependent function" - for decl in ← getLocalHyps do - let decltype ← whnfR <|← instantiateMVars <|← inferType decl - match decltype with - | mkApp7 (.const `FiberBundle _) _ F _ _ E _ _ => - if ← withReducible (isDefEq E V) then - return ← withLocalDeclD x base fun x ↦ do - let body ← mkAppM ``Bundle.TotalSpace.mk' #[F, x, .app e x] - mkLambdaFVars #[x] body - | _ => pure () - | .forallE x src tgt _ => - trace[Elab.DiffGeo.TotalSpaceMk] "Section of a trivial bundle as a non-dependent function" - -- TODO: can `tgt` depend on `x` in a way that is not a function application? - -- Check that `x` is not a bound variable in `tgt`! - -- xxx: is this check fine or overzealous? - if Lean.Expr.hasLooseBVars tgt then - throwError "Term {tgt} has loose bound variables\n\ - Hint: applying the `T%` elaborator twice makes no sense." - let trivBundle ← mkAppOptM ``Bundle.Trivial #[src, tgt] - return ← withLocalDeclD x src fun x ↦ do - let body ← mkAppOptM ``Bundle.TotalSpace.mk' #[src, trivBundle, tgt, x, e.app x] - mkLambdaFVars #[x] body + | _ => match tgt with + | .app V _ => + trace[Elab.DiffGeo.TotalSpaceMk] "Section of a bundle as a dependent function" + for decl in ← getLocalHyps do + let decltype ← instantiateMVars <|← inferType decl + match decltype with + | mkApp7 (.const `FiberBundle _) _ F _ _ E _ _ => + if ← withReducible (isDefEq E V) then + return ← withLocalDeclD x base fun x ↦ do + let body ← mkAppM ``Bundle.TotalSpace.mk' #[F, x, .app e x] + mkLambdaFVars #[x] body + | _ => pure () + | tgt => + trace[Elab.DiffGeo.TotalSpaceMk] "Section of a trivial bundle as a non-dependent function" + -- TODO: can `tgt` depend on `x` in a way that is not a function application? + -- Check that `x` is not a bound variable in `tgt`! + -- xxx: is this check fine or overzealous? + if Lean.Expr.hasLooseBVars tgt then + throwError "Term {tgt} has loose bound variables\n\ + Hint: applying the `T%` elaborator twice makes no sense." + let trivBundle ← mkAppOptM ``Bundle.Trivial #[base, tgt] + return ← withLocalDeclD x base fun x ↦ do + let body ← mkAppOptM ``Bundle.TotalSpace.mk' #[base, trivBundle, tgt, x, e.app x] + mkLambdaFVars #[x] body | _ => pure () return e From 7208266d039baced597892a150357722121118f5 Mon Sep 17 00:00:00 2001 From: thorimur <68410468+thorimur@users.noreply.github.com> Date: Thu, 2 Oct 2025 23:58:16 -0400 Subject: [PATCH 072/106] chore: remove `mkApp12` --- Mathlib/Geometry/Manifold/Elaborators.lean | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Mathlib/Geometry/Manifold/Elaborators.lean b/Mathlib/Geometry/Manifold/Elaborators.lean index 641bf6db2c3145..fcf4ea08a76a35 100644 --- a/Mathlib/Geometry/Manifold/Elaborators.lean +++ b/Mathlib/Geometry/Manifold/Elaborators.lean @@ -78,10 +78,6 @@ open Lean Meta Elab Tactic open Mathlib.Tactic open Qq -/-- Call `mkApp` recursively with 12 arguments -/ -@[match_pattern] def mkApp12 (f a b c d e g e₁ e₂ e₃ e₄ e₅ e₆ : Expr) := - mkApp6 (mkApp6 f a b c d e g) e₁ e₂ e₃ e₄ e₅ e₆ - namespace Manifold.Elab /-- Elaborator for sections in a fibre bundle: converts a section as a dependent function From 95c9baf727c91213fa0926c44facff6bf75f1a7a Mon Sep 17 00:00:00 2001 From: thorimur <68410468+thorimur@users.noreply.github.com> Date: Thu, 2 Oct 2025 21:02:56 -0400 Subject: [PATCH 073/106] style: use dot notation for `hasLooseBVars` --- Mathlib/Geometry/Manifold/Elaborators.lean | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Mathlib/Geometry/Manifold/Elaborators.lean b/Mathlib/Geometry/Manifold/Elaborators.lean index fcf4ea08a76a35..ea9138a925b893 100644 --- a/Mathlib/Geometry/Manifold/Elaborators.lean +++ b/Mathlib/Geometry/Manifold/Elaborators.lean @@ -125,7 +125,7 @@ elab:max "T% " t:term:arg : term => do -- TODO: can `tgt` depend on `x` in a way that is not a function application? -- Check that `x` is not a bound variable in `tgt`! -- xxx: is this check fine or overzealous? - if Lean.Expr.hasLooseBVars tgt then + if tgt.hasLooseBVars then throwError "Term {tgt} has loose bound variables\n\ Hint: applying the `T%` elaborator twice makes no sense." let trivBundle ← mkAppOptM ``Bundle.Trivial #[base, tgt] @@ -298,7 +298,7 @@ def findModels (etype eterm : Expr) (estype : Option Expr) : match etype with | .forallE _ src tgt _ => let srcI ← findModel src - if Lean.Expr.hasLooseBVars tgt then + if tgt.hasLooseBVars then throwError "Term {eterm} is a dependent function, of type {etype}\n\ Hint: you can use the `T%` elaborator to convert a dependent function to a non-dependent one" if let some es := estype then From eca902df4ad996eb6ee997aeb71dc35d424a53c9 Mon Sep 17 00:00:00 2001 From: thorimur <68410468+thorimur@users.noreply.github.com> Date: Thu, 2 Oct 2025 21:29:36 -0400 Subject: [PATCH 074/106] chore: move `findSomeLocalInstanceOf?` above `T%` --- Mathlib/Geometry/Manifold/Elaborators.lean | 40 +++++++++++----------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/Mathlib/Geometry/Manifold/Elaborators.lean b/Mathlib/Geometry/Manifold/Elaborators.lean index ea9138a925b893..b7d9b6da434a7a 100644 --- a/Mathlib/Geometry/Manifold/Elaborators.lean +++ b/Mathlib/Geometry/Manifold/Elaborators.lean @@ -80,6 +80,26 @@ open Qq namespace Manifold.Elab +/-- Finds the first local instance of class `c` for which `p inst type` produces `some a`. +Instantiates mvars in and runs `whnfR` on `type` before passing it to `p`. (Does not validate that +`c` resolves to a class.) -/ +private def findSomeLocalInstanceOf? (c : Name) {α} (p : Expr → Expr → MetaM (Option α)) : + MetaM (Option α) := do + (← getLocalInstances).findSomeM? fun inst ↦ do + if inst.className == c then + let type ← whnfR <|← instantiateMVars <|← inferType inst.fvar + p inst.fvar type + else return none + +/-- Finds the most recent local declaration for which `p fvar type` produces `some a`. +Skips implementation details; instantiates mvars in and runs `whnfR` on `type` before providing it +to `p`. -/ +private def findSomeLocalHyp? {α} (p : Expr → Expr → MetaM (Option α)) : MetaM (Option α) := do + (← getLCtx).findDeclRevM? fun decl ↦ do + if decl.isImplementationDetail then return none + let type ← whnfR <|← instantiateMVars decl.type + p decl.toExpr type + /-- Elaborator for sections in a fibre bundle: converts a section as a dependent function to a non-dependent function into the total space. This handles the cases of - sections of a trivial bundle @@ -135,26 +155,6 @@ elab:max "T% " t:term:arg : term => do | _ => pure () return e -/-- Finds the first local instance of class `c` for which `p inst type` produces `some a`. -Instantiates mvars in and runs `whnfR` on `type` before passing it to `p`. (Does not validate that -`c` resolves to a class.) -/ -private def findSomeLocalInstanceOf? (c : Name) {α} (p : Expr → Expr → MetaM (Option α)) : - MetaM (Option α) := do - (← getLocalInstances).findSomeM? fun inst ↦ do - if inst.className == c then - let type ← whnfR <|← instantiateMVars <|← inferType inst.fvar - p inst.fvar type - else return none - -/-- Finds the most recent local declaration for which `p fvar type` produces `some a`. -Skips implementation details; instantiates mvars in and runs `whnfR` on `type` before providing it -to `p`. -/ -private def findSomeLocalHyp? {α} (p : Expr → Expr → MetaM (Option α)) : MetaM (Option α) := do - (← getLCtx).findDeclRevM? fun decl ↦ do - if decl.isImplementationDetail then return none - let type ← whnfR <|← instantiateMVars decl.type - p decl.toExpr type - /-- Try a strategy `x : TermElabM` which either successfully produces some `Expr` or fails. On failure in `x`, exceptions are caught, traced (`trace.Elab.DiffGeo.MDiff`), and `none` is successfully returned. From 1ed3ba285f61b3a6d4a63356777e9ca9f4df58fd Mon Sep 17 00:00:00 2001 From: thorimur <68410468+thorimur@users.noreply.github.com> Date: Sat, 4 Oct 2025 17:29:29 -0400 Subject: [PATCH 075/106] chore: comment for `findSomeLocalInstanceOf?` --- Mathlib/Geometry/Manifold/Elaborators.lean | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Mathlib/Geometry/Manifold/Elaborators.lean b/Mathlib/Geometry/Manifold/Elaborators.lean index b7d9b6da434a7a..7a4b9de601f124 100644 --- a/Mathlib/Geometry/Manifold/Elaborators.lean +++ b/Mathlib/Geometry/Manifold/Elaborators.lean @@ -80,6 +80,9 @@ open Qq namespace Manifold.Elab +/- Note: these functions are convenient in this file, and may be convenient elsewhere, but their +precise behavior should be considered before adding them to the meta API. -/ + /-- Finds the first local instance of class `c` for which `p inst type` produces `some a`. Instantiates mvars in and runs `whnfR` on `type` before passing it to `p`. (Does not validate that `c` resolves to a class.) -/ From e6af20cd483c113afbfc375d4e9d5da2f0ffc88b Mon Sep 17 00:00:00 2001 From: thorimur <68410468+thorimur@users.noreply.github.com> Date: Thu, 2 Oct 2025 21:16:08 -0400 Subject: [PATCH 076/106] chore: use `findSomeLocalInstanceOf?` in `T%`, and explain why we don't use `match_expr` --- Mathlib/Geometry/Manifold/Elaborators.lean | 50 +++++++++++----------- 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/Mathlib/Geometry/Manifold/Elaborators.lean b/Mathlib/Geometry/Manifold/Elaborators.lean index 7a4b9de601f124..3e3430552e6030 100644 --- a/Mathlib/Geometry/Manifold/Elaborators.lean +++ b/Mathlib/Geometry/Manifold/Elaborators.lean @@ -118,45 +118,47 @@ elab:max "T% " t:term:arg : term => do let e ← Term.elabTerm t none let etype ← whnf <|← instantiateMVars <|← inferType e match etype with - | .forallE x base tgt _ => + | .forallE x base tgt _ => withLocalDeclD x base fun x ↦ do + let tgtHasLooseBVars := tgt.hasLooseBVars + let tgt := tgt.instantiate1 x + -- Note: we do not run `whnfR` on `tgt` because `Bundle.Trivial` is reducible. match_expr tgt with | Bundle.Trivial E E' _ => trace[Elab.DiffGeo.TotalSpaceMk] "Section of a trivial bundle" if ← withReducible (isDefEq E base) then - return ← withLocalDeclD x base fun x ↦ do - let body ← mkAppM ``Bundle.TotalSpace.mk' #[E', x, .app e x] - mkLambdaFVars #[x] body + let body ← mkAppM ``Bundle.TotalSpace.mk' #[E', x, .app e x] + mkLambdaFVars #[x] body + else return e | TangentSpace _k _ E _ _ _H _ _I _M _ _ _x => trace[Elab.DiffGeo.TotalSpaceMk] "Vector field" - return ← withLocalDeclD x base fun x ↦ do - let body ← mkAppM ``Bundle.TotalSpace.mk' #[E, x, .app e x] - mkLambdaFVars #[x] body - | _ => match tgt with + let body ← mkAppM ``Bundle.TotalSpace.mk' #[E, x, .app e x] + mkLambdaFVars #[x] body + | _ => match (← instantiateMVars tgt).cleanupAnnotations with | .app V _ => trace[Elab.DiffGeo.TotalSpaceMk] "Section of a bundle as a dependent function" - for decl in ← getLocalHyps do - let decltype ← instantiateMVars <|← inferType decl - match decltype with - | mkApp7 (.const `FiberBundle _) _ F _ _ E _ _ => - if ← withReducible (isDefEq E V) then - return ← withLocalDeclD x base fun x ↦ do - let body ← mkAppM ``Bundle.TotalSpace.mk' #[F, x, .app e x] - mkLambdaFVars #[x] body - | _ => pure () + let f? ← findSomeLocalInstanceOf? `FiberBundle fun _ declType ↦ + /- Note: we do not use `match_expr` here since that would require importing + `Mathlib.Topology.FiberBundle.Basic` to resolve `FiberBundle`. -/ + match declType with + | mkApp7 (.const `FiberBundle _) _ F _ _ E _ _ => do + if ← withReducible (pureIsDefEq E V) then + let body ← mkAppM ``Bundle.TotalSpace.mk' #[F, x, .app e x] + some <$> mkLambdaFVars #[x] body + else return none + | _ => return none + return f?.getD e | tgt => trace[Elab.DiffGeo.TotalSpaceMk] "Section of a trivial bundle as a non-dependent function" -- TODO: can `tgt` depend on `x` in a way that is not a function application? -- Check that `x` is not a bound variable in `tgt`! -- xxx: is this check fine or overzealous? - if tgt.hasLooseBVars then - throwError "Term {tgt} has loose bound variables\n\ + if tgtHasLooseBVars then + throwError "Term {tgt} depends on {x}\n\ Hint: applying the `T%` elaborator twice makes no sense." let trivBundle ← mkAppOptM ``Bundle.Trivial #[base, tgt] - return ← withLocalDeclD x base fun x ↦ do - let body ← mkAppOptM ``Bundle.TotalSpace.mk' #[base, trivBundle, tgt, x, e.app x] - mkLambdaFVars #[x] body - | _ => pure () - return e + let body ← mkAppOptM ``Bundle.TotalSpace.mk' #[base, trivBundle, tgt, x, e.app x] + mkLambdaFVars #[x] body + | _ => return e /-- Try a strategy `x : TermElabM` which either successfully produces some `Expr` or fails. On failure in `x`, exceptions are caught, traced (`trace.Elab.DiffGeo.MDiff`), and `none` is From 915bb3204dccee339cb93d966c617052d4497637 Mon Sep 17 00:00:00 2001 From: thorimur <68410468+thorimur@users.noreply.github.com> Date: Thu, 2 Oct 2025 21:51:03 -0400 Subject: [PATCH 077/106] chore: perform cheapest check first --- Mathlib/Geometry/Manifold/Elaborators.lean | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mathlib/Geometry/Manifold/Elaborators.lean b/Mathlib/Geometry/Manifold/Elaborators.lean index 3e3430552e6030..129f8c35980ae3 100644 --- a/Mathlib/Geometry/Manifold/Elaborators.lean +++ b/Mathlib/Geometry/Manifold/Elaborators.lean @@ -302,10 +302,10 @@ def findModels (etype eterm : Expr) (estype : Option Expr) : TermElabM (Option (Expr × Expr)) := do match etype with | .forallE _ src tgt _ => - let srcI ← findModel src if tgt.hasLooseBVars then throwError "Term {eterm} is a dependent function, of type {etype}\n\ Hint: you can use the `T%` elaborator to convert a dependent function to a non-dependent one" + let srcI ← findModel src if let some es := estype then if !(← isDefEq es (← mkAppM ``Set #[src])) then throwError "The domain {src} of {eterm} is not definitionally equal to the carrier From a96e44161bd66992f44017492cffd9ee494b3fbf Mon Sep 17 00:00:00 2001 From: thorimur <68410468+thorimur@users.noreply.github.com> Date: Thu, 2 Oct 2025 21:54:02 -0400 Subject: [PATCH 078/106] chore: use `pureIsDefEq` or explain why not --- Mathlib/Geometry/Manifold/Elaborators.lean | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Mathlib/Geometry/Manifold/Elaborators.lean b/Mathlib/Geometry/Manifold/Elaborators.lean index 129f8c35980ae3..a790bd505cc592 100644 --- a/Mathlib/Geometry/Manifold/Elaborators.lean +++ b/Mathlib/Geometry/Manifold/Elaborators.lean @@ -125,6 +125,7 @@ elab:max "T% " t:term:arg : term => do match_expr tgt with | Bundle.Trivial E E' _ => trace[Elab.DiffGeo.TotalSpaceMk] "Section of a trivial bundle" + -- Note: we allow `isDefEq` here because any mvar assignments should persist. if ← withReducible (isDefEq E base) then let body ← mkAppM ``Bundle.TotalSpace.mk' #[E', x, .app e x] mkLambdaFVars #[x] body @@ -307,7 +308,7 @@ def findModels (etype eterm : Expr) (estype : Option Expr) : Hint: you can use the `T%` elaborator to convert a dependent function to a non-dependent one" let srcI ← findModel src if let some es := estype then - if !(← isDefEq es (← mkAppM ``Set #[src])) then + if !(← pureIsDefEq es <|← mkAppM ``Set #[src]) then throwError "The domain {src} of {eterm} is not definitionally equal to the carrier of the type {es} of the set `s` passed in" let tgtI ← findModel tgt (src, srcI) From 77f10239a53891c032ad73217293d38670616af8 Mon Sep 17 00:00:00 2001 From: thorimur <68410468+thorimur@users.noreply.github.com> Date: Wed, 1 Oct 2025 22:21:35 -0400 Subject: [PATCH 079/106] chore: comment out (fixed) `MDiffAt2` and remove test --- Mathlib/Geometry/Manifold/Elaborators.lean | 37 +++++++++---------- .../DifferentialGeometry/Elaborators.lean | 14 ------- 2 files changed, 18 insertions(+), 33 deletions(-) diff --git a/Mathlib/Geometry/Manifold/Elaborators.lean b/Mathlib/Geometry/Manifold/Elaborators.lean index a790bd505cc592..5863ad066ec52b 100644 --- a/Mathlib/Geometry/Manifold/Elaborators.lean +++ b/Mathlib/Geometry/Manifold/Elaborators.lean @@ -337,25 +337,24 @@ elab:max "MDiffAt" ppSpace t:term:arg : term => do | some (srcI, tgtI) => return ← mkAppM ``MDifferentiableAt #[srcI, tgtI, e] | none => throwError "Term {e} is not a function." --- This implement is more robust (in theory), but currently fails tests. --- TODO: investigate why, fix this and replace `MDiffAt` by this one! -/-- `MDiffAt2 f x` elaborates to `MDifferentiableAt I J f x`, -trying to determine `I` and `J` from the local context. -The argument `x` can be omitted. -/ -elab:max "MDiffAt2" ppSpace t:term:arg : term => do - let e ← Term.elabTerm t none - let etype ← whnfR <|← instantiateMVars <|← inferType e - forallBoundedTelescope etype (some 1) fun src tgt ↦ do - if let some src := src[0]? then - let srcI ← findModel src - if Lean.Expr.occurs src tgt then - throwError "Term {e} is a dependent function, of type {etype}\n\ - Hint: you can use the `T%` elaborator to convert a dependent function \ - to a non-dependent one" - let tgtI ← findModel tgt (src, srcI) - return ← mkAppM ``MDifferentiableAt #[srcI, tgtI, e] - else - throwError "Term {e} is not a function." +-- An alternate implementation for `MDiffAt`. +-- /-- `MDiffAt2 f x` elaborates to `MDifferentiableAt I J f x`, +-- trying to determine `I` and `J` from the local context. +-- The argument `x` can be omitted. -/ +-- scoped elab:max "MDiffAt2" ppSpace t:term:arg : term => do +-- let e ← Term.elabTerm t none +-- let etype ← whnfR <|← instantiateMVars <|← inferType e +-- forallBoundedTelescope etype (some 1) fun src tgt ↦ do +-- if let some src := src[0]? then +-- let srcI ← findModel (← inferType src) +-- if Lean.Expr.occurs src tgt then +-- throwErrorAt t "Term {e} is a dependent function, of type {etype}\n\ +-- Hint: you can use the `T%` elaborator to convert a dependent function \ +-- to a non-dependent one" +-- let tgtI ← findModel tgt (src, srcI) +-- mkAppM ``MDifferentiableAt #[srcI, tgtI, e] +-- else +-- throwErrorAt t "Expected{indentD e}\nof type{indentD etype}\nto be a function" /-- `MDiff[s] f` elaborates to `MDifferentiableOn I J f s`, trying to determine `I` and `J` from the local context. -/ diff --git a/MathlibTest/DifferentialGeometry/Elaborators.lean b/MathlibTest/DifferentialGeometry/Elaborators.lean index b741b66bc150aa..720f7ea114b33a 100644 --- a/MathlibTest/DifferentialGeometry/Elaborators.lean +++ b/MathlibTest/DifferentialGeometry/Elaborators.lean @@ -112,20 +112,6 @@ variable {f : M → M'} {s : Set M} {m : M} #guard_msgs in #check MDiffAt f --- TODO: understand why this fails and fix it! -/-- -error: Application type mismatch: The argument - a✝ -has type - M -of sort `Type u_4` but is expected to have type - Type ?u.63952 -of sort `Type (?u.63952 + 1)` in the application - @modelWithCornersSelf a✝ --/ -#guard_msgs in -#check MDiffAt2 f - /-- info: MDifferentiableAt I I' f m : Prop -/ #guard_msgs in #check MDiffAt f m From 32bfff525d53e5679540c71fa4ebbc4de6d4dfda Mon Sep 17 00:00:00 2001 From: thorimur <68410468+thorimur@users.noreply.github.com> Date: Thu, 2 Oct 2025 22:11:00 -0400 Subject: [PATCH 080/106] chore: use commented-out code instead of syntax re-elab --- Mathlib/Geometry/Manifold/Elaborators.lean | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/Mathlib/Geometry/Manifold/Elaborators.lean b/Mathlib/Geometry/Manifold/Elaborators.lean index 5863ad066ec52b..8c134111788201 100644 --- a/Mathlib/Geometry/Manifold/Elaborators.lean +++ b/Mathlib/Geometry/Manifold/Elaborators.lean @@ -255,25 +255,14 @@ where else throwError "No `baseInfo` provided" fromNormedSpace : TermElabM Expr := do - let some K ← findSomeLocalInstanceOf? ``NormedSpace fun _ type ↦ do + let some (inst, K) ← findSomeLocalInstanceOf? ``NormedSpace fun inst type ↦ do match_expr type with | NormedSpace K E _ _ => - if ← withReducible (pureIsDefEq E e) then return some K else return none + if ← withReducible (pureIsDefEq E e) then return some (inst, K) else return none | _ => return none | throwError "Couldn't find a `NormedSpace` structure on {e} among local instances." trace[Elab.DiffGeo.MDiff] "Field is: {K}" - let eT : Term ← Term.exprToSyntax e - let eK : Term ← Term.exprToSyntax K - let iTerm : Term ← ``(𝓘($eK, $eT)) - Term.elabTerm iTerm none - -- let uK ← K.getUniverse - -- let normedFieldK ← synthInstance (.app (.const ``NontriviallyNormedField [uK]) K) - -- trace[Elab.DiffGeo.MDiff] "NontriviallyNormedField instance is: {normedFieldK}" - -- let ue ← e.getUniverse - -- let normedGroupE ← synthInstance (.app (.const ``NormedAddCommGroup [ue]) e) - -- trace[Elab.DiffGeo.MDiff] "NormedAddCommGroup instance is: {normedGroupE}" - -- return mkAppN (.const `modelWithCornersSelf [uK, ue]) - -- #[K, normedFieldK, e, normedGroupE, normedSpaceInst] + mkAppOptM ``modelWithCornersSelf #[K, none, e, none, inst] fromChartedSpace : TermElabM Expr := do let some H ← findSomeLocalInstanceOf? ``ChartedSpace fun _ type ↦ do match_expr type with From 8fc91f35b0afdce2da458f0528253ac1fd96ebdc Mon Sep 17 00:00:00 2001 From: thorimur <68410468+thorimur@users.noreply.github.com> Date: Thu, 2 Oct 2025 23:21:18 -0400 Subject: [PATCH 081/106] chore: TODO comments --- Mathlib/Geometry/Manifold/Elaborators.lean | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Mathlib/Geometry/Manifold/Elaborators.lean b/Mathlib/Geometry/Manifold/Elaborators.lean index 8c134111788201..0543d378dd32b9 100644 --- a/Mathlib/Geometry/Manifold/Elaborators.lean +++ b/Mathlib/Geometry/Manifold/Elaborators.lean @@ -114,6 +114,7 @@ This elaborator operates purely syntactically, by analysing the local contexts f hypothesis for the above cases. Therefore, it is (hopefully) fast enough to always run. -/ -- TODO: document how this elaborator works, any gotchas, etc. +-- TODO: factor out `MetaM` component for reuse elab:max "T% " t:term:arg : term => do let e ← Term.elabTerm t none let etype ← whnf <|← instantiateMVars <|← inferType e @@ -212,6 +213,7 @@ corners. This implementation is not maximally robust yet. -/ -- TODO: better error messages when all strategies fail +-- TODO: consider lowering monad to `MetaM` def findModel (e : Expr) (baseInfo : Option (Expr × Expr) := none) : TermElabM Expr := do trace[Elab.DiffGeo.MDiff] "Finding a model for: {e}" if let some m ← tryStrategy m!"TotalSpace" fromTotalSpace then return m @@ -293,6 +295,7 @@ def findModels (etype eterm : Expr) (estype : Option Expr) : match etype with | .forallE _ src tgt _ => if tgt.hasLooseBVars then + -- TODO: try `T%` here, and if it works, add an interactive suggestion to use it throwError "Term {eterm} is a dependent function, of type {etype}\n\ Hint: you can use the `T%` elaborator to convert a dependent function to a non-dependent one" let srcI ← findModel src From d2be66bb259825959b00fc1c560be1c60c6ab222 Mon Sep 17 00:00:00 2001 From: thorimur <68410468+thorimur@users.noreply.github.com> Date: Fri, 3 Oct 2025 00:31:58 -0400 Subject: [PATCH 082/106] fix: make elaborators `scoped`, as promised --- Mathlib/Geometry/Manifold/Elaborators.lean | 26 +++++++++++++--------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/Mathlib/Geometry/Manifold/Elaborators.lean b/Mathlib/Geometry/Manifold/Elaborators.lean index 0543d378dd32b9..eae2400fe76e2d 100644 --- a/Mathlib/Geometry/Manifold/Elaborators.lean +++ b/Mathlib/Geometry/Manifold/Elaborators.lean @@ -307,10 +307,14 @@ def findModels (etype eterm : Expr) (estype : Option Expr) : return some (srcI, tgtI) | _ => return none +end Elab + +open Elab + /-- `MDiffAt[s] f x` elaborates to `MDifferentiableWithinAt I J f s x`, trying to determine `I` and `J` from the local context. The argument x can be omitted. -/ -elab:max "MDiffAt[" s:term "]" ppSpace f:term:arg : term => do +scoped elab:max "MDiffAt[" s:term "]" ppSpace f:term:arg : term => do let es ← Term.elabTerm s none let ef ← Term.elabTerm f none let etype ← whnfR <|← instantiateMVars <|← inferType ef @@ -322,7 +326,7 @@ elab:max "MDiffAt[" s:term "]" ppSpace f:term:arg : term => do /-- `MDiffAt f x` elaborates to `MDifferentiableAt I J f x`, trying to determine `I` and `J` from the local context. The argument `x` can be omitted. -/ -elab:max "MDiffAt" ppSpace t:term:arg : term => do +scoped elab:max "MDiffAt" ppSpace t:term:arg : term => do let e ← Term.elabTerm t none let etype ← whnfR <|← instantiateMVars <|← inferType e match ← findModels etype e none with @@ -350,7 +354,7 @@ elab:max "MDiffAt" ppSpace t:term:arg : term => do /-- `MDiff[s] f` elaborates to `MDifferentiableOn I J f s`, trying to determine `I` and `J` from the local context. -/ -elab:max "MDiff[" s:term "]" ppSpace t:term:arg : term => do +scoped elab:max "MDiff[" s:term "]" ppSpace t:term:arg : term => do let es ← Term.elabTerm s none let et ← Term.elabTerm t none let estype ← whnfR <|← instantiateMVars <|← inferType es @@ -361,7 +365,7 @@ elab:max "MDiff[" s:term "]" ppSpace t:term:arg : term => do /-- `MDiff f` elaborates to `MDifferentiable I J f`, trying to determine `I` and `J` from the local context. -/ -elab:max "MDiff" ppSpace t:term:arg : term => do +scoped elab:max "MDiff" ppSpace t:term:arg : term => do let e ← Term.elabTerm t none let etype ← whnfR <|← instantiateMVars <|← inferType e match ← findModels etype e none with @@ -372,7 +376,7 @@ elab:max "MDiff" ppSpace t:term:arg : term => do trying to determine `I` and `J` from the local context. `n` is coerced to `WithTop ℕ∞` if necessary (so passing a `ℕ`, `∞` or `ω` are all supported). The argument `x` can be omitted. -/ -elab:max "CMDiffAt[" s:term "]" ppSpace nt:term:arg ppSpace f:term:arg : term => do +scoped elab:max "CMDiffAt[" s:term "]" ppSpace nt:term:arg ppSpace f:term:arg : term => do let es ← Term.elabTerm s none let ef ← Term.elabTerm f none let ne ← Term.elabTermEnsuringType nt q(WithTop ℕ∞) @@ -386,7 +390,7 @@ elab:max "CMDiffAt[" s:term "]" ppSpace nt:term:arg ppSpace f:term:arg : term => trying to determine `I` and `J` from the local context. `n` is coerced to `WithTop ℕ∞` if necessary (so passing a `ℕ`, `∞` or `ω` are all supported). The argument `x` can be omitted. -/ -elab:max "CMDiffAt" ppSpace nt:term:arg ppSpace t:term:arg : term => do +scoped elab:max "CMDiffAt" ppSpace nt:term:arg ppSpace t:term:arg : term => do let e ← Term.elabTerm t none let ne ← Term.elabTermEnsuringType nt q(WithTop ℕ∞) let etype ← whnfR <|← instantiateMVars <|← inferType e @@ -397,7 +401,7 @@ elab:max "CMDiffAt" ppSpace nt:term:arg ppSpace t:term:arg : term => do /-- `CMDiff[s] n f` elaborates to `ContMDiffOn I J n f s`, trying to determine `I` and `J` from the local context. `n` is coerced to `WithTop ℕ∞` if necessary (so passing a `ℕ`, `∞` or `ω` are all supported). -/ -elab:max "CMDiff[" s:term "]" ppSpace nt:term:arg ppSpace f:term:arg : term => do +scoped elab:max "CMDiff[" s:term "]" ppSpace nt:term:arg ppSpace f:term:arg : term => do let es ← Term.elabTerm s none let ef ← Term.elabTerm f none let ne ← Term.elabTermEnsuringType nt q(WithTop ℕ∞) @@ -410,7 +414,7 @@ elab:max "CMDiff[" s:term "]" ppSpace nt:term:arg ppSpace f:term:arg : term => d /-- `CMDiff n f` elaborates to `ContMDiff I J n f`, trying to determine `I` and `J` from the local context. `n` is coerced to `WithTop ℕ∞` if necessary (so passing a `ℕ`, `∞` or `ω` are all supported). -/ -elab:max "CMDiff" ppSpace nt:term:arg ppSpace f:term:arg : term => do +scoped elab:max "CMDiff" ppSpace nt:term:arg ppSpace f:term:arg : term => do let e ← Term.elabTerm f none let ne ← Term.elabTermEnsuringType nt q(WithTop ℕ∞) let etype ← whnfR <|← instantiateMVars <|← inferType e @@ -420,7 +424,7 @@ elab:max "CMDiff" ppSpace nt:term:arg ppSpace f:term:arg : term => do /-- `mfderiv[u] f x` elaborates to `mfderivWithin I J f u x`, trying to determine `I` and `J` from the local context. -/ -elab:max "mfderiv[" s:term "]" ppSpace t:term:arg : term => do +scoped elab:max "mfderiv[" s:term "]" ppSpace t:term:arg : term => do let es ← Term.elabTerm s none let e ← Term.elabTerm t none let etype ← whnfR <|← instantiateMVars <|← inferType e @@ -431,14 +435,14 @@ elab:max "mfderiv[" s:term "]" ppSpace t:term:arg : term => do /-- `mfderiv% f x` elaborates to `mfderiv I J f x`, trying to determine `I` and `J` from the local context. -/ -elab:max "mfderiv%" ppSpace t:term:arg : term => do +scoped elab:max "mfderiv%" ppSpace t:term:arg : term => do let e ← Term.elabTerm t none let etype ← whnfR <|← instantiateMVars <|← inferType e match ← findModels etype e none with | some (srcI, tgtI) => return ← mkAppM ``mfderiv #[srcI, tgtI, e] | none => throwError "Term {e} is not a function." -end Manifold.Elab +end Manifold section trace From 9d4bcbe3b91e5a482971217933d3a76c6ea6b701 Mon Sep 17 00:00:00 2001 From: thorimur <68410468+thorimur@users.noreply.github.com> Date: Sat, 4 Oct 2025 16:42:55 -0400 Subject: [PATCH 083/106] docs: clean up module docstring --- Mathlib/Geometry/Manifold/Elaborators.lean | 66 +++++++++++++--------- 1 file changed, 39 insertions(+), 27 deletions(-) diff --git a/Mathlib/Geometry/Manifold/Elaborators.lean b/Mathlib/Geometry/Manifold/Elaborators.lean index eae2400fe76e2d..317baaf67e7af4 100644 --- a/Mathlib/Geometry/Manifold/Elaborators.lean +++ b/Mathlib/Geometry/Manifold/Elaborators.lean @@ -9,48 +9,61 @@ import Mathlib.Geometry.Manifold.MFDeriv.Defs /-! # Elaborators for differential geometry -This file defines custom elaborators for differential geometry, to allow for more compact notation. -There are two classes of elaborators. The first provides more compact notation for differentiability -and continuous differentiability on manifolds, including inference of the model with corners. -All these elaborators are scoped to the `Manifold` namespace. They allow writing -- `MDiff f` for `MDifferentiable I J f` -- `MDiffAt f x` for `MDifferentiableAt I J f x` -- `MDiff[u] f` for `MDifferentiableOn I J f u` -- `MDiffAt[u] f x` for `MDifferentiableWithinAt I J f u x` -- `CMDiff n f` for `ContMDiff I J n f` -- `CMDiffAt n f x` for `ContMDiffAt I J n f x` -- `CMDiff[u] n f` for `ContMDiffOn I J n f u` -- `CMDiffAt[u] n f x` for `ContMDiffWithinAt I J n f u x`, -- `mfderiv[u] f x` for `mfderivWithin I J f u x`, -- `mfderiv% f x` for `mfderiv I J f x`. +This file defines custom elaborators for differential geometry to allow for more compact notation. +We introduce a class of elaborators for handling differentiability on manifolds, and the elaborator +`T%` for converting dependent sections of fibre bundles into non-dependent functions into the total +space. + +All of these elaborators are scoped to the `Manifold` namespace. + +## Differentiability on manifolds + +We provide compact notation for differentiability and continuous differentiability on manifolds, +including inference of the model with corners. + +| Notation | Elaborates to | +|---------------------|-------------------------------------| +| `MDiff f` | `MDifferentiable I J f` | +| `MDiffAt f x` | `MDifferentiableAt I J f x` | +| `MDiff[u] f` | `MDifferentiableOn I J f u` | +| `MDiffAt[u] f x` | `MDifferentiableWithinAt I J f u x` | +| `CMDiff n f` | `ContMDiff I J n f` | +| `CMDiffAt n f x` | `ContMDiffAt I J n f x` | +| `CMDiff[u] n f` | `ContMDiffOn I J n f u` | +| `CMDiffAt[u] n f x` | `ContMDiffWithinAt I J n f u x` | +| `mfderiv[u] f x` | `mfderivWithin I J f u x` | +| `mfderiv% f x` | `mfderiv I J f x` | In each of these cases, the models with corners are inferred from the domain and codomain of `f`. -The search for models with corners uses the local context and is (almost) only syntactic, hence -hopefully fast enough to always run. +The search for models with corners uses the local context and is (almost) only based on expression +structure, hence hopefully fast enough to always run. This has no dedicated support for product manifolds (or product vector spaces) yet; adding this is left for future changes. (It would need to make a choice between e.g. the trivial model with corners on a product `E × F` and the product of the trivial models on `E` and `F`). In these settings, the elaborators should be avoided (for now). -Secondly, this file adds an elaborator to ease working with sections in a fibre bundle, -converting a section `s : Π x : M, Π V x` to a non-dependent function into the total space of the +## `T%` + +Secondly, this file adds an elaborator `T%` to ease working with sections in a fibre bundle, +which converts a section `s : Π x : M, V x` to a non-dependent function into the total space of the bundle. ```lean -- omitted: let `V` be a fibre bundle over `M` -variable {σ : Π x : M, V x} {σ' : (x : E) → Trivial E E' x} {s : E → E'} --- outputs `fun x ↦ TotalSpace.mk' F x (σ x) : M → TotalSpace F V` -#check T% σ +variable {σ : Π x : M, V x} in +#check T% σ -- `(fun x ↦ TotalSpace.mk' F x (σ x)) : M → TotalSpace F V` --- outputs `fun x ↦ TotalSpace.mk' E' x (σ' x) : E → TotalSpace E' (Trivial E E')` -- Note how the name of the bound variable `x` is preserved. -#check T% σ' +variable {σ : (x : E) → Trivial E E' x} in +#check T% σ -- `(fun x ↦ TotalSpace.mk' E' x (σ x)) : E → TotalSpace E' (Trivial E E')` --- outputs `fun a ↦ TotalSpace.mk' E' a (s a) : E → TotalSpace E' (Trivial E E')` -#check T% s +variable {s : E → E'} in +#check T% s -- `(fun a ↦ TotalSpace.mk' E' a (s a)) : E → TotalSpace E' (Trivial E E')` ``` +--- + These elaborators can be combined: `CMDiffAt[u] n (T% s) x` **Warning.** These elaborators are a proof of concept; the implementation should be considered a @@ -60,11 +73,10 @@ the following. ## TODO - extend the elaborators to guess models with corners on product manifolds (this has to make a guess, hence cannot always be correct: but it could make the guess that - is correct 90% of the time) + is correct 90% of the time). For products of vector spaces `E × F`, this could print a warning about making a choice between the model in `E × F` and the product of the models on `E` and `F`. - extend the elaborators to support `PartialHomeomorph`s and `PartialEquiv`s - - better error messages (as needed) - further testing and fixing of edge cases - add tests for all of the above From 3866f8a5f28de25a9fe40fbc17eb1cf561fc098f Mon Sep 17 00:00:00 2001 From: thorimur <68410468+thorimur@users.noreply.github.com> Date: Sat, 4 Oct 2025 16:45:30 -0400 Subject: [PATCH 084/106] docs: misc. style, typos, wording --- Mathlib/Geometry/Manifold/Elaborators.lean | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/Mathlib/Geometry/Manifold/Elaborators.lean b/Mathlib/Geometry/Manifold/Elaborators.lean index 317baaf67e7af4..6c79c14e2a186f 100644 --- a/Mathlib/Geometry/Manifold/Elaborators.lean +++ b/Mathlib/Geometry/Manifold/Elaborators.lean @@ -115,15 +115,17 @@ private def findSomeLocalHyp? {α} (p : Expr → Expr → MetaM (Option α)) : M let type ← whnfR <|← instantiateMVars decl.type p decl.toExpr type -/-- Elaborator for sections in a fibre bundle: converts a section as a dependent function -to a non-dependent function into the total space. This handles the cases of +/-- +Elaborator for sections in a fibre bundle: converts a section `s : Π x : M, V x` as a dependent +function to a non-dependent function into the total space. This handles the cases of - sections of a trivial bundle - vector fields on a manifold (i.e., sections of the tangent bundle) - sections of an explicit fibre bundle - turning a bare function `E → E'` into a section of the trivial bundle `Bundle.Trivial E E'` -This elaborator operates purely syntactically, by analysing the local contexts for suitable -hypothesis for the above cases. Therefore, it is (hopefully) fast enough to always run. +This elaborator searches the local context for suitable hypotheses for the above cases by matching +on the expression structure, avoiding `isDefEq`. Therefore, it is (hopefully) fast enough to always +run. -/ -- TODO: document how this elaborator works, any gotchas, etc. -- TODO: factor out `MetaM` component for reuse @@ -206,7 +208,7 @@ private def tryStrategy (strategyDescr : MessageData) (x : TermElabM Expr) : return none /-- Try to find a `ModelWithCorners` instance on a type (represented by an expression `e`), -using the local context to infer the expected type. This supports the following cases: +using the local context to infer the appropriate instance. This supports the following cases: - the model with corners on the total space of a vector bundle - a model with corners on a manifold - the trivial model `𝓘(𝕜, E)` on a normed space @@ -300,8 +302,8 @@ where /-- If `etype` is a non-dependent function between spaces `src` and `tgt`, try to find a model with corners on both `src` and `tgt`. If successful, return both models. -`ef` is the term having type `etype`: this is used only for better diagnostics. -If `estype` is `some`, we verify that `src` and `estype` are def-eq. -/ +`eterm` is the term having type `etype`: this is used only for better diagnostics. +If `estype` is `some`, we verify that `src` and `estype` are defeq. -/ def findModels (etype eterm : Expr) (estype : Option Expr) : TermElabM (Option (Expr × Expr)) := do match etype with @@ -325,7 +327,7 @@ open Elab /-- `MDiffAt[s] f x` elaborates to `MDifferentiableWithinAt I J f s x`, trying to determine `I` and `J` from the local context. -The argument x can be omitted. -/ +The argument `x` can be omitted. -/ scoped elab:max "MDiffAt[" s:term "]" ppSpace f:term:arg : term => do let es ← Term.elabTerm s none let ef ← Term.elabTerm f none From 3edd7797e73af4ac8da64af522fe0ea2989b4144 Mon Sep 17 00:00:00 2001 From: thorimur <68410468+thorimur@users.noreply.github.com> Date: Sat, 4 Oct 2025 17:15:06 -0400 Subject: [PATCH 085/106] style(`T%`): `e.app` --- Mathlib/Geometry/Manifold/Elaborators.lean | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Mathlib/Geometry/Manifold/Elaborators.lean b/Mathlib/Geometry/Manifold/Elaborators.lean index 6c79c14e2a186f..1c26a5737f976e 100644 --- a/Mathlib/Geometry/Manifold/Elaborators.lean +++ b/Mathlib/Geometry/Manifold/Elaborators.lean @@ -142,12 +142,12 @@ elab:max "T% " t:term:arg : term => do trace[Elab.DiffGeo.TotalSpaceMk] "Section of a trivial bundle" -- Note: we allow `isDefEq` here because any mvar assignments should persist. if ← withReducible (isDefEq E base) then - let body ← mkAppM ``Bundle.TotalSpace.mk' #[E', x, .app e x] + let body ← mkAppM ``Bundle.TotalSpace.mk' #[E', x, e.app x] mkLambdaFVars #[x] body else return e | TangentSpace _k _ E _ _ _H _ _I _M _ _ _x => trace[Elab.DiffGeo.TotalSpaceMk] "Vector field" - let body ← mkAppM ``Bundle.TotalSpace.mk' #[E, x, .app e x] + let body ← mkAppM ``Bundle.TotalSpace.mk' #[E, x, e.app x] mkLambdaFVars #[x] body | _ => match (← instantiateMVars tgt).cleanupAnnotations with | .app V _ => @@ -158,7 +158,7 @@ elab:max "T% " t:term:arg : term => do match declType with | mkApp7 (.const `FiberBundle _) _ F _ _ E _ _ => do if ← withReducible (pureIsDefEq E V) then - let body ← mkAppM ``Bundle.TotalSpace.mk' #[F, x, .app e x] + let body ← mkAppM ``Bundle.TotalSpace.mk' #[F, x, e.app x] some <$> mkLambdaFVars #[x] body else return none | _ => return none From 11b39ab8877536ec715b12c8d3efe2898d1f92a3 Mon Sep 17 00:00:00 2001 From: thorimur <68410468+thorimur@users.noreply.github.com> Date: Sat, 4 Oct 2025 17:20:52 -0400 Subject: [PATCH 086/106] style: line reflow --- Mathlib/Geometry/Manifold/Elaborators.lean | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Mathlib/Geometry/Manifold/Elaborators.lean b/Mathlib/Geometry/Manifold/Elaborators.lean index 1c26a5737f976e..737149f2c0cdf5 100644 --- a/Mathlib/Geometry/Manifold/Elaborators.lean +++ b/Mathlib/Geometry/Manifold/Elaborators.lean @@ -304,8 +304,7 @@ corners on both `src` and `tgt`. If successful, return both models. `eterm` is the term having type `etype`: this is used only for better diagnostics. If `estype` is `some`, we verify that `src` and `estype` are defeq. -/ -def findModels (etype eterm : Expr) (estype : Option Expr) : - TermElabM (Option (Expr × Expr)) := do +def findModels (etype eterm : Expr) (estype : Option Expr) : TermElabM (Option (Expr × Expr)) := do match etype with | .forallE _ src tgt _ => if tgt.hasLooseBVars then From 81cd4e004915290038c51b59ffe12c6766f48bad Mon Sep 17 00:00:00 2001 From: thorimur <68410468+thorimur@users.noreply.github.com> Date: Sat, 4 Oct 2025 17:30:06 -0400 Subject: [PATCH 087/106] fix: scope `T%` to `Manifold` --- Mathlib/Geometry/Manifold/Elaborators.lean | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Mathlib/Geometry/Manifold/Elaborators.lean b/Mathlib/Geometry/Manifold/Elaborators.lean index 737149f2c0cdf5..9430be0095b4b2 100644 --- a/Mathlib/Geometry/Manifold/Elaborators.lean +++ b/Mathlib/Geometry/Manifold/Elaborators.lean @@ -115,6 +115,9 @@ private def findSomeLocalHyp? {α} (p : Expr → Expr → MetaM (Option α)) : M let type ← whnfR <|← instantiateMVars decl.type p decl.toExpr type +end Elab + +open Elab in /-- Elaborator for sections in a fibre bundle: converts a section `s : Π x : M, V x` as a dependent function to a non-dependent function into the total space. This handles the cases of @@ -129,7 +132,7 @@ run. -/ -- TODO: document how this elaborator works, any gotchas, etc. -- TODO: factor out `MetaM` component for reuse -elab:max "T% " t:term:arg : term => do +scoped elab:max "T% " t:term:arg : term => do let e ← Term.elabTerm t none let etype ← whnf <|← instantiateMVars <|← inferType e match etype with @@ -176,6 +179,8 @@ elab:max "T% " t:term:arg : term => do mkLambdaFVars #[x] body | _ => return e +namespace Elab + /-- Try a strategy `x : TermElabM` which either successfully produces some `Expr` or fails. On failure in `x`, exceptions are caught, traced (`trace.Elab.DiffGeo.MDiff`), and `none` is successfully returned. From 6bbacad8c9d5b68ed236c246feb659aa946db8c3 Mon Sep 17 00:00:00 2001 From: thorimur <68410468+thorimur@users.noreply.github.com> Date: Thu, 2 Oct 2025 22:47:45 -0400 Subject: [PATCH 088/106] chore: refactor `findModels` to clean up elabs --- Mathlib/Geometry/Manifold/Elaborators.lean | 92 +++++++------------ .../DifferentialGeometry/Elaborators.lean | 30 +++--- 2 files changed, 47 insertions(+), 75 deletions(-) diff --git a/Mathlib/Geometry/Manifold/Elaborators.lean b/Mathlib/Geometry/Manifold/Elaborators.lean index 9430be0095b4b2..78278be3196ac8 100644 --- a/Mathlib/Geometry/Manifold/Elaborators.lean +++ b/Mathlib/Geometry/Manifold/Elaborators.lean @@ -304,26 +304,29 @@ where let iTerm : Term ← ``(𝓘($eT, $eT)) Term.elabTerm iTerm none -/-- If `etype` is a non-dependent function between spaces `src` and `tgt`, try to find a model with -corners on both `src` and `tgt`. If successful, return both models. +/-- If the type of `e` is a non-dependent function between spaces `src` and `tgt`, try to find a +model with corners on both `src` and `tgt`. If successful, return both models. -`eterm` is the term having type `etype`: this is used only for better diagnostics. -If `estype` is `some`, we verify that `src` and `estype` are defeq. -/ -def findModels (etype eterm : Expr) (estype : Option Expr) : TermElabM (Option (Expr × Expr)) := do +We pass `e` instead of just its type for better diagnostics. + +If `es` is `some`, we verify that `src` and the type of `es` are defeq. -/ +def findModels (e : Expr) (es : Option Expr) : TermElabM (Expr × Expr) := do + let etype ← whnf <|← instantiateMVars <|← inferType e match etype with | .forallE _ src tgt _ => if tgt.hasLooseBVars then -- TODO: try `T%` here, and if it works, add an interactive suggestion to use it - throwError "Term {eterm} is a dependent function, of type {etype}\n\ + throwError "Term {e} is a dependent function, of type {etype}\n\ Hint: you can use the `T%` elaborator to convert a dependent function to a non-dependent one" let srcI ← findModel src - if let some es := estype then - if !(← pureIsDefEq es <|← mkAppM ``Set #[src]) then - throwError "The domain {src} of {eterm} is not definitionally equal to the carrier - of the type {es} of the set `s` passed in" + if let some es := es then + let estype ← inferType es + if !(← pureIsDefEq estype <|← mkAppM ``Set #[src]) then + throwError "The domain {src} of {e} is not definitionally equal to the carrier type of \ + the set {es} : {estype}" let tgtI ← findModel tgt (src, srcI) - return some (srcI, tgtI) - | _ => return none + return (srcI, tgtI) + | _ => throwError "Expected{indentD e}\nof type{indentD etype}\nto be a function" end Elab @@ -335,21 +338,16 @@ The argument `x` can be omitted. -/ scoped elab:max "MDiffAt[" s:term "]" ppSpace f:term:arg : term => do let es ← Term.elabTerm s none let ef ← Term.elabTerm f none - let etype ← whnfR <|← instantiateMVars <|← inferType ef - let estype ← whnfR <|← instantiateMVars <|← inferType es - match ← findModels etype ef estype with - | some (srcI, tgtI) => return ← mkAppM ``MDifferentiableWithinAt #[srcI, tgtI, ef, es] - | none => throwError "Term {ef} is not a function." + let (srcI, tgtI) ← findModels ef es + mkAppM ``MDifferentiableWithinAt #[srcI, tgtI, ef, es] /-- `MDiffAt f x` elaborates to `MDifferentiableAt I J f x`, trying to determine `I` and `J` from the local context. The argument `x` can be omitted. -/ scoped elab:max "MDiffAt" ppSpace t:term:arg : term => do let e ← Term.elabTerm t none - let etype ← whnfR <|← instantiateMVars <|← inferType e - match ← findModels etype e none with - | some (srcI, tgtI) => return ← mkAppM ``MDifferentiableAt #[srcI, tgtI, e] - | none => throwError "Term {e} is not a function." + let (srcI, tgtI) ← findModels e none + mkAppM ``MDifferentiableAt #[srcI, tgtI, e] -- An alternate implementation for `MDiffAt`. -- /-- `MDiffAt2 f x` elaborates to `MDifferentiableAt I J f x`, @@ -375,20 +373,15 @@ trying to determine `I` and `J` from the local context. -/ scoped elab:max "MDiff[" s:term "]" ppSpace t:term:arg : term => do let es ← Term.elabTerm s none let et ← Term.elabTerm t none - let estype ← whnfR <|← instantiateMVars <|← inferType es - let etype ← whnfR <|← instantiateMVars <|← inferType et - match ← findModels etype et estype with - | some (srcI, tgtI) => return ← mkAppM ``MDifferentiableOn #[srcI, tgtI, et, es] - | none => throwError "Term {et} is not a function." + let (srcI, tgtI) ← findModels et es + mkAppM ``MDifferentiableOn #[srcI, tgtI, et, es] /-- `MDiff f` elaborates to `MDifferentiable I J f`, trying to determine `I` and `J` from the local context. -/ scoped elab:max "MDiff" ppSpace t:term:arg : term => do let e ← Term.elabTerm t none - let etype ← whnfR <|← instantiateMVars <|← inferType e - match ← findModels etype e none with - | some (srcI, tgtI) => return ← mkAppM ``MDifferentiable #[srcI, tgtI, e] - | none => throwError "Term {e} is not a function." + let (srcI, tgtI) ← findModels e none + mkAppM ``MDifferentiable #[srcI, tgtI, e] /-- `CMDiffAt[s] n f x` elaborates to `ContMDiffWithinAt I J n f s x`, trying to determine `I` and `J` from the local context. @@ -398,11 +391,8 @@ scoped elab:max "CMDiffAt[" s:term "]" ppSpace nt:term:arg ppSpace f:term:arg : let es ← Term.elabTerm s none let ef ← Term.elabTerm f none let ne ← Term.elabTermEnsuringType nt q(WithTop ℕ∞) - let estype ← whnfR <|← instantiateMVars <|← inferType es - let eftype ← whnfR <|← instantiateMVars <|← inferType ef - match ← findModels eftype ef estype with - | some (srcI, tgtI) => return ← mkAppM ``ContMDiffWithinAt #[srcI, tgtI, ne, ef, es] - | none => throwError "Term {ef} is not a function." + let (srcI, tgtI) ← findModels ef es + mkAppM ``ContMDiffWithinAt #[srcI, tgtI, ne, ef, es] /-- `CMDiffAt n f x` elaborates to `ContMDiffAt I J n f x` trying to determine `I` and `J` from the local context. @@ -411,10 +401,8 @@ The argument `x` can be omitted. -/ scoped elab:max "CMDiffAt" ppSpace nt:term:arg ppSpace t:term:arg : term => do let e ← Term.elabTerm t none let ne ← Term.elabTermEnsuringType nt q(WithTop ℕ∞) - let etype ← whnfR <|← instantiateMVars <|← inferType e - match ← findModels etype e none with - | some (srcI, tgtI) => return ← mkAppM ``ContMDiffAt #[srcI, tgtI, ne, e] - | none => throwError "Term {e} is not a function." + let (srcI, tgtI) ← findModels e none + mkAppM ``ContMDiffAt #[srcI, tgtI, ne, e] /-- `CMDiff[s] n f` elaborates to `ContMDiffOn I J n f s`, trying to determine `I` and `J` from the local context. @@ -423,11 +411,8 @@ scoped elab:max "CMDiff[" s:term "]" ppSpace nt:term:arg ppSpace f:term:arg : te let es ← Term.elabTerm s none let ef ← Term.elabTerm f none let ne ← Term.elabTermEnsuringType nt q(WithTop ℕ∞) - let estype ← whnfR <|← instantiateMVars <|← inferType es - let eftype ← whnfR <|← instantiateMVars <|← inferType ef - match ← findModels eftype ef estype with - | some (srcI, tgtI) => return ← mkAppM ``ContMDiffOn #[srcI, tgtI, ne, ef, es] - | none => throwError "Term {ef} is not a function." + let (srcI, tgtI) ← findModels ef es + mkAppM ``ContMDiffOn #[srcI, tgtI, ne, ef, es] /-- `CMDiff n f` elaborates to `ContMDiff I J n f`, trying to determine `I` and `J` from the local context. @@ -435,30 +420,23 @@ trying to determine `I` and `J` from the local context. scoped elab:max "CMDiff" ppSpace nt:term:arg ppSpace f:term:arg : term => do let e ← Term.elabTerm f none let ne ← Term.elabTermEnsuringType nt q(WithTop ℕ∞) - let etype ← whnfR <|← instantiateMVars <|← inferType e - match ← findModels etype e none with - | some (srcI, tgtI) => return ← mkAppM ``ContMDiff #[srcI, tgtI, ne, e] - | none => throwError "Term {e} is not a function." + let (srcI, tgtI) ← findModels e none + mkAppM ``ContMDiff #[srcI, tgtI, ne, e] /-- `mfderiv[u] f x` elaborates to `mfderivWithin I J f u x`, trying to determine `I` and `J` from the local context. -/ scoped elab:max "mfderiv[" s:term "]" ppSpace t:term:arg : term => do let es ← Term.elabTerm s none let e ← Term.elabTerm t none - let etype ← whnfR <|← instantiateMVars <|← inferType e - let estype ← whnfR <|← instantiateMVars <|← inferType es - match ← findModels etype e estype with - | some (srcI, tgtI) => return ← mkAppM ``mfderivWithin #[srcI, tgtI, e, es] - | none => throwError "Term {e} is not a function." + let (srcI, tgtI) ← findModels e es + mkAppM ``mfderivWithin #[srcI, tgtI, e, es] /-- `mfderiv% f x` elaborates to `mfderiv I J f x`, trying to determine `I` and `J` from the local context. -/ scoped elab:max "mfderiv%" ppSpace t:term:arg : term => do let e ← Term.elabTerm t none - let etype ← whnfR <|← instantiateMVars <|← inferType e - match ← findModels etype e none with - | some (srcI, tgtI) => return ← mkAppM ``mfderiv #[srcI, tgtI, e] - | none => throwError "Term {e} is not a function." + let (srcI, tgtI) ← findModels e none + mkAppM ``mfderiv #[srcI, tgtI, e] end Manifold diff --git a/MathlibTest/DifferentialGeometry/Elaborators.lean b/MathlibTest/DifferentialGeometry/Elaborators.lean index 720f7ea114b33a..e0a59a76dbb3e2 100644 --- a/MathlibTest/DifferentialGeometry/Elaborators.lean +++ b/MathlibTest/DifferentialGeometry/Elaborators.lean @@ -404,7 +404,11 @@ of sort `Type (max u_10 u_4)` but is expected to have type WithTop ℕ∞ of sort `Type` --- -error: Term m is not a function. +error: Expected + m +of type + M +to be a function -/ #guard_msgs in #check CMDiffAt[s] f m @@ -418,7 +422,11 @@ of sort `Type (max u_10 u_4)` but is expected to have type WithTop ℕ∞ of sort `Type` --- -error: Term m is not a function. +error: Expected + m +of type + M +to be a function -/ #guard_msgs in #check CMDiffAt[s] f m @@ -832,27 +840,13 @@ info: mfderiv 𝓘(𝕜, E) 𝓘(𝕜, EM') f sorry : TangentSpace 𝓘(𝕜, E) -- Error messages: argument s has mismatched type. /-- -error: Application type mismatch: The argument - s' -has type - Set.{u_4} M -of sort `Type u_4` but is expected to have type - Set.{u_2} E -of sort `Type u_2` in the application - mfderivWithin 𝓘(𝕜, E) 𝓘(𝕜, EM') f s' +error: The domain E of f is not definitionally equal to the carrier type of the set s' : Set M -/ #guard_msgs in #check mfderiv[s'] f /-- -error: Application type mismatch: The argument - s' -has type - Set.{u_4} M -of sort `Type u_4` but is expected to have type - Set.{u_2} E -of sort `Type u_2` in the application - mfderivWithin 𝓘(𝕜, E) 𝓘(𝕜, EM') f s' +error: The domain E of f is not definitionally equal to the carrier type of the set s' : Set M -/ #guard_msgs in #check mfderiv[s'] f m From 95f24aed78a7e17101c6d0d4f67a0f6e146ca96a Mon Sep 17 00:00:00 2001 From: thorimur <68410468+thorimur@users.noreply.github.com> Date: Sat, 4 Oct 2025 20:04:15 -0400 Subject: [PATCH 089/106] style: indent second line of multiline errors --- Mathlib/Geometry/Manifold/Elaborators.lean | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Mathlib/Geometry/Manifold/Elaborators.lean b/Mathlib/Geometry/Manifold/Elaborators.lean index 78278be3196ac8..58f2b889989e8e 100644 --- a/Mathlib/Geometry/Manifold/Elaborators.lean +++ b/Mathlib/Geometry/Manifold/Elaborators.lean @@ -173,7 +173,7 @@ scoped elab:max "T% " t:term:arg : term => do -- xxx: is this check fine or overzealous? if tgtHasLooseBVars then throwError "Term {tgt} depends on {x}\n\ - Hint: applying the `T%` elaborator twice makes no sense." + Hint: applying the `T%` elaborator twice makes no sense." let trivBundle ← mkAppOptM ``Bundle.Trivial #[base, tgt] let body ← mkAppOptM ``Bundle.TotalSpace.mk' #[base, trivBundle, tgt, x, e.app x] mkLambdaFVars #[x] body @@ -316,14 +316,14 @@ def findModels (e : Expr) (es : Option Expr) : TermElabM (Expr × Expr) := do | .forallE _ src tgt _ => if tgt.hasLooseBVars then -- TODO: try `T%` here, and if it works, add an interactive suggestion to use it - throwError "Term {e} is a dependent function, of type {etype}\n\ - Hint: you can use the `T%` elaborator to convert a dependent function to a non-dependent one" + throwError "Term {e} is a dependent function, of type {etype}\nHint: you can use the `T%` \ + elaborator to convert a dependent function to a non-dependent one" let srcI ← findModel src if let some es := es then let estype ← inferType es if !(← pureIsDefEq estype <|← mkAppM ``Set #[src]) then throwError "The domain {src} of {e} is not definitionally equal to the carrier type of \ - the set {es} : {estype}" + the set {es} : {estype}" let tgtI ← findModel tgt (src, srcI) return (srcI, tgtI) | _ => throwError "Expected{indentD e}\nof type{indentD etype}\nto be a function" From d56601d49ff816ad66ac1786973321b3903c61a9 Mon Sep 17 00:00:00 2001 From: thorimur <68410468+thorimur@users.noreply.github.com> Date: Sat, 4 Oct 2025 20:05:49 -0400 Subject: [PATCH 090/106] chore: improve error message for trivial bundle --- Mathlib/Geometry/Manifold/Elaborators.lean | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Mathlib/Geometry/Manifold/Elaborators.lean b/Mathlib/Geometry/Manifold/Elaborators.lean index 58f2b889989e8e..1ae96e78f6603a 100644 --- a/Mathlib/Geometry/Manifold/Elaborators.lean +++ b/Mathlib/Geometry/Manifold/Elaborators.lean @@ -172,8 +172,9 @@ scoped elab:max "T% " t:term:arg : term => do -- Check that `x` is not a bound variable in `tgt`! -- xxx: is this check fine or overzealous? if tgtHasLooseBVars then - throwError "Term {tgt} depends on {x}\n\ - Hint: applying the `T%` elaborator twice makes no sense." + throwError "Attempted to fall back to creating a section of the trivial bundle out of \ + ({e} : {etype}) as a non-dependent function, but return type {tgt} depends on the bound + variable ({x} : {base}).\nHint: applying the `T%` elaborator twice makes no sense." let trivBundle ← mkAppOptM ``Bundle.Trivial #[base, tgt] let body ← mkAppOptM ``Bundle.TotalSpace.mk' #[base, trivBundle, tgt, x, e.app x] mkLambdaFVars #[x] body From 1976265473576347dd8126e0b8e26f81345acb41 Mon Sep 17 00:00:00 2001 From: thorimur Date: Sun, 5 Oct 2025 22:34:51 -0400 Subject: [PATCH 091/106] test: tracing --- .../DifferentialGeometry/Elaborators.lean | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/MathlibTest/DifferentialGeometry/Elaborators.lean b/MathlibTest/DifferentialGeometry/Elaborators.lean index e0a59a76dbb3e2..3cfe0941992e69 100644 --- a/MathlibTest/DifferentialGeometry/Elaborators.lean +++ b/MathlibTest/DifferentialGeometry/Elaborators.lean @@ -888,3 +888,44 @@ Hint: you can use the `T%` elaborator to convert a dependent function to a non-d end end mfderiv + +section trace + +/- Test that basic tracing works. -/ + +set_option trace.Elab.DiffGeo true + +variable {f : Unit → Unit} + +/-- +error: Could not find models with corners for Unit +--- +trace: [Elab.DiffGeo.MDiff] Finding a model for: Unit +[Elab.DiffGeo.MDiff] ❌️ TotalSpace + [Elab.DiffGeo.MDiff] Failed with error: + Unit is not a `Bundle.TotalSpace`. +[Elab.DiffGeo.MDiff] ❌️ NormedSpace + [Elab.DiffGeo.MDiff] Failed with error: + Couldn't find a `NormedSpace` structure on Unit among local instances. +[Elab.DiffGeo.MDiff] ❌️ ChartedSpace + [Elab.DiffGeo.MDiff] Failed with error: + Couldn't find a `ChartedSpace` structure on Unit among local instances. +[Elab.DiffGeo.MDiff] ❌️ NormedField + [Elab.DiffGeo.MDiff] Failed with error: + failed to synthesize + NontriviallyNormedField Unit + ⏎ + Hint: Additional diagnostic information may be available using the `set_option diagnostics true` command. +-/ +#guard_msgs in +#check mfderiv% f + +/-- +info: fun a ↦ TotalSpace.mk' Unit a (f a) : Unit → TotalSpace Unit (Trivial Unit Unit) +--- +trace: [Elab.DiffGeo.TotalSpaceMk] Section of a trivial bundle as a non-dependent function +-/ +#guard_msgs in +#check T% f + +end trace From 0fa0ca7d0f1e5b7948c4ef2dec4ebd2ea9cce2da Mon Sep 17 00:00:00 2001 From: thorimur Date: Mon, 6 Oct 2025 00:34:09 -0400 Subject: [PATCH 092/106] chore: affirm that this check is fine! --- Mathlib/Geometry/Manifold/Elaborators.lean | 1 - 1 file changed, 1 deletion(-) diff --git a/Mathlib/Geometry/Manifold/Elaborators.lean b/Mathlib/Geometry/Manifold/Elaborators.lean index 1ae96e78f6603a..e37cf621b90d9d 100644 --- a/Mathlib/Geometry/Manifold/Elaborators.lean +++ b/Mathlib/Geometry/Manifold/Elaborators.lean @@ -170,7 +170,6 @@ scoped elab:max "T% " t:term:arg : term => do trace[Elab.DiffGeo.TotalSpaceMk] "Section of a trivial bundle as a non-dependent function" -- TODO: can `tgt` depend on `x` in a way that is not a function application? -- Check that `x` is not a bound variable in `tgt`! - -- xxx: is this check fine or overzealous? if tgtHasLooseBVars then throwError "Attempted to fall back to creating a section of the trivial bundle out of \ ({e} : {etype}) as a non-dependent function, but return type {tgt} depends on the bound From d68de786007e36c2b60bcbd142674d21de9a5061 Mon Sep 17 00:00:00 2001 From: Michael Rothgang Date: Mon, 6 Oct 2025 12:24:57 -0700 Subject: [PATCH 093/106] chore: move file to Notation.lean --- Mathlib.lean | 2 +- Mathlib/Geometry/Manifold/{Elaborators.lean => Notation.lean} | 0 MathlibTest/DifferentialGeometry/Elaborators.lean | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) rename Mathlib/Geometry/Manifold/{Elaborators.lean => Notation.lean} (100%) diff --git a/Mathlib.lean b/Mathlib.lean index 7dccd338c376ea..0eeae4be8d1618 100644 --- a/Mathlib.lean +++ b/Mathlib.lean @@ -3905,7 +3905,6 @@ import Mathlib.Geometry.Manifold.ContMDiffMFDeriv import Mathlib.Geometry.Manifold.ContMDiffMap import Mathlib.Geometry.Manifold.DerivationBundle import Mathlib.Geometry.Manifold.Diffeomorph -import Mathlib.Geometry.Manifold.Elaborators import Mathlib.Geometry.Manifold.GroupLieAlgebra import Mathlib.Geometry.Manifold.Instances.Icc import Mathlib.Geometry.Manifold.Instances.Real @@ -3929,6 +3928,7 @@ import Mathlib.Geometry.Manifold.MFDeriv.SpecificFunctions import Mathlib.Geometry.Manifold.MFDeriv.Tangent import Mathlib.Geometry.Manifold.MFDeriv.UniqueDifferential import Mathlib.Geometry.Manifold.Metrizable +import Mathlib.Geometry.Manifold.Notation import Mathlib.Geometry.Manifold.PartitionOfUnity import Mathlib.Geometry.Manifold.PoincareConjecture import Mathlib.Geometry.Manifold.Riemannian.Basic diff --git a/Mathlib/Geometry/Manifold/Elaborators.lean b/Mathlib/Geometry/Manifold/Notation.lean similarity index 100% rename from Mathlib/Geometry/Manifold/Elaborators.lean rename to Mathlib/Geometry/Manifold/Notation.lean diff --git a/MathlibTest/DifferentialGeometry/Elaborators.lean b/MathlibTest/DifferentialGeometry/Elaborators.lean index 3cfe0941992e69..d512d11a4f7e0b 100644 --- a/MathlibTest/DifferentialGeometry/Elaborators.lean +++ b/MathlibTest/DifferentialGeometry/Elaborators.lean @@ -1,4 +1,4 @@ -import Mathlib.Geometry.Manifold.Elaborators +import Mathlib.Geometry.Manifold.Notation import Mathlib.Geometry.Manifold.VectorBundle.SmoothSection import Mathlib.Geometry.Manifold.VectorBundle.Tangent import Mathlib.Geometry.Manifold.MFDeriv.FDeriv From 6ca727da04fdb23b48d7148dd5cd1ec8e5868797 Mon Sep 17 00:00:00 2001 From: Michael Rothgang Date: Mon, 6 Oct 2025 12:41:02 -0700 Subject: [PATCH 094/106] Review comments --- Mathlib/Geometry/Manifold/Notation.lean | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Mathlib/Geometry/Manifold/Notation.lean b/Mathlib/Geometry/Manifold/Notation.lean index e37cf621b90d9d..9670c438e59c3c 100644 --- a/Mathlib/Geometry/Manifold/Notation.lean +++ b/Mathlib/Geometry/Manifold/Notation.lean @@ -76,7 +76,7 @@ the following. is correct 90% of the time). For products of vector spaces `E × F`, this could print a warning about making a choice between the model in `E × F` and the product of the models on `E` and `F`. -- extend the elaborators to support `PartialHomeomorph`s and `PartialEquiv`s +- extend the elaborators to support `OpenPartialHomeomorph`s and `PartialEquiv`s - better error messages (as needed) - further testing and fixing of edge cases - add tests for all of the above @@ -309,7 +309,7 @@ model with corners on both `src` and `tgt`. If successful, return both models. We pass `e` instead of just its type for better diagnostics. -If `es` is `some`, we verify that `src` and the type of `es` are defeq. -/ +If `es` is `some`, we verify that `src` and the type of `es` are definitionally equal. -/ def findModels (e : Expr) (es : Option Expr) : TermElabM (Expr × Expr) := do let etype ← whnf <|← instantiateMVars <|← inferType e match etype with From 7bc54f03011985ab6297824a86710c09191bd05a Mon Sep 17 00:00:00 2001 From: Michael Rothgang Date: Mon, 6 Oct 2025 12:43:36 -0700 Subject: [PATCH 095/106] chore: add missing test; fails for reasons I don't understand --- .../DifferentialGeometry/Elaborators.lean | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/MathlibTest/DifferentialGeometry/Elaborators.lean b/MathlibTest/DifferentialGeometry/Elaborators.lean index d512d11a4f7e0b..777ccc2c395a74 100644 --- a/MathlibTest/DifferentialGeometry/Elaborators.lean +++ b/MathlibTest/DifferentialGeometry/Elaborators.lean @@ -303,6 +303,40 @@ info: MDifferentiableAt 𝓘(𝕜, E) (𝓘(𝕜, E).prod 𝓘(𝕜, E')) fun x #guard_msgs in #check MDiffAt (T% σ') +-- Inferring a model with corners on the trivial bundle over the tangent space of a manifold. +-- TODO: why does this fail; this is not supposed to happen! +/-- +error: Could not find models with corners for TotalSpace F (TangentSpace I) +--- +trace: [Elab.DiffGeo.MDiff] Finding a model for: TotalSpace F (TangentSpace I) +[Elab.DiffGeo.MDiff] ❌️ TotalSpace + [Elab.DiffGeo.MDiff] ❌️ TangentSpace + [Elab.DiffGeo.MDiff] Failed with error: + TangentSpace I is not a `TangentSpace` + [Elab.DiffGeo.MDiff] ❌️ From base info + [Elab.DiffGeo.MDiff] Failed with error: + No `baseInfo` provided + [Elab.DiffGeo.MDiff] Failed with error: + Having a TotalSpace as source is not yet supported +[Elab.DiffGeo.MDiff] ❌️ NormedSpace + [Elab.DiffGeo.MDiff] Failed with error: + Couldn't find a `NormedSpace` structure on TotalSpace F (TangentSpace I) among local instances. +[Elab.DiffGeo.MDiff] ❌️ ChartedSpace + [Elab.DiffGeo.MDiff] Failed with error: + Couldn't find a `ChartedSpace` structure on TotalSpace F (TangentSpace I) among local instances. +[Elab.DiffGeo.MDiff] ❌️ NormedField + [Elab.DiffGeo.MDiff] Failed with error: + failed to synthesize + NontriviallyNormedField (TotalSpace F (TangentSpace I)) + ⏎ + Hint: Additional diagnostic information may be available using the `set_option diagnostics true` command. +-/ +#guard_msgs in +variable {h : Bundle.TotalSpace F (TangentSpace I : M → Type _) → F} in +set_option trace.Elab.DiffGeo true in +#check MDiff h + + /-! Error messages in case of a forgotten `T%`. -/ section From bf9b5e48a54cd68fe159937f91307aabd315a3cb Mon Sep 17 00:00:00 2001 From: Michael Rothgang Date: Mon, 6 Oct 2025 15:41:04 -0700 Subject: [PATCH 096/106] Update Mathlib/Geometry/Manifold/Notation.lean Co-authored-by: thorimur <68410468+thorimur@users.noreply.github.com> --- Mathlib/Geometry/Manifold/Notation.lean | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Mathlib/Geometry/Manifold/Notation.lean b/Mathlib/Geometry/Manifold/Notation.lean index 9670c438e59c3c..6c119222cacbf3 100644 --- a/Mathlib/Geometry/Manifold/Notation.lean +++ b/Mathlib/Geometry/Manifold/Notation.lean @@ -321,7 +321,10 @@ def findModels (e : Expr) (es : Option Expr) : TermElabM (Expr × Expr) := do let srcI ← findModel src if let some es := es then let estype ← inferType es - if !(← pureIsDefEq estype <|← mkAppM ``Set #[src]) then + /- Note: we use `isDefEq` here since persistent metavariable assignments in `src` and + `estype` are acceptable. + TODO: consider attempting to coerce `es` to a `Set`. -/ + if !(← isDefEq estype <|← mkAppM ``Set #[src]) then throwError "The domain {src} of {e} is not definitionally equal to the carrier type of \ the set {es} : {estype}" let tgtI ← findModel tgt (src, srcI) From e6bd1b90c3cf58e91f57c93451d98d1e6ec9cc4e Mon Sep 17 00:00:00 2001 From: Michael Rothgang Date: Mon, 6 Oct 2025 15:41:38 -0700 Subject: [PATCH 097/106] Add docs for auxiliary doc-strings Co-authored-by: thorimur <68410468+thorimur@users.noreply.github.com> --- Mathlib/Geometry/Manifold/Notation.lean | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/Mathlib/Geometry/Manifold/Notation.lean b/Mathlib/Geometry/Manifold/Notation.lean index 6c119222cacbf3..fbc703c78bec42 100644 --- a/Mathlib/Geometry/Manifold/Notation.lean +++ b/Mathlib/Geometry/Manifold/Notation.lean @@ -243,6 +243,8 @@ def findModel (e : Expr) (baseInfo : Option (Expr × Expr) := none) : TermElabM where /- Note that errors thrown in the following are caught by `tryStrategy` and converted to trace messages. -/ + /-- Attempt to find a model from a `TotalSpace` first by seeing if it is the total space of a + tangent bundle, then by attempting to use any provided `baseInfo`. -/ fromTotalSpace : TermElabM Expr := do match_expr e with | Bundle.TotalSpace _ F V => do @@ -250,14 +252,16 @@ where if let some m ← tryStrategy m!"From base info" (fromTotalSpace.fromBaseInfo F) then return m throwError "Having a TotalSpace as source is not yet supported" | _ => throwError "{e} is not a `Bundle.TotalSpace`." + /-- Attempt to find a model from the total space of a tangent bundle. -/ fromTotalSpace.tangentSpace (V : Expr) : TermElabM Expr := do match_expr V with - | TangentSpace _k _ _E _ _ _H _ I M _ _ _x => do + | TangentSpace _k _ _E _ _ _H _ I M _ _ => do trace[Elab.DiffGeo.MDiff] "This is the total space of the tangent bundle of {M}" let srcIT : Term ← Term.exprToSyntax I - let resTerm : Term ← ``(ModelWithCorners.prod $srcIT ModelWithCorners.tangent $srcIT) + let resTerm : Term ← ``(ModelWithCorners.prod $srcIT (ModelWithCorners.tangent $srcIT)) Term.elabTerm resTerm none | _ => throwError "{V} is not a `TangentSpace`" + /-- Attempt to use the provided `baseInfo` to find a model. -/ fromTotalSpace.fromBaseInfo (F : Expr) : TermElabM Expr := do if let some (src, srcI) := baseInfo then trace[Elab.DiffGeo.MDiff] "Using base info {src}, {srcI}" @@ -275,6 +279,7 @@ where Term.elabTerm iTerm none else throwError "No `baseInfo` provided" + /-- Attempt to find the trivial model on a normed space. -/ fromNormedSpace : TermElabM Expr := do let some (inst, K) ← findSomeLocalInstanceOf? ``NormedSpace fun inst type ↦ do match_expr type with @@ -284,6 +289,7 @@ where | throwError "Couldn't find a `NormedSpace` structure on {e} among local instances." trace[Elab.DiffGeo.MDiff] "Field is: {K}" mkAppOptM ``modelWithCornersSelf #[K, none, e, none, inst] + /-- Attempt to find a model with corners on a manifold. -/ fromChartedSpace : TermElabM Expr := do let some H ← findSomeLocalInstanceOf? ``ChartedSpace fun _ type ↦ do match_expr type with @@ -299,6 +305,8 @@ where | _ => return none | throwError "Couldn't find a `ModelWithCorners` with model space {H} in the local context." return m + /-- Attempt to find a model with corners from a normed field. We attempt to find a global + instance here. -/ fromNormedField : TermElabM Expr := do let eT : Term ← Term.exprToSyntax e let iTerm : Term ← ``(𝓘($eT, $eT)) From 583867574e4a2fc293a6e98cefbee4096406da90 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci-lite[bot]" <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com> Date: Mon, 6 Oct 2025 22:42:11 +0000 Subject: [PATCH 098/106] [pre-commit.ci lite] apply automatic fixes --- Mathlib/Geometry/Manifold/Notation.lean | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Mathlib/Geometry/Manifold/Notation.lean b/Mathlib/Geometry/Manifold/Notation.lean index fbc703c78bec42..0d98ac6a4d8bee 100644 --- a/Mathlib/Geometry/Manifold/Notation.lean +++ b/Mathlib/Geometry/Manifold/Notation.lean @@ -243,7 +243,7 @@ def findModel (e : Expr) (baseInfo : Option (Expr × Expr) := none) : TermElabM where /- Note that errors thrown in the following are caught by `tryStrategy` and converted to trace messages. -/ - /-- Attempt to find a model from a `TotalSpace` first by seeing if it is the total space of a + /-- Attempt to find a model from a `TotalSpace` first by seeing if it is the total space of a tangent bundle, then by attempting to use any provided `baseInfo`. -/ fromTotalSpace : TermElabM Expr := do match_expr e with @@ -329,7 +329,7 @@ def findModels (e : Expr) (es : Option Expr) : TermElabM (Expr × Expr) := do let srcI ← findModel src if let some es := es then let estype ← inferType es - /- Note: we use `isDefEq` here since persistent metavariable assignments in `src` and + /- Note: we use `isDefEq` here since persistent metavariable assignments in `src` and `estype` are acceptable. TODO: consider attempting to coerce `es` to a `Set`. -/ if !(← isDefEq estype <|← mkAppM ``Set #[src]) then From 14cc4edb9b86bf67d06a39fa704ad4eda4dbf658 Mon Sep 17 00:00:00 2001 From: Michael Rothgang Date: Mon, 6 Oct 2025 18:15:38 -0700 Subject: [PATCH 099/106] Update Mathlib/Geometry/Manifold/Notation.lean Co-authored-by: thorimur <68410468+thorimur@users.noreply.github.com> --- Mathlib/Geometry/Manifold/Notation.lean | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/Mathlib/Geometry/Manifold/Notation.lean b/Mathlib/Geometry/Manifold/Notation.lean index 0d98ac6a4d8bee..fb8917106a2e8a 100644 --- a/Mathlib/Geometry/Manifold/Notation.lean +++ b/Mathlib/Geometry/Manifold/Notation.lean @@ -243,24 +243,15 @@ def findModel (e : Expr) (baseInfo : Option (Expr × Expr) := none) : TermElabM where /- Note that errors thrown in the following are caught by `tryStrategy` and converted to trace messages. -/ - /-- Attempt to find a model from a `TotalSpace` first by seeing if it is the total space of a - tangent bundle, then by attempting to use any provided `baseInfo`. -/ + /-- Attempt to find a model from a `TotalSpace` first by attempting to use any provided + `baseInfo`, then by seeing if it is the total space of a tangent bundle. -/ fromTotalSpace : TermElabM Expr := do match_expr e with | Bundle.TotalSpace _ F V => do - if let some m ← tryStrategy m!"TangentSpace" (fromTotalSpace.tangentSpace V) then return m if let some m ← tryStrategy m!"From base info" (fromTotalSpace.fromBaseInfo F) then return m + if let some m ← tryStrategy m!"TangentSpace" (fromTotalSpace.tangentSpace V) then return m throwError "Having a TotalSpace as source is not yet supported" | _ => throwError "{e} is not a `Bundle.TotalSpace`." - /-- Attempt to find a model from the total space of a tangent bundle. -/ - fromTotalSpace.tangentSpace (V : Expr) : TermElabM Expr := do - match_expr V with - | TangentSpace _k _ _E _ _ _H _ I M _ _ => do - trace[Elab.DiffGeo.MDiff] "This is the total space of the tangent bundle of {M}" - let srcIT : Term ← Term.exprToSyntax I - let resTerm : Term ← ``(ModelWithCorners.prod $srcIT (ModelWithCorners.tangent $srcIT)) - Term.elabTerm resTerm none - | _ => throwError "{V} is not a `TangentSpace`" /-- Attempt to use the provided `baseInfo` to find a model. -/ fromTotalSpace.fromBaseInfo (F : Expr) : TermElabM Expr := do if let some (src, srcI) := baseInfo then @@ -279,6 +270,15 @@ where Term.elabTerm iTerm none else throwError "No `baseInfo` provided" + /-- Attempt to find a model from the total space of a tangent bundle. -/ + fromTotalSpace.tangentSpace (V : Expr) : TermElabM Expr := do + match_expr V with + | TangentSpace _k _ _E _ _ _H _ I M _ _ => do + trace[Elab.DiffGeo.MDiff] "This is the total space of the tangent bundle of {M}" + let srcIT : Term ← Term.exprToSyntax I + let resTerm : Term ← ``(ModelWithCorners.prod $srcIT (ModelWithCorners.tangent $srcIT)) + Term.elabTerm resTerm none + | _ => throwError "{V} is not a `TangentSpace`" /-- Attempt to find the trivial model on a normed space. -/ fromNormedSpace : TermElabM Expr := do let some (inst, K) ← findSomeLocalInstanceOf? ``NormedSpace fun inst type ↦ do From 77a71aa674f46536750682c6257c8a21e2151719 Mon Sep 17 00:00:00 2001 From: Michael Rothgang Date: Mon, 6 Oct 2025 16:01:22 -0700 Subject: [PATCH 100/106] Update expected output --- .../DifferentialGeometry/Elaborators.lean | 33 +++++++++---------- 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/MathlibTest/DifferentialGeometry/Elaborators.lean b/MathlibTest/DifferentialGeometry/Elaborators.lean index 777ccc2c395a74..dcae674e265913 100644 --- a/MathlibTest/DifferentialGeometry/Elaborators.lean +++ b/MathlibTest/DifferentialGeometry/Elaborators.lean @@ -306,30 +306,27 @@ info: MDifferentiableAt 𝓘(𝕜, E) (𝓘(𝕜, E).prod 𝓘(𝕜, E')) fun x -- Inferring a model with corners on the trivial bundle over the tangent space of a manifold. -- TODO: why does this fail; this is not supposed to happen! /-- -error: Could not find models with corners for TotalSpace F (TangentSpace I) +error: failed to synthesize + TopologicalSpace (TotalSpace F (TangentSpace I)) + +Hint: Additional diagnostic information may be available using the `set_option diagnostics true` command. --- trace: [Elab.DiffGeo.MDiff] Finding a model for: TotalSpace F (TangentSpace I) -[Elab.DiffGeo.MDiff] ❌️ TotalSpace - [Elab.DiffGeo.MDiff] ❌️ TangentSpace - [Elab.DiffGeo.MDiff] Failed with error: - TangentSpace I is not a `TangentSpace` +[Elab.DiffGeo.MDiff] ✅️ TotalSpace [Elab.DiffGeo.MDiff] ❌️ From base info [Elab.DiffGeo.MDiff] Failed with error: No `baseInfo` provided + [Elab.DiffGeo.MDiff] ✅️ TangentSpace + [Elab.DiffGeo.MDiff] This is the total space of the tangent bundle of M + [Elab.DiffGeo.MDiff] Found model: I.prod I.tangent + [Elab.DiffGeo.MDiff] Found model: I.prod I.tangent +[Elab.DiffGeo.MDiff] Finding a model for: F +[Elab.DiffGeo.MDiff] ❌️ TotalSpace [Elab.DiffGeo.MDiff] Failed with error: - Having a TotalSpace as source is not yet supported -[Elab.DiffGeo.MDiff] ❌️ NormedSpace - [Elab.DiffGeo.MDiff] Failed with error: - Couldn't find a `NormedSpace` structure on TotalSpace F (TangentSpace I) among local instances. -[Elab.DiffGeo.MDiff] ❌️ ChartedSpace - [Elab.DiffGeo.MDiff] Failed with error: - Couldn't find a `ChartedSpace` structure on TotalSpace F (TangentSpace I) among local instances. -[Elab.DiffGeo.MDiff] ❌️ NormedField - [Elab.DiffGeo.MDiff] Failed with error: - failed to synthesize - NontriviallyNormedField (TotalSpace F (TangentSpace I)) - ⏎ - Hint: Additional diagnostic information may be available using the `set_option diagnostics true` command. + F is not a `Bundle.TotalSpace`. +[Elab.DiffGeo.MDiff] ✅️ NormedSpace + [Elab.DiffGeo.MDiff] Field is: 𝕜 + [Elab.DiffGeo.MDiff] Found model: 𝓘(𝕜, F) -/ #guard_msgs in variable {h : Bundle.TotalSpace F (TangentSpace I : M → Type _) → F} in From 7411ecd4325e262a37a8f8e12b3abc1564bd408c Mon Sep 17 00:00:00 2001 From: Michael Rothgang Date: Mon, 6 Oct 2025 19:45:10 -0700 Subject: [PATCH 101/106] Comment the recent test --- MathlibTest/DifferentialGeometry/Elaborators.lean | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/MathlibTest/DifferentialGeometry/Elaborators.lean b/MathlibTest/DifferentialGeometry/Elaborators.lean index dcae674e265913..8a03e1c3340755 100644 --- a/MathlibTest/DifferentialGeometry/Elaborators.lean +++ b/MathlibTest/DifferentialGeometry/Elaborators.lean @@ -303,8 +303,9 @@ info: MDifferentiableAt 𝓘(𝕜, E) (𝓘(𝕜, E).prod 𝓘(𝕜, E')) fun x #guard_msgs in #check MDiffAt (T% σ') --- Inferring a model with corners on the trivial bundle over the tangent space of a manifold. --- TODO: why does this fail; this is not supposed to happen! +-- Test the inference of a model with corners on a trivial bundle over the tangent space of a +-- manifold. (This code path is not covered by the other tests, hence should be kept.) +-- Stating smoothness this way does not make sense, but finding a model with corners should work. /-- error: failed to synthesize TopologicalSpace (TotalSpace F (TangentSpace I)) @@ -333,6 +334,7 @@ variable {h : Bundle.TotalSpace F (TangentSpace I : M → Type _) → F} in set_option trace.Elab.DiffGeo true in #check MDiff h +-- TODO: add a test with the correct spelling of this! /-! Error messages in case of a forgotten `T%`. -/ section From 62173130d6618869c063763e4da99243d6f1a2c9 Mon Sep 17 00:00:00 2001 From: Michael Rothgang Date: Mon, 6 Oct 2025 19:46:42 -0700 Subject: [PATCH 102/106] chore: move test --- .../DifferentialGeometry/{Elaborators.lean => Notation.lean} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename MathlibTest/DifferentialGeometry/{Elaborators.lean => Notation.lean} (100%) diff --git a/MathlibTest/DifferentialGeometry/Elaborators.lean b/MathlibTest/DifferentialGeometry/Notation.lean similarity index 100% rename from MathlibTest/DifferentialGeometry/Elaborators.lean rename to MathlibTest/DifferentialGeometry/Notation.lean From 41046cd1758c66c6d33aadadce59242b7056a0b4 Mon Sep 17 00:00:00 2001 From: Michael Rothgang Date: Tue, 7 Oct 2025 07:37:52 -0700 Subject: [PATCH 103/106] chore: add regression test for precendence in the "on/within" set --- .../DifferentialGeometry/Notation.lean | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/MathlibTest/DifferentialGeometry/Notation.lean b/MathlibTest/DifferentialGeometry/Notation.lean index 8a03e1c3340755..66f9149586988c 100644 --- a/MathlibTest/DifferentialGeometry/Notation.lean +++ b/MathlibTest/DifferentialGeometry/Notation.lean @@ -165,6 +165,29 @@ Note: Expected a function because this term is being applied to the argument end +-- Testing the precedence of parsing of the "within" set: regression test. +section + +variable {ι : Type} {i : ι} {s : ι → Set M} + +/-- info: MDifferentiableOn I I' f (s i) : Prop -/ +#guard_msgs in +#check MDiff[s i] f +/-- info: MDifferentiableWithinAt I I' f (s i) m : Prop -/ +#guard_msgs in +#check MDiffAt[s i] f m +/-- info: ContMDiffOn I I' 2 f (s i) : Prop -/ +#guard_msgs in +#check CMDiff[s i] 2 f +/-- info: ContMDiffWithinAt I I' 0 f (s i) m : Prop -/ +#guard_msgs in +#check CMDiffAt[s i] 0 f m +/-- info: mfderivWithin I I' f (s i) m : TangentSpace I m →L[𝕜] TangentSpace I' (f m) -/ +#guard_msgs in +#check mfderiv[s i] f m + +end + -- Function from a manifold into a normed space. variable {g : M → E} From faf1b241383809d2f1e4dca0e037f76c16454fc6 Mon Sep 17 00:00:00 2001 From: Michael Rothgang Date: Tue, 7 Oct 2025 07:47:49 -0700 Subject: [PATCH 104/106] Clarify failing test, and document the right spelling with TangentBundle --- .../DifferentialGeometry/Notation.lean | 38 ++++++++++++++++++- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/MathlibTest/DifferentialGeometry/Notation.lean b/MathlibTest/DifferentialGeometry/Notation.lean index 66f9149586988c..1620190e4fb9a9 100644 --- a/MathlibTest/DifferentialGeometry/Notation.lean +++ b/MathlibTest/DifferentialGeometry/Notation.lean @@ -326,6 +326,12 @@ info: MDifferentiableAt 𝓘(𝕜, E) (𝓘(𝕜, E).prod 𝓘(𝕜, E')) fun x #guard_msgs in #check MDiffAt (T% σ') +section + +variable [IsManifold I 2 M] + +variable {h : Bundle.TotalSpace F (TangentSpace I : M → Type _) → F} {h' : TangentBundle I M → F} + -- Test the inference of a model with corners on a trivial bundle over the tangent space of a -- manifold. (This code path is not covered by the other tests, hence should be kept.) -- Stating smoothness this way does not make sense, but finding a model with corners should work. @@ -353,11 +359,39 @@ trace: [Elab.DiffGeo.MDiff] Finding a model for: TotalSpace F (TangentSpace I) [Elab.DiffGeo.MDiff] Found model: 𝓘(𝕜, F) -/ #guard_msgs in -variable {h : Bundle.TotalSpace F (TangentSpace I : M → Type _) → F} in set_option trace.Elab.DiffGeo true in #check MDiff h --- TODO: add a test with the correct spelling of this! +-- The reason this test fails is that Bundle.TotalSpace F (TangentSpace I : M → Type _) is not +-- the way to state smoothness. +/-- +error: failed to synthesize + TopologicalSpace (TotalSpace F (TangentSpace I)) + +Hint: Additional diagnostic information may be available using the `set_option diagnostics true` command. +-/ +#guard_msgs in +#synth IsManifold I.tangent 1 (Bundle.TotalSpace F (TangentSpace I : M → Type _)) + +-- The correct way is this. +/-- info: TotalSpace.isManifold E (TangentSpace I) -/ +#guard_msgs in +#synth IsManifold I.tangent 1 (TangentBundle I M) + +/-- info: MDifferentiable I.tangent 𝓘(𝕜, F) h' : Prop -/ +#guard_msgs in +#check MDifferentiable I.tangent 𝓘(𝕜, F) h' + +/-- info: MDifferentiable (I.prod 𝓘(𝕜, E)) 𝓘(𝕜, F) h' : Prop -/ +#guard_msgs in +#check MDifferentiable (I.prod (𝓘(𝕜, E))) 𝓘(𝕜, F) h' + +-- TODO: implement special handling for the tangent bundle +/-- error: Could not find models with corners for TangentBundle I M -/ +#guard_msgs in +#check MDiff h' + +end /-! Error messages in case of a forgotten `T%`. -/ section From 8e5d337597e72cb1effc104a652b4a3fb28d951d Mon Sep 17 00:00:00 2001 From: Michael Rothgang Date: Tue, 7 Oct 2025 18:32:16 -0700 Subject: [PATCH 105/106] Noshake; fix bad merge/import --- Mathlib/Lean/Elab/Term.lean | 2 +- scripts/noshake.json | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Mathlib/Lean/Elab/Term.lean b/Mathlib/Lean/Elab/Term.lean index d536cad0358b2b..88069b18f506eb 100644 --- a/Mathlib/Lean/Elab/Term.lean +++ b/Mathlib/Lean/Elab/Term.lean @@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Kyle Miller -/ import Mathlib.Init -import Lean.Elab.SyntheticMVars +import Lean.Elab.Term /-! # Additions to `Lean.Elab.Term` diff --git a/scripts/noshake.json b/scripts/noshake.json index ff19c31cadcd7e..5953a416fa7748 100644 --- a/scripts/noshake.json +++ b/scripts/noshake.json @@ -49,8 +49,8 @@ "Mathlib.Data.Set.Notation", "Mathlib.Data.Sym.Sym2.Init", "Mathlib.Data.Vector.Basic", + "Mathlib.Geometry.Manifold.Notation", "Mathlib.Geometry.Manifold.Instances.Real", - "Mathlib.Geometry.Manifold.Elaborators", "Mathlib.Init", "Mathlib.LinearAlgebra.AffineSpace.Basic", "Mathlib.LinearAlgebra.Matrix.Notation", @@ -254,9 +254,9 @@ "Mathlib.Data.PNat.Defs"], "Mathlib.Tactic.Order.CollectFacts": ["Mathlib.Order.BoundedOrder.Basic", "Mathlib.Order.Lattice"], + "Mathlib.Tactic.NormNum.Parity": ["Mathlib.Algebra.Ring.Int.Parity"], "Mathlib.Tactic.NormNum.ModEq": ["Mathlib.Data.Int.ModEq", "Mathlib.Tactic.NormNum.DivMod"], - "Mathlib.Tactic.NormNum.Parity": ["Mathlib.Algebra.Ring.Int.Parity"], "Mathlib.Tactic.NormNum.Ineq": ["Mathlib.Algebra.Order.Field.Defs", "Mathlib.Algebra.Order.Monoid.WithTop"], "Mathlib.Tactic.NormNum.BigOperators": @@ -349,6 +349,7 @@ "Mathlib.Tactic.Algebraize": ["Mathlib.Algebra.Algebra.Tower"], "Mathlib.Std.Data.HashMap": ["Std.Data.HashMap.AdditionalOperations"], "Mathlib.RingTheory.SimpleModule.Basic": ["Mathlib.Data.Matrix.Mul"], + "Mathlib.RingTheory.PowerSeries.Restricted": ["Mathlib.Tactic.Bound"], "Mathlib.RingTheory.PowerSeries.Evaluation": ["Mathlib.RingTheory.PowerSeries.PiTopology"], "Mathlib.RingTheory.PowerSeries.Basic": @@ -363,7 +364,6 @@ ["Mathlib.LinearAlgebra.FreeModule.IdealQuotient"], "Mathlib.RingTheory.Finiteness.Defs": ["Mathlib.Data.Finsupp.Defs"], "Mathlib.RingTheory.Adjoin.Basic": ["Mathlib.LinearAlgebra.Finsupp.SumProd"], - "Mathlib.RingTheory.PowerSeries.Restricted": ["Mathlib.Tactic.Bound"], "Mathlib.RepresentationTheory.FdRep": ["Mathlib.CategoryTheory.Monoidal.Rigid.Braided"], "Mathlib.RepresentationTheory.FDRep": @@ -415,13 +415,13 @@ "Mathlib.Lean.Expr.ExtraRecognizers": ["Mathlib.Data.Set.Operations"], "Mathlib.Lean.Expr.Basic": ["Batteries.Logic"], "Mathlib.GroupTheory.MonoidLocalization.Basic": ["Mathlib.Init.Data.Prod"], - "Mathlib.Geometry.Manifold.Elaborators": - ["Mathlib.Geometry.Manifold.ContMDiff.Defs", "Mathlib.Geometry.Manifold.MFDeriv.Defs"], "Mathlib.Geometry.Manifold.Sheaf.Smooth": ["Mathlib.CategoryTheory.Sites.Whiskering"], "Mathlib.Geometry.Manifold.PoincareConjecture": ["Mathlib.AlgebraicTopology.FundamentalGroupoid.SimplyConnected", "Mathlib.Util.Superscript"], + "Mathlib.Geometry.Manifold.Notation": + ["Mathlib.Geometry.Manifold.ContMDiff.Defs", "Mathlib.Geometry.Manifold.MFDeriv.Defs"], "Mathlib.Deprecated.NatLemmas": ["Batteries.Data.Nat.Lemmas", "Batteries.WF"], "Mathlib.Deprecated.MinMax": ["Mathlib.Order.MinMax"], "Mathlib.Deprecated.LazyList": ["Mathlib.Lean.Thunk"], From fb2e2b6efd031a35ca2bc70c2a4c0122fd1c0b3f Mon Sep 17 00:00:00 2001 From: Michael Rothgang Date: Wed, 8 Oct 2025 07:27:33 -0700 Subject: [PATCH 106/106] Update Mathlib/Geometry/Manifold/Notation.lean --- Mathlib/Geometry/Manifold/Notation.lean | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mathlib/Geometry/Manifold/Notation.lean b/Mathlib/Geometry/Manifold/Notation.lean index fb8917106a2e8a..52b60ff0e38028 100644 --- a/Mathlib/Geometry/Manifold/Notation.lean +++ b/Mathlib/Geometry/Manifold/Notation.lean @@ -1,7 +1,7 @@ /- Copyright (c) 2025 Patrick Massot. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. -Authors: Patrick Massot, Michael Rothgang +Authors: Patrick Massot, Michael Rothgang, Thomas Murrills -/ import Mathlib.Geometry.Manifold.ContMDiff.Defs import Mathlib.Geometry.Manifold.MFDeriv.Defs