Skip to content

Commit e8da78a

Browse files
authored
fix: enforce implicit invariants in EmitC stronger (#11381)
This PR fixes a bug where the closed term extraction does not respect the implicit invariant of the c emitter to have closed term decls first, other decls second, within an SCC. This bug has not yet been triggered in the wild but was unearthed during work on upcoming modifications of the specializer.
1 parent d8913f8 commit e8da78a

File tree

3 files changed

+37
-27
lines changed

3 files changed

+37
-27
lines changed

src/Lean/Compiler/LCNF/ExtractClosed.lean

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -141,17 +141,27 @@ def visitDecl (decl : Decl) : M Decl := do
141141

142142
end ExtractClosed
143143

144-
partial def Decl.extractClosed (decl : Decl) (sccDecls : Array Decl) : CompilerM (Array Decl) := do
144+
partial def Decl.extractClosed (decl : Decl) (sccDecls : Array Decl) : CompilerM (Decl × Array Decl) := do
145145
let ⟨decl, s⟩ ← ExtractClosed.visitDecl decl |>.run { baseName := decl.name, sccDecls } |>.run {}
146-
return s.decls.push decl
146+
return (decl, s.decls)
147147

148148
def extractClosed : Pass where
149149
phase := .mono
150150
name := `extractClosed
151151
run := fun decls => do
152152
if (← getConfig).extractClosed then
153-
decls.foldlM (init := #[]) fun newDecls decl =>
154-
return newDecls ++ (← decl.extractClosed decls)
153+
let mut changedDecls := Array.emptyWithCapacity decls.size
154+
let mut closedDecls := #[]
155+
for decl in decls do
156+
let (change, new) ← decl.extractClosed decls
157+
changedDecls := changedDecls.push change
158+
closedDecls := closedDecls ++ new
159+
160+
/-
161+
EmitC later relies on the fact that within an SCC the closed term declarations come first,
162+
then the declarations that rely on them.
163+
-/
164+
return closedDecls ++ changedDecls
155165
else
156166
return decls
157167

tests/lean/run/emptyLcnf.lean

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,17 +11,7 @@ trace: [Compiler.result] size: 0
1111
def f x : Nat :=
1212
1313
---
14-
trace: [Compiler.result] size: 5
15-
def _private.lean.run.emptyLcnf.0._eval._lam_0 _x.1 _x.2 _y.3 _y.4 _y.5 _y.6 _y.7 _y.8 _y.9 : EST.Out Lean.Exception
16-
lcAny PUnit :=
17-
let _x.10 := Lean.Compiler.compile _x.1 _y.7 _y.8 _y.9;
18-
cases _x.10 : EST.Out Lean.Exception lcAny PUnit
19-
| EST.Out.ok a.11 a.12 =>
20-
let _x.13 := @EST.Out.ok ◾ ◾ ◾ _x.2 a.12;
21-
return _x.13
22-
| EST.Out.error a.14 a.15 =>
23-
return _x.10
24-
[Compiler.result] size: 1
14+
trace: [Compiler.result] size: 1
2515
def _private.lean.run.emptyLcnf.0._eval._closed_0 : String :=
2616
let _x.1 := "f";
2717
return _x.1
@@ -41,6 +31,16 @@ trace: [Compiler.result] size: 5
4131
let _x.2 := _eval._closed_2.2;
4232
let _x.3 := Array.push ◾ _x.2 _x.1;
4333
return _x.3
34+
[Compiler.result] size: 5
35+
def _private.lean.run.emptyLcnf.0._eval._lam_0 _x.1 _x.2 _y.3 _y.4 _y.5 _y.6 _y.7 _y.8 _y.9 : EST.Out Lean.Exception
36+
lcAny PUnit :=
37+
let _x.10 := Lean.Compiler.compile _x.1 _y.7 _y.8 _y.9;
38+
cases _x.10 : EST.Out Lean.Exception lcAny PUnit
39+
| EST.Out.ok a.11 a.12 =>
40+
let _x.13 := @EST.Out.ok ◾ ◾ ◾ _x.2 a.12;
41+
return _x.13
42+
| EST.Out.error a.14 a.15 =>
43+
return _x.10
4444
[Compiler.result] size: 8
4545
def _private.lean.run.emptyLcnf.0._eval a.1 a.2 a.3 : EST.Out Lean.Exception lcAny PUnit :=
4646
let _x.4 := _eval._closed_0.2;

tests/lean/run/erased.lean

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -25,18 +25,7 @@ trace: [Compiler.result] size: 1
2525
let _x.1 : PSigma lcErased lcAny := PSigma.mk ◾ ◾ ◾ ◾;
2626
return _x.1
2727
---
28-
trace: [Compiler.result] size: 5
29-
def _private.lean.run.erased.0._eval._lam_0 (_x.1 : Array
30-
Lean.Name) (_x.2 : PUnit) (_y.3 : Lean.Elab.Term.Context) (_y.4 : lcAny) (_y.5 : Lean.Meta.Context) (_y.6 : lcAny) (_y.7 : Lean.Core.Context) (_y.8 : lcAny) (_y.9 : lcVoid) : EST.Out
31-
Lean.Exception lcAny PUnit :=
32-
let _x.10 : EST.Out Lean.Exception lcAny PUnit := compile _x.1 _y.7 _y.8 _y.9;
33-
cases _x.10 : EST.Out Lean.Exception lcAny PUnit
34-
| EST.Out.ok (a.11 : PUnit) (a.12 : lcVoid) =>
35-
let _x.13 : EST.Out Lean.Exception lcAny PUnit := @EST.Out.ok ◾ ◾ ◾ _x.2 a.12;
36-
return _x.13
37-
| EST.Out.error (a.14 : Lean.Exception) (a.15 : lcVoid) =>
38-
return _x.10
39-
[Compiler.result] size: 1
28+
trace: [Compiler.result] size: 1
4029
def _private.lean.run.erased.0._eval._closed_0 : String :=
4130
let _x.1 : String := "Erased";
4231
return _x.1
@@ -61,6 +50,17 @@ trace: [Compiler.result] size: 5
6150
let _x.2 : Array Lean.Name := _eval._closed_3.2;
6251
let _x.3 : Array Lean.Name := Array.push ◾ _x.2 _x.1;
6352
return _x.3
53+
[Compiler.result] size: 5
54+
def _private.lean.run.erased.0._eval._lam_0 (_x.1 : Array
55+
Lean.Name) (_x.2 : PUnit) (_y.3 : Lean.Elab.Term.Context) (_y.4 : lcAny) (_y.5 : Lean.Meta.Context) (_y.6 : lcAny) (_y.7 : Lean.Core.Context) (_y.8 : lcAny) (_y.9 : lcVoid) : EST.Out
56+
Lean.Exception lcAny PUnit :=
57+
let _x.10 : EST.Out Lean.Exception lcAny PUnit := compile _x.1 _y.7 _y.8 _y.9;
58+
cases _x.10 : EST.Out Lean.Exception lcAny PUnit
59+
| EST.Out.ok (a.11 : PUnit) (a.12 : lcVoid) =>
60+
let _x.13 : EST.Out Lean.Exception lcAny PUnit := @EST.Out.ok ◾ ◾ ◾ _x.2 a.12;
61+
return _x.13
62+
| EST.Out.error (a.14 : Lean.Exception) (a.15 : lcVoid) =>
63+
return _x.10
6464
[Compiler.result] size: 9
6565
def _private.lean.run.erased.0._eval (a.1 : Lean.Elab.Command.Context) (a.2 : lcAny) (a.3 : lcVoid) : EST.Out
6666
Lean.Exception lcAny PUnit :=

0 commit comments

Comments
 (0)