feat: option to ignore borrowing annotations completely (#12886)

This PR adds support for ignoring user defined borrow annotations. This
can be useful when defining
`extern`/`export` pairs as the `extern` might be infected by borrow
annotations while in `export`
they are already ignored.
This commit is contained in:
Henrik Böving
2026-03-11 21:59:06 +01:00
committed by GitHub
parent 6a2a884372
commit d9ebd51c04
4 changed files with 57 additions and 4 deletions

View File

@@ -15,6 +15,7 @@ import Lean.Compiler.LCNF.ExplicitBoxing
import Lean.Compiler.LCNF.Internalize
public import Lean.Compiler.ExternAttr
import Lean.Compiler.LCNF.ExplicitRC
import Lean.Compiler.Options
public section
@@ -32,9 +33,10 @@ where
let type Compiler.LCNF.getOtherDeclMonoType declName
let mut typeIter := type
let mut params := #[]
let ignoreBorrow := Compiler.compiler.ignoreBorrowAnnotation.get ( getOptions)
repeat
let .forallE binderName ty b _ := typeIter | break
let borrow := isMarkedBorrowed ty
let borrow := !ignoreBorrow && isMarkedBorrowed ty
params := params.push {
fvarId := ( mkFreshFVarId)
type := ty,

View File

@@ -7,10 +7,13 @@ module
prelude
public import Lean.Compiler.InitAttr
public import Lean.Compiler.LCNF.ToLCNF
import Lean.Compiler.Options
import Lean.Meta.Transform
import Lean.Meta.Match.MatcherInfo
import Init.While
public section
namespace Lean.Compiler.LCNF
/--
Inline constants tagged with the `[macro_inline]` attribute occurring in `e`.
@@ -127,10 +130,11 @@ def toDecl (declName : Name) : CompilerM (Decl .pure) := do
let paramsFromTypeBinders (expr : Expr) : CompilerM (Array (Param .pure)) := do
let mut params := #[]
let mut currentExpr := expr
let ignoreBorrow := compiler.ignoreBorrowAnnotation.get ( getOptions)
repeat
match currentExpr with
| .forallE binderName type body _ =>
let borrow := isMarkedBorrowed type
let borrow := !ignoreBorrow && isMarkedBorrowed type
params := params.push ( mkParam binderName type borrow)
currentExpr := body
| _ => break
@@ -156,12 +160,15 @@ def toDecl (declName : Name) : CompilerM (Decl .pure) := do
let value macroInline value
return (type, value)
let code toLCNF value
let decl if let .fun decl (.return _) := code then
let mut decl if let .fun decl (.return _) := code then
eraseFunDecl decl (recursive := false)
pure { name := declName, params := decl.params, type, value := .code decl.value, levelParams := info.levelParams, safe, inlineAttr? : Decl .pure }
else
pure { name := declName, params := #[], type, value := .code code, levelParams := info.levelParams, safe, inlineAttr? }
/- `toLCNF` may eta-reduce simple declarations. -/
decl.etaExpand
decl decl.etaExpand
if compiler.ignoreBorrowAnnotation.get ( getOptions) then
decl := { decl with params := decl.params.mapM (·.updateBorrow false) }
return decl
end Lean.Compiler.LCNF

View File

@@ -35,4 +35,10 @@ register_builtin_option compiler.relaxedMetaCheck : Bool := {
descr := "Allow mixed `meta`/non-`meta` references in the same module. References to imports are unaffected."
}
register_builtin_option compiler.ignoreBorrowAnnotation : Bool := {
defValue := false
descr := "Ignore user defined borrow inference annotations. This is useful for export/extern \
forward declarations"
}
end Lean.Compiler

View File

@@ -0,0 +1,38 @@
module
/-!
This test asserts that disabling user-defined borrow annotations works. This is sometimes required for
export/extern pairs
-/
public abbrev Foo (α : Type) := (x : @& α) α
/--
trace: [Compiler.result] size: 0
def t1 @&x : tobj :=
extern
[Compiler.result] size: 2
def t1._boxed x : tobj :=
let res := t1 x;
dec x;
return res
-/
#guard_msgs in
set_option trace.Compiler.result true in
@[extern "t1"]
public opaque t1 : Foo Nat
/--
trace: [Compiler.result] size: 0
def t2 x : tobj :=
extern
[Compiler.result] size: 1
def t2._boxed x : tobj :=
let res := t2 x;
return res
-/
#guard_msgs in
set_option compiler.ignoreBorrowAnnotation true in
set_option trace.Compiler.result true in
@[extern "t2"]
public opaque t2 : Foo Nat