@@ -11,7 +11,6 @@ public import Lean.Meta.SynthInstance
1111public import Lean.Meta.CtorRecognizer
1212public import Lean.Elab.Term.TermElabM
1313import Lean.Structure
14- import all Lean.Elab.App
1514
1615/-!
1716# Instance Wrapping
@@ -63,7 +62,7 @@ Given an instance `i : I` and expected type `I'` (where `I'` must be mvar-free),
6362- `backward.inferInstanceAs.wrap.data`: wrap data fields in auxiliary definitions
6463 -/
6564
66- namespace Lean.Elab.Term
65+ namespace Lean.Meta
6766
6867public register_builtin_option backward.inferInstanceAs.wrap : Bool := {
6968 defValue := true
@@ -113,12 +112,30 @@ partial def getFieldOrigin (structName field : Name) : MetaM (Name × StructureF
113112 | throwError "no such field {field} in {structName}"
114113 return (structName, fi)
115114
115+ /-- Projects application of a structure type to corresponding application of a parent structure. -/
116+ def getParentStructType? (structName parentStructName : Name) (structType : Expr) : MetaM (Option Expr) := OptionT.run do
117+ let env ← getEnv
118+ let some path := getPathToBaseStructure? env parentStructName structName | failure
119+ withLocalDeclD `self structType fun self => do
120+ let proj ← path.foldlM (init := self) fun e projFn => do
121+ let ty ← whnf (← inferType e)
122+ let .const _ us := ty.getAppFn
123+ | trace[Meta.wrapInstance] "could not reduce type `{ ty} `"
124+ failure
125+ let params := ty.getAppArgs
126+ pure <| mkApp (mkAppN (.const projFn us) params) e
127+ let projTy ← whnf <| ← inferType proj
128+ if projTy.containsFVar self.fvarId! then
129+ trace[Meta.wrapInstance] "parent type depends on instance fields{ indentExpr projTy} "
130+ failure
131+ return projTy
132+
116133/--
117134Wrap an instance value so its type matches the expected type exactly.
118135See the module docstring for the full algorithm specification.
119136-/
120137public partial def wrapInstance (inst expectedType : Expr) (compile : Bool := true )
121- (logCompileErrors : Bool := true) (isMeta : Bool := false) : Term.TermElabM Expr := withTransparency .instances do
138+ (logCompileErrors : Bool := true ) (isMeta : Bool := false ) : MetaM Expr := withTransparency .instances do
122139 withTraceNode `Meta.wrapInstance
123140 (fun _ => return m! "type: { expectedType} " ) do
124141 let some className ← isClass? expectedType
@@ -199,19 +216,15 @@ public partial def wrapInstance (inst expectedType : Expr) (compile : Bool := tr
199216 let (baseClassName, fieldInfo) ← getFieldOrigin className mvarDecl.userName
200217 if baseClassName != className then
201218 trace[Meta.wrapInstance] "found inherited field `{ mvarDecl.userName} ` from parent `{ baseClassName} `"
202- -- find appropriate arguments to `baseClassName` by unification with projection chain
203- let baseClassType ← do
204- let instMVar ← mkFreshExprMVar (some expectedType)
205- let baseClassInst ← mkBaseProjections baseClassName className instMVar
206- inferType baseClassInst
207- try
208- if let .some existingBaseClassInst ← trySynthInstance baseClassType then
209- trace[Meta.wrapInstance] " using projection of existing instance `{existingBaseClassInst}`"
210- mvarId.assign (← mkProjection existingBaseClassInst fieldInfo.fieldName)
211- continue
212- trace[Meta.wrapInstance] " did not find existing instance for `{baseClassName}`"
213- catch e =>
214- trace[Meta.wrapInstance] " error when attempting to reuse existing instance for `{baseClassName}`: {e.toMessageData}"
219+ if let some baseClassType ← getParentStructType? className baseClassName expectedType then
220+ try
221+ if let .some existingBaseClassInst ← trySynthInstance baseClassType then
222+ trace[Meta.wrapInstance] "using projection of existing instance `{ existingBaseClassInst} `"
223+ mvarId.assign (← mkProjection existingBaseClassInst fieldInfo.fieldName)
224+ continue
225+ trace[Meta.wrapInstance] "did not find existing instance for `{ baseClassName} `"
226+ catch e =>
227+ trace[Meta.wrapInstance] "error when attempting to reuse existing instance for `{ baseClassName} `: { e.toMessageData} "
215228
216229 -- For data fields, assign directly or wrap in aux def to fix types.
217230 if backward.inferInstanceAs.wrap.data.get (← getOptions) then
0 commit comments