@@ -563,26 +563,68 @@ def applyReplacementLambda (t : TranslateData) (dontTranslate : List Nat) (e : E
563563
564564/-- Run `applyReplacementFun` on the given `srcDecl` to make a new declaration with name `tgt`. -/
565565def updateDecl (t : TranslateData) (tgt : Name) (srcDecl : ConstantInfo)
566- (reorder : Reorder) (dont : List Nat) : MetaM ConstantInfo := do
566+ (reorder : Reorder) (dont : List Nat)
567+ (unfoldBoundaries? : Option UnfoldBoundary.UnfoldBoundaries) : MetaM ConstantInfo := do
567568 let mut decl := srcDecl.updateName tgt
568569 if reorder.any (·.contains 0 ) then
569570 decl := decl.updateLevelParams decl.levelParams.swapFirstTwo
570571 let mut value := decl.value! (allowOpaque := true )
571- if let some b := t. unfoldBoundaries? then
572+ if let some b := unfoldBoundaries? then
572573 value ← b.cast (← b.insertBoundaries value t.attrName) decl.type t.attrName
573574 trace[translate] "Value before translation:{ indentExpr value} "
574575 value ← reorderLambda reorder <| ← applyReplacementLambda t dont value
575- if let some b := t. unfoldBoundaries? then
576+ if let some b := unfoldBoundaries? then
576577 value ← b.unfoldInsertions value
577578 decl := decl.updateValue value
578579 let mut type := decl.type
579- if let some b := t. unfoldBoundaries? then
580+ if let some b := unfoldBoundaries? then
580581 type ← b.insertBoundaries decl.type t.attrName
581582 type ← reorderForall reorder <| ← applyReplacementForall t dont <| renameBinderNames t type
582- if let some b := t. unfoldBoundaries? then
583+ if let some b := unfoldBoundaries? then
583584 type ← b.unfoldInsertions type
584585 return decl.updateType type
585586
587+ /-- Translate the source declaration and then run `addDecl`. If the kernel throws an error,
588+ try to emit a better error message.
589+
590+ For efficiency in `to_dual`, we first run `updateDecl` without any `UnfoldBoundaries`,
591+ and only if that fails do we try to include them.
592+ The reason is that in the most common case, `to_dual` succeeds without needing to insert
593+ unfold boundaries, and figuring out whether to insert them can be quite expensive. -/
594+ def updateAndAddDecl (t : TranslateData) (tgt : Name) (srcDecl : ConstantInfo)
595+ (reorder : Reorder) (dont : List Nat) : MetaM ConstantInfo :=
596+ -- Set `Elab.async` to `false` so that we can catch kernel errors.
597+ withOptions (Elab.async.set · false ) do
598+ let decl ←
599+ if let some unfoldBoundaries := t.unfoldBoundaries? then
600+ let env ← getEnv
601+ -- First attempt to generate the translation without unfold boundaries.
602+ let declAttempt ← updateDecl t tgt srcDecl reorder dont none
603+ try
604+ addDecl declAttempt.toDeclaration!
605+ trace[translate] "generating\n { tgt} : { declAttempt.type} :=\
606+ { indentExpr <| declAttempt.value! (allowOpaque := true )} "
607+ return declAttempt -- early return
608+ catch _ =>
609+ setEnv env
610+ updateDecl t tgt srcDecl reorder dont (unfoldBoundaries.getState env)
611+ else
612+ updateDecl t tgt srcDecl reorder dont none
613+ trace[translate] "generating\n { tgt} : { decl.type} :=\
614+ { indentExpr <| decl.value! (allowOpaque := true )} "
615+ try
616+ addDecl decl.toDeclaration!
617+ return decl
618+ catch ex =>
619+ try
620+ withoutExporting <| check (decl.value! (allowOpaque := true ))
621+ catch ex =>
622+ throwError "@[{t.attrName}] failed to add declaration `{decl.name}`.\n \
623+ The translated value is not type correct.\n \
624+ For help, see the docstring of `to_additive`, section `Troubleshooting`.\n \
625+ {ex.toMessageData}"
626+ throwError "@[{t.attrName}] failed. Nested error message:\n {ex.toMessageData}"
627+
586628/--
587629Find the argument of `nm` that appears in the first translatable (type-class) argument.
588630Returns 1 if there are no types with a translatable class as arguments.
@@ -702,26 +744,10 @@ partial def transformDeclRec (t : TranslateData) (ref : Syntax) (pre tgt_pre src
702744 let namesSrc := (← getConstInfo src).type.getForallBinderNames
703745 pure <| dontTranslate.filterMap (namesPre[·]? >>= namesSrc.idxOf?)
704746 -- now transform the source declaration
705- let trgDecl ← MetaM.run' <| updateDecl t tgt srcDecl reorder dontTranslate
706- if src == pre && srcDecl.isThm && trgDecl .type == srcDecl.type then
747+ let tgtDecl ← MetaM.run' <| updateAndAddDecl t tgt srcDecl reorder dontTranslate
748+ if src == pre && srcDecl.isThm && tgtDecl .type == srcDecl.type then
707749 Linter.logLintIf linter.translateRedundant ref m! "`{ t.attrName} ` did not change the type \
708750 of theorem `{ .ofConstName src} `. Please remove the attribute."
709- let value := trgDecl.value! (allowOpaque := true )
710- trace[translate] "generating\n { tgt} : { trgDecl.type} :=\n { value} "
711- try
712- -- set `Elab.async` to `false` in order to be able to catch kernel errors
713- withOptions (Elab.async.set · false ) do
714- addDecl trgDecl.toDeclaration!
715- catch ex =>
716- -- Try to emit a better error message if the kernel throws an error.
717- try
718- withoutExporting <| MetaM.run' <| check value
719- catch ex =>
720- throwError "@[{t.attrName}] failed. \
721- The translated value is not type correct. For help, see the docstring \
722- of `to_additive`, section `Troubleshooting`. \
723- Failed to add declaration\n {tgt}:\n {ex.toMessageData}"
724- throwError "@[{t.attrName}] failed. Nested error message:\n {ex.toMessageData}"
725751 /- If `src` is explicitly marked as `noncomputable`, then add the new decl as a declaration but
726752 do not compile it, and mark is as noncomputable. Otherwise, only log errors in compiling if `src`
727753 has executable code.
@@ -740,8 +766,8 @@ partial def transformDeclRec (t : TranslateData) (ref : Syntax) (pre tgt_pre src
740766 if isMarkedMeta (← getEnv) src then
741767 -- We need to mark `tgt` as `meta` before running `compileDecl`
742768 modifyEnv (markMeta · tgt)
743- compileDecl trgDecl .toDeclaration! (logErrors := (IR.findEnvDecl (← getEnv) src).isSome)
744- if let .defnInfo { hints := .abbrev, .. } := trgDecl then
769+ compileDecl tgtDecl .toDeclaration! (logErrors := (IR.findEnvDecl (← getEnv) src).isSome)
770+ if let .defnInfo { hints := .abbrev, .. } := tgtDecl then
745771 if (← getReducibilityStatus src) == .reducible then
746772 setReducibilityStatus tgt .reducible
747773 if Compiler.getInlineAttribute? (← getEnv) src == some .inline then
@@ -917,7 +943,8 @@ partial def checkExistingType (t : TranslateData) (src tgt : Name) (cfg : Config
917943 throwError "`{t.attrName}` validation failed:\n expected {srcDecl.levelParams.length} \
918944 universe levels, but '{tgt}' has {tgtDecl.levelParams.length} universe levels"
919945 let mut srcType := srcDecl.type
920- if let some b := t.unfoldBoundaries? then
946+ let unfoldBoundaries? ← t.unfoldBoundaries?.mapM (return ·.getState (← getEnv))
947+ if let some b := unfoldBoundaries? then
921948 srcType ← b.insertBoundaries srcType t.attrName
922949 srcType ← applyReplacementForall t cfg.dontTranslate srcType
923950 let reorder' := guessReorder srcType tgtDecl.type
@@ -942,7 +969,7 @@ partial def checkExistingType (t : TranslateData) (src tgt : Name) (cfg : Config
942969 If you need to give a hint to `{ t.attrName} ` to translate expressions involving `{ src} `,\n \
943970 use `{ t.attrName} _do_translate` instead"
944971 srcType ← reorderForall reorder srcType
945- if let some b := t. unfoldBoundaries? then
972+ if let some b := unfoldBoundaries? then
946973 srcType ← b.unfoldInsertions srcType
947974 if reorder.any (·.contains 0 ) then
948975 srcDecl := srcDecl.updateLevelParams srcDecl.levelParams.swapFirstTwo
0 commit comments