From 4d349987fa16c78d2548141faac3aba8aa245de4 Mon Sep 17 00:00:00 2001 From: Remy Willems Date: Tue, 5 May 2026 15:09:07 +0000 Subject: [PATCH 01/10] Update test to expose HeapParameterization bug --- .gitignore | 3 ++- .../Laurel/Examples/Objects/T1_MutableFields.lean | 7 +++++-- StrataTest/Languages/Laurel/TestExamples.lean | 10 ++++++++++ 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index 3776616d98..9f5babd9ab 100644 --- a/.gitignore +++ b/.gitignore @@ -12,4 +12,5 @@ vcs/*.smt2 *.py.ion *.py.ion.core.st -Strata.code-workspace \ No newline at end of file +Strata.code-workspace +Build/ \ No newline at end of file diff --git a/StrataTest/Languages/Laurel/Examples/Objects/T1_MutableFields.lean b/StrataTest/Languages/Laurel/Examples/Objects/T1_MutableFields.lean index 7dbf35022d..cb6c151d45 100644 --- a/StrataTest/Languages/Laurel/Examples/Objects/T1_MutableFields.lean +++ b/StrataTest/Languages/Laurel/Examples/Objects/T1_MutableFields.lean @@ -195,9 +195,12 @@ procedure fieldTargetInMultiAssign() assign c#intValue, y, var z: int := modifyHeapAndReturnMultiple(c); assert c#intValue == 1; assert y == 2; - assert z == 3 + var z2: int := (z := z + 1); + assert z2 == 4; + assert false +//^^^^^^^^^^^^ error: assertion could not be proved }; "# -#guard_msgs(drop info, error) in +#guard_msgs (drop info, error) in #eval testInputWithOffset "MutableFields" program 14 processLaurelFile diff --git a/StrataTest/Languages/Laurel/TestExamples.lean b/StrataTest/Languages/Laurel/TestExamples.lean index 5affbb2813..781cc366fd 100644 --- a/StrataTest/Languages/Laurel/TestExamples.lean +++ b/StrataTest/Languages/Laurel/TestExamples.lean @@ -36,4 +36,14 @@ def processLaurelFileWithOptions (options : LaurelVerifyOptions) (input : InputC def processLaurelFile (input : InputContext) : IO (Array Diagnostic) := processLaurelFileWithOptions default input +/-- Project-root-relative path to the `Build/` directory for intermediate files. + Resolved from the current working directory so it works on any machine. -/ +def buildDir : IO String := do + let cwd ← IO.currentDir + return s!"{cwd}/Build/" + +def processLaurelFileKeepIntermediates (input : InputContext) : IO (Array Diagnostic) := do + let dir ← buildDir + processLaurelFileWithOptions { translateOptions := { keepAllFilesPrefix := dir}} input + end Laurel From 7760c921758d4409326d1fdfd333734d50ecd03d Mon Sep 17 00:00:00 2001 From: Remy Willems Date: Tue, 5 May 2026 15:27:09 +0000 Subject: [PATCH 02/10] Add fix --- Strata/Languages/Laurel/HeapParameterization.lean | 8 ++++++-- .../Laurel/Examples/Objects/T1_MutableFields.lean | 1 + 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/Strata/Languages/Laurel/HeapParameterization.lean b/Strata/Languages/Laurel/HeapParameterization.lean index fecaf5350c..3378896a90 100644 --- a/Strata/Languages/Laurel/HeapParameterization.lean +++ b/Strata/Languages/Laurel/HeapParameterization.lean @@ -315,7 +315,11 @@ where let isLast := idx == n - 1 let s' ← recurse s (isLast && valueUsed) let rest' ← processStmts (idx + 1) rest - pure (s' :: rest') + -- Flatten unlabeled blocks returned by recurse so that + -- Declare targets remain in the enclosing scope. + match s'.val with + | .Block innerStmts (some "$inlineMe") => pure (innerStmts ++ rest') + | _ => pure (s' :: rest') termination_by sizeOf remaining let stmts' ← processStmts 0 stmts return ⟨ .Block stmts' label, source ⟩ @@ -389,7 +393,7 @@ where -- Create a block if necessary if suffixes.length > 0 then - return ⟨ StmtExpr.Block (newAssign :: suffixes) none, source ⟩ + return ⟨ StmtExpr.Block (newAssign :: suffixes) (some "$inlineMe"), source ⟩ else return newAssign diff --git a/StrataTest/Languages/Laurel/Examples/Objects/T1_MutableFields.lean b/StrataTest/Languages/Laurel/Examples/Objects/T1_MutableFields.lean index cb6c151d45..1f1d6210b3 100644 --- a/StrataTest/Languages/Laurel/Examples/Objects/T1_MutableFields.lean +++ b/StrataTest/Languages/Laurel/Examples/Objects/T1_MutableFields.lean @@ -195,6 +195,7 @@ procedure fieldTargetInMultiAssign() assign c#intValue, y, var z: int := modifyHeapAndReturnMultiple(c); assert c#intValue == 1; assert y == 2; + // This looks convoluted but it is to ensure that z is still in scope after the transformation var z2: int := (z := z + 1); assert z2 == 4; assert false From f8acfc6535982c59558885d0ce4e12e68e9ee123 Mon Sep 17 00:00:00 2001 From: Remy Willems Date: Tue, 5 May 2026 15:35:22 +0000 Subject: [PATCH 03/10] Update --- Strata/Languages/Laurel/LaurelCompilationPipeline.lean | 3 +++ .../Languages/Laurel/Examples/Objects/T1_MutableFields.lean | 6 +----- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/Strata/Languages/Laurel/LaurelCompilationPipeline.lean b/Strata/Languages/Laurel/LaurelCompilationPipeline.lean index c6984120fe..b207913395 100644 --- a/Strata/Languages/Laurel/LaurelCompilationPipeline.lean +++ b/Strata/Languages/Laurel/LaurelCompilationPipeline.lean @@ -180,6 +180,9 @@ private def runLaurelPasses (options : LaurelTranslateOptions) (program : Progra -- Run resolve after the pass if needed if pass.needsResolves then let result := resolve program (some model) + if !result.errors.isEmpty then + panic! s!"Internal error: resolution after '{pass.name}' introduced {result.errors.size} new error(s). \ + This indicates a compiler bug in the '{pass.name}' pass." program := result.program model := result.model emit pass.name "laurel.st" program diff --git a/StrataTest/Languages/Laurel/Examples/Objects/T1_MutableFields.lean b/StrataTest/Languages/Laurel/Examples/Objects/T1_MutableFields.lean index 1f1d6210b3..e46f03ef99 100644 --- a/StrataTest/Languages/Laurel/Examples/Objects/T1_MutableFields.lean +++ b/StrataTest/Languages/Laurel/Examples/Objects/T1_MutableFields.lean @@ -195,11 +195,7 @@ procedure fieldTargetInMultiAssign() assign c#intValue, y, var z: int := modifyHeapAndReturnMultiple(c); assert c#intValue == 1; assert y == 2; - // This looks convoluted but it is to ensure that z is still in scope after the transformation - var z2: int := (z := z + 1); - assert z2 == 4; - assert false -//^^^^^^^^^^^^ error: assertion could not be proved + assert z == 3 }; "# From 39189f3c44384d276754551afb33791332ab4ccb Mon Sep 17 00:00:00 2001 From: Remy Willems Date: Tue, 5 May 2026 15:36:23 +0000 Subject: [PATCH 04/10] update comment --- Strata/Languages/Laurel/HeapParameterization.lean | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Strata/Languages/Laurel/HeapParameterization.lean b/Strata/Languages/Laurel/HeapParameterization.lean index 3378896a90..f68b93c031 100644 --- a/Strata/Languages/Laurel/HeapParameterization.lean +++ b/Strata/Languages/Laurel/HeapParameterization.lean @@ -315,7 +315,7 @@ where let isLast := idx == n - 1 let s' ← recurse s (isLast && valueUsed) let rest' ← processStmts (idx + 1) rest - -- Flatten unlabeled blocks returned by recurse so that + -- Flatten blocks created by recurse so that -- Declare targets remain in the enclosing scope. match s'.val with | .Block innerStmts (some "$inlineMe") => pure (innerStmts ++ rest') From 515f13db3f7ff217ab5121f62e7eafa6b70b49f2 Mon Sep 17 00:00:00 2001 From: Remy Willems Date: Tue, 5 May 2026 15:58:24 +0000 Subject: [PATCH 05/10] Replace panic --- Strata/Languages/Laurel/LaurelCompilationPipeline.lean | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/Strata/Languages/Laurel/LaurelCompilationPipeline.lean b/Strata/Languages/Laurel/LaurelCompilationPipeline.lean index b207913395..e13efd3679 100644 --- a/Strata/Languages/Laurel/LaurelCompilationPipeline.lean +++ b/Strata/Languages/Laurel/LaurelCompilationPipeline.lean @@ -180,9 +180,12 @@ private def runLaurelPasses (options : LaurelTranslateOptions) (program : Progra -- Run resolve after the pass if needed if pass.needsResolves then let result := resolve program (some model) - if !result.errors.isEmpty then - panic! s!"Internal error: resolution after '{pass.name}' introduced {result.errors.size} new error(s). \ - This indicates a compiler bug in the '{pass.name}' pass." + let newErrors := result.errors.filter fun e => !resolutionErrors.contains e + if !newErrors.isEmpty then + let newDiags := newErrors.toList.map fun d => + { d with message := + s!"Internal error: resolution after '{pass.name}' introduced this diagnostic: {d.message}" } + return (program, model, allDiags ++ newDiags, allStats) program := result.program model := result.model emit pass.name "laurel.st" program From 4c72dc4410faa0f42c3500d992dd15f1d3cfb81d Mon Sep 17 00:00:00 2001 From: Remy Willems Date: Tue, 5 May 2026 16:12:52 +0000 Subject: [PATCH 06/10] Fixes --- Strata/Languages/Laurel/LaurelCompilationPipeline.lean | 1 + .../Laurel/Examples/Objects/T7_InstanceProcedures.lean | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Strata/Languages/Laurel/LaurelCompilationPipeline.lean b/Strata/Languages/Laurel/LaurelCompilationPipeline.lean index e13efd3679..17b6f42d63 100644 --- a/Strata/Languages/Laurel/LaurelCompilationPipeline.lean +++ b/Strata/Languages/Laurel/LaurelCompilationPipeline.lean @@ -185,6 +185,7 @@ private def runLaurelPasses (options : LaurelTranslateOptions) (program : Progra let newDiags := newErrors.toList.map fun d => { d with message := s!"Internal error: resolution after '{pass.name}' introduced this diagnostic: {d.message}" } + emit pass.name "laurel.st" program return (program, model, allDiags ++ newDiags, allStats) program := result.program model := result.model diff --git a/StrataTest/Languages/Laurel/Examples/Objects/T7_InstanceProcedures.lean b/StrataTest/Languages/Laurel/Examples/Objects/T7_InstanceProcedures.lean index ec05fcfd3d..189295102d 100644 --- a/StrataTest/Languages/Laurel/Examples/Objects/T7_InstanceProcedures.lean +++ b/StrataTest/Languages/Laurel/Examples/Objects/T7_InstanceProcedures.lean @@ -15,8 +15,8 @@ namespace Strata.Laurel def instanceProcedureProgram := r" composite Counter { var count: int - procedure increment(self: Counter) -// ^^^^^^^^^ error: Instance procedure 'increment' on composite type 'Counter' is not yet supported + procedure self_increment(self: Counter) +// ^^^^^^^^^^^^^^ error: Instance procedure 'self_increment' on composite type 'Counter' is not yet supported opaque { self#count := self#count + 1 From 9788a1bfcd878beb388f317f5dc4cd3241d4aa79 Mon Sep 17 00:00:00 2001 From: Remy Willems Date: Tue, 5 May 2026 16:23:14 +0000 Subject: [PATCH 07/10] Fix bug in ConstrainedTypeElim --- Strata/Languages/Laurel/ConstrainedTypeElim.lean | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Strata/Languages/Laurel/ConstrainedTypeElim.lean b/Strata/Languages/Laurel/ConstrainedTypeElim.lean index 7e86c374a1..dce1a2eef3 100644 --- a/Strata/Languages/Laurel/ConstrainedTypeElim.lean +++ b/Strata/Languages/Laurel/ConstrainedTypeElim.lean @@ -224,7 +224,7 @@ private def mkWitnessProc (ptMap : ConstrainedTypeMap) (ct : ConstrainedType) : { name := mkId s!"$witness_{ct.name.text}" inputs := [] outputs := [] - body := .Transparent ⟨.Block [witnessInit, assert] none, src⟩ + body := .Opaque [] (some ⟨.Block [witnessInit, assert] none, src⟩) [] preconditions := [] isFunctional := false decreases := none } From a5a6d5c7126b98c380c4bd9784c977eac60cd54b Mon Sep 17 00:00:00 2001 From: Remy Willems Date: Tue, 5 May 2026 16:39:53 +0000 Subject: [PATCH 08/10] Fix test --- StrataTest/Languages/Laurel/ConstrainedTypeElimTest.lean | 3 +++ 1 file changed, 3 insertions(+) diff --git a/StrataTest/Languages/Laurel/ConstrainedTypeElimTest.lean b/StrataTest/Languages/Laurel/ConstrainedTypeElimTest.lean index 86ce51e683..0811d5e955 100644 --- a/StrataTest/Languages/Laurel/ConstrainedTypeElimTest.lean +++ b/StrataTest/Languages/Laurel/ConstrainedTypeElimTest.lean @@ -52,6 +52,7 @@ procedure test(n: int) ensures nat$constraint(r) { assert r >= 0; var y: int := n; assert nat$constraint(y); return y }; procedure $witness_nat() + opaque { var $witness: int := 0; assert nat$constraint($witness) }; -/ #guard_msgs in @@ -80,6 +81,7 @@ info: function pos$constraint(v: int): bool procedure test(b: bool) { if b then { var x: int := 1; assert pos$constraint(x) }; { var x: int := -5; x := -10 } }; procedure $witness_pos() + opaque { var $witness: int := 1; assert pos$constraint($witness) }; -/ #guard_msgs in @@ -104,6 +106,7 @@ info: function posint$constraint(x: int): bool procedure f() { var x: int; assume posint$constraint(x); assert x == 1 }; procedure $witness_posint() + opaque { var $witness: int := 1; assert posint$constraint($witness) }; -/ #guard_msgs in From 702bf342897ffad63dfada248046dc375853316c Mon Sep 17 00:00:00 2001 From: Remy Willems Date: Tue, 5 May 2026 19:56:31 +0200 Subject: [PATCH 09/10] Update Strata/Languages/Laurel/LaurelCompilationPipeline.lean Co-authored-by: Michael Tautschnig --- Strata/Languages/Laurel/LaurelCompilationPipeline.lean | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/Strata/Languages/Laurel/LaurelCompilationPipeline.lean b/Strata/Languages/Laurel/LaurelCompilationPipeline.lean index 17b6f42d63..ffb15c1bda 100644 --- a/Strata/Languages/Laurel/LaurelCompilationPipeline.lean +++ b/Strata/Languages/Laurel/LaurelCompilationPipeline.lean @@ -179,16 +179,21 @@ private def runLaurelPasses (options : LaurelTranslateOptions) (program : Progra allStats := allStats.merge stats -- Run resolve after the pass if needed if pass.needsResolves then + let result := resolve program (some model) let result := resolve program (some model) let newErrors := result.errors.filter fun e => !resolutionErrors.contains e if !newErrors.isEmpty then let newDiags := newErrors.toList.map fun d => - { d with message := - s!"Internal error: resolution after '{pass.name}' introduced this diagnostic: {d.message}" } + { d with + message := + s!"Internal error: resolution after '{pass.name}' introduced this diagnostic: {d.message}" + type := .StrataBug } emit pass.name "laurel.st" program return (program, model, allDiags ++ newDiags, allStats) program := result.program model := result.model + program := result.program + model := result.model emit pass.name "laurel.st" program return (program, model, allDiags, allStats) From 906fe44d1b4b352997476dd89e9585d34ad3328c Mon Sep 17 00:00:00 2001 From: Remy Willems Date: Tue, 5 May 2026 17:57:26 +0000 Subject: [PATCH 10/10] Fix oops --- Strata/Languages/Laurel/LaurelCompilationPipeline.lean | 3 --- 1 file changed, 3 deletions(-) diff --git a/Strata/Languages/Laurel/LaurelCompilationPipeline.lean b/Strata/Languages/Laurel/LaurelCompilationPipeline.lean index ffb15c1bda..22e40c57fc 100644 --- a/Strata/Languages/Laurel/LaurelCompilationPipeline.lean +++ b/Strata/Languages/Laurel/LaurelCompilationPipeline.lean @@ -179,7 +179,6 @@ private def runLaurelPasses (options : LaurelTranslateOptions) (program : Progra allStats := allStats.merge stats -- Run resolve after the pass if needed if pass.needsResolves then - let result := resolve program (some model) let result := resolve program (some model) let newErrors := result.errors.filter fun e => !resolutionErrors.contains e if !newErrors.isEmpty then @@ -192,8 +191,6 @@ private def runLaurelPasses (options : LaurelTranslateOptions) (program : Progra return (program, model, allDiags ++ newDiags, allStats) program := result.program model := result.model - program := result.program - model := result.model emit pass.name "laurel.st" program return (program, model, allDiags, allStats)