@@ -531,16 +531,6 @@ def applyReplacementLambda (t : TranslateData) (dontTranslate : List Nat) (e : E
531531 else
532532 applyReplacementFun t e #[]
533533
534- /-- Unfold auxlemmas in the type and value. -/
535- def declUnfoldAuxLemmas (decl : ConstantInfo) : MetaM ConstantInfo := do
536- let mut decl := decl
537- decl := decl.updateType <| ← unfoldAuxLemmas decl.type
538- if let some v := decl.value? (allowOpaque := true ) then
539- trace[translate] "value before unfold:{ indentExpr v} "
540- decl := decl.updateValue <| ← unfoldAuxLemmas v
541- trace[translate] "value after unfold:{ indentExpr decl.value!} "
542- return decl
543-
544534/-- Run applyReplacementFun on the given `srcDecl` to make a new declaration with name `tgt` -/
545535def updateDecl (t : TranslateData) (tgt : Name) (srcDecl : ConstantInfo)
546536 (reorder : List (List Nat)) (dont : List Nat) : MetaM ConstantInfo := do
@@ -578,48 +568,49 @@ def findRelevantArg (t : TranslateData) (nm : Name) : CoreM Nat := MetaM.run' do
578568 trace[translate_detail] "findRelevantArg: { arg} "
579569 return arg.getD 0
580570
581- /-- Abstracts the nested proofs in the value of `decl` if it is a def.
582- This follows the behaviour of `Elab.abstractNestedProofs`. -/
583- def declAbstractNestedProofs (decl : ConstantInfo) : MetaM ConstantInfo := do
584- let .defnInfo info := decl | return decl
585- let value ← withDeclNameForAuxNaming decl.name do Meta.abstractNestedProofs info.value
586- return .defnInfo { info with value }
571+ /-- Unfold `simp` auxlemmas in the type and value.
572+ The reason why we can't just translate them is that they are generated by the `@[simp]` attribute,
573+ so it would require a change in the implementation of `@[simp]` to add these translateions.
574+ Additionally, these lemmas have very short proofs, so unfolding them is not costly. -/
575+ def declUnfoldSimpAuxLemmas (decl : ConstantInfo) : MetaM ConstantInfo := do
576+ let unfold (e : Expr) := deltaExpand e fun
577+ | .str _ s => "_simp_" .isPrefixOf s
578+ | _ => false
579+ let mut decl := decl
580+ decl := decl.updateType <| ← unfold decl.type
581+ if let some v := decl.value? (allowOpaque := true ) then
582+ trace[translate] "value before unfold:{ indentExpr v} "
583+ decl := decl.updateValue <| ← unfold v
584+ trace[translate] "value after unfold:{ indentExpr decl.value!} "
585+ return decl
587586
588- /-- Find the target name of `pre` and all created auxiliary declarations. -/
589- def findTargetName (env : Environment) (t : TranslateData) (src pre tgt_pre : Name) : CoreM Name :=
587+ /-- Find the target name of `src`, which is assumed to have been selected by `findAuxDecls`. -/
588+ def findTargetName (env : Environment) (t : TranslateData) (src pre tgt_pre : Name) :
589+ CoreM Name := do
590590 /- This covers auxiliary declarations like `match_i` and `proof_i`. -/
591- if let some post := pre.isPrefixOf? src then
592- return tgt_pre ++ post
593- else if src.hasMacroScopes then
594- -- This branch should come before the next one because an aux def may be both private and macro
595- -- scoped - but really the next branch shouldn't just assume all private defs are eqns??
591+ if let some post := (privateToUserName pre).isPrefixOf? (privateToUserName src) then
592+ let tgt := tgt_pre ++ post
593+ return if isPrivateName src then mkPrivateName env tgt else tgt
594+ if src.hasMacroScopes then
596595 mkFreshUserName src.eraseMacroScopes
597- /- This covers equation lemmas (for other declarations). -/
598- else if let some post := privateToUserName? src then
599- match findTranslation? env t post.getPrefix with
600- -- this is an equation lemma for a declaration without a translation. We will skip this.
601- | none => return src
602- -- this is an equation lemma for a declaration with a translation. We will translate this.
603- -- Note: if this errors we could do this instead by calling `getEqnsFor?`
604- | some addName => return src.updatePrefix <| mkPrivateName env addName
605596 else
606- throwError "internal @[{t.attrName}] error."
607-
608- /-- Returns a `NameSet` of all auxiliary constants in `e` that might have been generated
609- when adding `pre` to the environment.
610- Examples include `pre.match_5` and
611- `_private.Mathlib.MyFile.someOtherNamespace.someOtherDeclaration._eq_2`.
612- The last two examples may or may not have been generated by this declaration.
613- The last example may or may not be the equation lemma of a declaration with a translation attribute.
614- We will only translate it if it has a translation attribute.
615-
616- Note that this function would return `proof_nnn` aux lemmas if
617- we hadn't unfolded them in `declUnfoldAuxLemmas`.
597+ withDeclNameForAuxNaming src do mkAuxDeclName (Name.mkSimple s! "_{ t.attrName.toString} " )
598+
599+ /-- Returns a `NameSet` of auxiliary constants in `decl` that might have been generated
600+ when adding `pre` to the environment, and which hence might need to be translated.
601+ Examples include `pre.match_5`, `pre._proof_2`, `someOtherDeclaration._proof_2` and `wrapped✝`.
602+ The reason why we have to include `_proof_i` lemmas from other declarations is that there is a
603+ cache of such proofs, and previous such auxiliary proofs are reused when possible.
604+ These auxiliary declarations may be private or not, independent of whether `pre` is private.
605+ `wrapped✝` is generated by `irreducible_def`, and it has macro scopes.
618606-/
619- def findAuxDecls (e : Expr) (pre : Name) : NameSet :=
620- e.foldConsts ∅ fun n l ↦
621- if (privateToUserName n).getPrefix == privateToUserName pre || n.hasMacroScopes then
622- l.insert n
607+ def findAuxDecls (decl : ConstantInfo) (pre : Name) : CoreM (Array Name) := do
608+ let env ← withoutExporting getEnv
609+ return (Expr.app decl.type (decl.value! (allowOpaque := true ))).foldConsts #[] fun n l ↦
610+ if (env.find? n).any (·.hasValue (allowOpaque := true )) &&
611+ ((match n with | .str _ s => "_proof_" .isPrefixOf s | _ => false ) ||
612+ (privateToUserName n).getPrefix == privateToUserName pre || n.hasMacroScopes) then
613+ l.push n
623614 else
624615 l
625616
@@ -631,7 +622,7 @@ occurring in `src` using the `translations` dictionary.
631622`pre` is the declaration that got the translation attribute and `tgt_pre` is the target of this
632623declaration. -/
633624partial def transformDeclRec (t : TranslateData) (ref : Syntax) (pre tgt_pre src : Name)
634- (reorder : List (List Nat) := []) (dontTranslate : List Nat := []) : CoreM Unit := do
625+ (dontTranslate : List Nat) (reorder : List (List Nat) := []) : CoreM Unit := do
635626 let env ← getEnv
636627 trace[translate_detail] "visiting { src} "
637628 -- if we have already translated this declaration, we do nothing.
@@ -655,27 +646,28 @@ partial def transformDeclRec (t : TranslateData) (ref : Syntax) (pre tgt_pre src
655646 return
656647 let srcDecl ← withoutExporting do getConstInfo src
657648 -- we first unfold all auxlemmas, since they are not always able to be translated on their own
658- let srcDecl ← withoutExporting do MetaM.run' do declUnfoldAuxLemmas srcDecl
649+ let srcDecl ← withoutExporting do MetaM.run' do declUnfoldSimpAuxLemmas srcDecl
659650 -- we then transform all auxiliary declarations generated when elaborating `pre`
660- for n in findAuxDecls srcDecl.type pre do
661- transformDeclRec t ref pre tgt_pre n
662- if let some value := srcDecl.value? (allowOpaque := true ) then
663- for n in findAuxDecls value pre do
664- transformDeclRec t ref pre tgt_pre n
651+ for n in ← findAuxDecls srcDecl pre do
652+ transformDeclRec t ref pre tgt_pre n dontTranslate
665653 -- expose target body when source body is exposed
666654 withExporting (isExporting := (← getEnv).setExporting true |>.find? src |>.any (·.hasValue)) do
667655 -- if the auxiliary declaration doesn't have prefix `pre`, then we have to add this declaration
668656 -- to the translation dictionary, since otherwise we cannot translate the name.
669657 let relevantArg ← findRelevantArg t src
670658 if !pre.isPrefixOf src || src != pre && relevantArg != 0 then
671659 insertTranslation t src tgt { relevantArg }
660+ -- We still lack a heuristic that automatically infers the `dontTranslate`,
661+ -- so for now we do a best guess based on argument names.
662+ let dontTranslate ← if dontTranslate.isEmpty then pure [] else
663+ if src == pre then pure dontTranslate else
664+ let namesPre := (← getConstInfo pre).type.getForallBinderNames
665+ let namesSrc := (← getConstInfo src).type.getForallBinderNames
666+ pure <| dontTranslate.filterMap (namesPre[·]? >>= namesSrc.idxOf?)
672667 -- now transform the source declaration
673668 let trgDecl ← MetaM.run' <| updateDecl t tgt srcDecl reorder dontTranslate
674- let some value := trgDecl.value? (allowOpaque := true )
675- | throwError "Expected {tgt} to have a value."
669+ let value := trgDecl.value! (allowOpaque := true )
676670 trace[translate] "generating\n { tgt} : { trgDecl.type} :=\n { value} "
677- -- "Refold" all the aux lemmas that we unfolded.
678- let trgDecl ← MetaM.run' <| declAbstractNestedProofs trgDecl
679671 /- If `src` is explicitly marked as `noncomputable`, then add the new decl as a declaration but
680672 do not compile it, and mark is as noncomputable. Otherwise, only log errors in compiling if `src`
681673 has executable code.
@@ -1194,7 +1186,7 @@ partial def addTranslationAttr (t : TranslateData) (src : Name) (cfg : Config)
11941186 proceedFields t src tgt argInfo
11951187 else
11961188 -- tgt doesn't exist, so let's make it
1197- transformDeclRec t cfg.ref src tgt src argInfo.reorder cfg.dontTranslate
1189+ transformDeclRec t cfg.ref src tgt src cfg.dontTranslate argInfo.reorder
11981190 let nestedNames ← copyMetaData t cfg src tgt argInfo
11991191 -- add pop-up information when mousing over the given translated name
12001192 -- (the information will be over the attribute if no translated name is given)
0 commit comments