@@ -19,6 +19,14 @@ open Lean.Compiler (LCNF.Alt LCNF.Arg LCNF.Code LCNF.Decl LCNF.DeclValue LCNF.LC
1919
2020namespace ToIR
2121
22+ /--
23+ Marks an extern definition to be guaranteed to always return tagged values.
24+ This information is used to optimize reference counting in the compiler.
25+ -/
26+ @[builtin_doc]
27+ builtin_initialize taggedReturnAttr : TagAttribute ←
28+ registerTagAttribute `tagged_return "mark extern definition to always return tagged values"
29+
2230structure BuilderState where
2331 vars : Std.HashMap FVarId Arg := {}
2432 joinPoints : Std.HashMap FVarId JoinPointId := {}
@@ -334,12 +342,20 @@ where resultTypeForArity (type : Lean.Expr) (arity : Nat) : Lean.Expr :=
334342
335343def lowerDecl (d : LCNF.Decl) : M (Option Decl) := do
336344 let params ← d.params.mapM lowerParam
337- let resultType ← lowerResultType d.type d.params.size
345+ let mut resultType ← lowerResultType d.type d.params.size
346+ let taggedReturn := taggedReturnAttr.hasTag (← getEnv) d.name
338347 match d.value with
339348 | .code code =>
349+ if taggedReturn then
350+ throwError m!"Error while compiling function '{d.name}': @[tagged_return] is only valid for extern declarations"
340351 let body ← lowerCode code
341352 pure <| some <| .fdecl d.name params resultType body {}
342353 | .extern externAttrData =>
354+ if taggedReturn then
355+ if resultType.isScalar then
356+ throwError m!"@[tagged_return] on function '{d.name}' with scalar return type {resultType}"
357+ else
358+ resultType := .tagged
343359 if externAttrData.entries.isEmpty then
344360 -- TODO: This matches the behavior of the old compiler, but we should
345361 -- find a better way to handle this.
0 commit comments