Skip to content

Commit 4d3cbac

Browse files
AD1024olivier-aws
andauthored
feat(laurel): Adding surface syntax for calling instance procedures & lowering to Core (#1328)
## Summary This PR addresses the problem that Laurel composite types could *declare* instance procedures inside `composite { ... }` blocks, but they couldn't be compiled or called. The Laurel→Core translator unconditionally rejected every instance procedure with a `NotYetImplemented` diagnostic, and even without that block they would have been silently dropped: the SCC ordering in [`CoreGroupingAndOrdering.lean`](Strata/Languages/Laurel/CoreGroupingAndOrdering.lean) only enumerates `program.staticProcedures`, so anything on `CompositeType.instanceProcedures` never reached Strata Core. ### 1. Surface syntax of instance procedure calls: `obj#method(args)` - **Parser** ([`ConcreteToAbstractTreeTranslator.lean`](Strata/Languages/Laurel/Grammar/ConcreteToAbstractTreeTranslator.lean)): when the callee of `call(...)` is a `fieldAccess` node, emit `InstanceCall target method args` instead of dropping the receiver into an empty-string static call. - **Grammar** ([`LaurelGrammar.st`](Strata/Languages/Laurel/Grammar/LaurelGrammar.st)): adjust `call`'s precedence so `c#m(args)` parses as `call(fieldAccess(c, m), args)`. - **Resolution** ([`Resolution.lean`](Strata/Languages/Laurel/Resolution.lean)): pre-register instance procedures in the global scope under their lifted key (`<CompositeName>$<methodName>`). Two composites can now share a method name without colliding (Note: this change seems to resolve #1321 but the the issue of the Resolver still exists - variable scope should be carefully refactored for the resolution pass). `InstanceCall` resolution looks up the receiver's composite type, builds the lifted key, and stamps the resolved `uniqueId` on the original callee identifier. ### 2. Laurel-to-Laurel pass: `LiftInstanceProcedures` A new pass under [`Strata/Languages/Laurel/LiftInstanceProcedures.lean`](Strata/Languages/Laurel/LiftInstanceProcedures.lean), wired into [`LaurelCompilationPipeline.lean`](Strata/Languages/Laurel/LaurelCompilationPipeline.lean) with `needsResolves := true` between `EliminateValueReturns` and `HeapParameterization`. The pass: - Walks every `.Composite ct` in `program.types` and clones each `proc ∈ ct.instanceProcedures` into a fresh top-level static procedure named `<CompositeName>$<methodName>`. Body, parameters, contracts, and `invokeOn` are copied verbatim. - Walks the entire program and rewrites every `InstanceCall` whose callee so it points at the lifted name (with the receiver prepended as the first argument to match the lifted procedure's `self : <CompositeName>` parameter). - Clears `ct.instanceProcedures := []` on every composite and appends the lifted procedures to `program.staticProcedures`. Downstream simplifications: [`HeapParameterization.lean`](Strata/Languages/Laurel/HeapParameterization.lean) drops its secondary traversal of `instanceProcedures` (now always empty), and the `NotYetImplemented` block in [`LaurelToCoreTranslator.lean`](Strata/Languages/Laurel/LaurelToCoreTranslator.lean) is replaced by a defensive `StrataBug` assertion that fires only on a pass-ordering regression (all instance procedures should already be lifted and rewritten at this point). --------- Co-authored-by: olivier-aws <obouisso@amazon.com>
1 parent 24b8f04 commit 4d3cbac

10 files changed

Lines changed: 427 additions & 49 deletions

Strata/Languages/Laurel/Grammar/ConcreteToAbstractTreeTranslator.lean

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -303,13 +303,20 @@ partial def translateStmtExpr (arg : Arg) : TransM StmtExprMd := do
303303
return mkStmtExprMd (.AsType target (mkHighTypeMd (.UserDefined typeName) src)) src
304304
| q`Laurel.call, #[arg0, argsSeq] =>
305305
let callee ← translateStmtExpr arg0
306-
let calleeName := match callee.val with
307-
| .Var (.Local name) => name
308-
| _ => ""
309306
let argsList ← match argsSeq with
310307
| .seq _ .comma args => args.toList.mapM translateStmtExpr
311308
| _ => pure []
312-
return mkStmtExprMd (.StaticCall calleeName argsList) src
309+
-- `obj#method(args)` parses as `call(fieldAccess(obj, method), args)`.
310+
-- Treat such calls as instance-method calls; everything else stays a
311+
-- static call by callee text (empty when the callee is a higher-order
312+
-- expression — preserved to match prior behavior).
313+
match callee.val with
314+
| .Var (.Field target fieldName) =>
315+
return mkStmtExprMd (.InstanceCall target fieldName argsList) src
316+
| .Var (.Local name) =>
317+
return mkStmtExprMd (.StaticCall name argsList) src
318+
| _ =>
319+
return mkStmtExprMd (.StaticCall (mkId "") argsList) src
313320
| q`Laurel.return, #[arg0] =>
314321
let value ← match arg0 with
315322
| .option _ (some valArg) => some <$> translateStmtExpr valArg

Strata/Languages/Laurel/Grammar/LaurelGrammar.lean

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,12 @@
33
44
SPDX-License-Identifier: Apache-2.0 OR MIT
55
-/
6+
-- Grammar updated: renamed Optional* categories (op names updated)
7+
-- Grammar updated: `call` callee at prec 89 to accept fieldAccess (prec 90) chains
8+
-- Grammar updated: `fieldAccess` is leftassoc so `a#b#c` parses as `(a#b)#c`
69
-- Grammar updated: added bitvector literal support (bvLiteral)
7-
module
810

11+
module
912
-- Laurel dialect definition, loaded from LaurelGrammar.st
1013
-- NOTE: Changes to LaurelGrammar.st are not automatically tracked by the build system.
1114
-- Update this file (e.g. this comment) to trigger a recompile after modifying LaurelGrammar.st.

Strata/Languages/Laurel/Grammar/LaurelGrammar.st

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,13 +34,14 @@ op initializer(value: StmtExpr): Initializer => " := " value:0;
3434
op varDecl (name: Ident, varType: Option TypeAnnotation, assignment: Option Initializer): StmtExpr
3535
=> @[prec(0)] "var " name varType assignment;
3636

37-
op call(callee: StmtExpr, args: CommaSepBy StmtExpr): StmtExpr => callee "(" args ")";
37+
op call(callee: StmtExpr, args: CommaSepBy StmtExpr): StmtExpr =>
38+
@[prec(95)] callee:89 "(" args ")";
3839

3940
// Instantiation
4041
op new(name: Ident): StmtExpr => "new " name;
4142

42-
// Field access
43-
op fieldAccess (obj: StmtExpr, field: Ident): StmtExpr => @[prec(90)] obj "#" field;
43+
// Field access. `leftassoc` so chained access (`a#b#c`) parses as `(a#b)#c`.
44+
op fieldAccess (obj: StmtExpr, field: Ident): StmtExpr => @[prec(90), leftassoc] obj "#" field;
4445

4546
// Identifiers/Variables - must come after fieldAccess so c.value parses as fieldAccess not identifier
4647
op identifier (name: Ident): StmtExpr => name;

Strata/Languages/Laurel/HeapParameterization.lean

Lines changed: 11 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -286,7 +286,8 @@ where
286286
| return [⟨ .Hole, source ⟩]
287287

288288
let valTy := (model.get fieldName).getType
289-
let readExpr := ⟨ .StaticCall "readField" [mkMd (.Var (.Local heapVar)), selectTarget, mkMd (.StaticCall qualifiedName [])], source ⟩
289+
let selectTarget' ← recurseOne selectTarget
290+
let readExpr := ⟨ .StaticCall "readField" [mkMd (.Var (.Local heapVar)), selectTarget', mkMd (.StaticCall qualifiedName [])], source ⟩
290291
-- Unwrap Box: apply the appropriate destructor
291292
recordBoxConstructor model valTy.val
292293
return [mkMd <| .StaticCall (boxDestructorName model valTy.val) [readExpr]]
@@ -544,16 +545,10 @@ def heapTransformProcedure (model: SemanticModel) (proc : Procedure) : Transform
544545
return proc
545546

546547
def heapParameterization (model: SemanticModel) (program : Program) : Program :=
547-
let program := { program with
548-
types := program.types
549-
staticProcedures := program.staticProcedures }
550-
let instanceProcs := program.types.foldl (fun acc td =>
551-
match td with
552-
| .Composite ct => acc ++ ct.instanceProcedures
553-
| _ => acc) ([] : List Procedure)
554-
let allProcs := program.staticProcedures ++ instanceProcs
555-
let heapReaders := computeReadsHeap allProcs
556-
let heapWriters := computeWritesHeap allProcs
548+
-- Instance procedures are already lifted to `staticProcedures` by an earlier
549+
-- pass, so they're covered by the calls below.
550+
let heapReaders := computeReadsHeap program.staticProcedures
551+
let heapWriters := computeWritesHeap program.staticProcedures
557552
let initState : TransformState := { heapReaders, heapWriters }
558553
let (procs', state1) := (program.staticProcedures.mapM (heapTransformProcedure model)).run initState
559554
-- Collect all qualified field names and generate a Field datatype
@@ -563,18 +558,14 @@ def heapParameterization (model: SemanticModel) (program : Program) : Program :=
563558
| _ => acc) ([] : List Identifier)
564559
let fieldDatatype : TypeDefinition :=
565560
.Datatype { name := "Field", typeArgs := [], constructors := fieldNames.map fun n => { name := n, args := [] } }
566-
-- Remove fields from composite types since they are now stored in the heap
567-
-- Also transform instance procedures, accumulating used Box constructors
568-
let (types', state2) := program.types.foldl (fun (accTypes, accState) td =>
561+
-- Remove fields from composite types since they are now stored in the heap.
562+
let types' := program.types.map fun td =>
569563
match td with
570-
| .Composite ct =>
571-
let (instProcs', s') := (ct.instanceProcedures.mapM (heapTransformProcedure model)).run accState
572-
(accTypes ++ [.Composite { ct with fields := [], instanceProcedures := instProcs' }], s')
573-
| other => (accTypes ++ [other], accState))
574-
([], state1)
564+
| .Composite ct => .Composite { ct with fields := [] }
565+
| other => other
575566
-- Generate Box datatype from all constructors used during transformation
576567
let boxDatatype : TypeDefinition :=
577-
.Datatype { name := "Box", typeArgs := [], constructors := state2.usedBoxConstructors }
568+
.Datatype { name := "Box", typeArgs := [], constructors := state1.usedBoxConstructors }
578569
{ program with
579570
staticProcedures := heapConstants.staticProcedures ++ procs',
580571
types := fieldDatatype :: boxDatatype :: heapConstants.types ++ types' }

Strata/Languages/Laurel/LaurelCompilationPipeline.lean

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import Strata.Languages.Laurel.EliminateDeterministicHoles
1818
import Strata.Languages.Laurel.CoreDefinitionsForLaurel
1919
import Strata.Languages.Laurel.LiftImperativeExpressions
2020
import Strata.Languages.Laurel.ConstrainedTypeElim
21-
21+
import Strata.Languages.Laurel.LiftInstanceProcedures
2222
import Strata.Languages.Laurel.TypeAliasElim
2323
public import Strata.Languages.Laurel.LaurelPass
2424
public import Strata.Languages.Core
@@ -96,6 +96,7 @@ def laurelPipeline : Array LaurelPass := #[
9696
typeAliasElimPass,
9797
filterNonCompositeModifiesPass,
9898
eliminateValueInReturnsPass,
99+
liftInstanceProceduresPass,
99100
heapParameterizationPass,
100101
typeHierarchyTransformPass,
101102
modifiesClausesTransformPass,
@@ -183,6 +184,15 @@ def translateWithLaurel (options : LaurelTranslateOptions) (program : Program)
183184
| none => Strata.Pipeline.PipelineContext.create (outputMode := .quiet)
184185
runPipelineM options.keepAllFilesPrefix do
185186
let (program, model, passDiags, stats) ← runLaurelPasses pctx program
187+
-- Sanity check: `LiftInstanceProcedures` should have cleared every
188+
-- composite's `instanceProcedures` list.
189+
let mut passDiags := passDiags
190+
for td in program.types do
191+
if let .Composite ct := td then
192+
for proc in ct.instanceProcedures do
193+
passDiags := passDiags ++ [diagnosticFromSource proc.name.source
194+
s!"Instance procedure '{proc.name.text}' on composite type '{ct.name.text}' was not lifted before Core translation (pipeline-ordering bug)"
195+
DiagnosticType.StrataBug]
186196
let unorderedCore := transparencyPass program
187197
emit "transparencyPass" "core.st" unorderedCore
188198

Strata/Languages/Laurel/LaurelToCoreTranslator.lean

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -722,7 +722,6 @@ abbrev TranslateResult := (Option Core.Program) × (List DiagnosticModel)
722722

723723
/--
724724
Translate a `CoreWithLaurelTypes` program to a `Core.Program`.
725-
The `program` parameter is the lowered Laurel program, used for type definitions.
726725
-/
727726
def translateLaurelToCore (options: LaurelTranslateOptions) (ordered : CoreWithLaurelTypes): TranslateM Core.Program := do
728727

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
/-
2+
Copyright Strata Contributors
3+
4+
SPDX-License-Identifier: Apache-2.0 OR MIT
5+
-/
6+
module
7+
8+
public import Strata.Languages.Laurel.MapStmtExpr
9+
public import Strata.Languages.Laurel.Resolution
10+
public import Strata.Languages.Laurel.LaurelPass
11+
12+
/-!
13+
# Lift Instance Procedures
14+
15+
A Laurel-to-Laurel pass that lifts every instance procedure (a procedure
16+
defined inside a `composite` block) to a top-level static procedure with a
17+
mangled name `<CompositeName>$<methodName>`, then rewrites every call site
18+
that resolved to such an instance procedure to use the lifted name.
19+
20+
After this pass:
21+
- `CompositeType.instanceProcedures` is empty for every composite.
22+
- `program.staticProcedures` contains the lifted procedures.
23+
- Every `InstanceCall` (from `obj#method(args)` surface syntax) points
24+
at the lifted name. For `InstanceCall`, the receiver is prepended to
25+
the argument list to match the lifted procedure's `self : <CompositeName>`
26+
parameter.
27+
-/
28+
29+
namespace Strata.Laurel
30+
31+
/-! ## Lifting + call-site rewriting
32+
33+
Lift instance procedures to static scope (e.g., procedure `proc`
34+
of composite type `T` will be lifted to `T$proc`).
35+
Then, rewrite caller-side of `obj#proc` to call the lifted procedure
36+
37+
-/
38+
39+
/-- Top-level name produced for a lifted instance procedure. -/
40+
def liftedProcName (typeName methodName : Identifier) : Identifier :=
41+
mkId s!"{typeName.text}${methodName.text}"
42+
43+
/-- Rewrite a single node so that any callee resolving to an instance procedure
44+
is replaced by its lifted name. -/
45+
private def rewriteCallNode (model : SemanticModel) (expr : StmtExprMd) : StmtExprMd :=
46+
match expr.val with
47+
| .StaticCall callee args =>
48+
match model.get? callee with
49+
| some (.instanceProcedure typeName _) =>
50+
let lifted := liftedProcName typeName callee
51+
{ expr with val := .StaticCall lifted args }
52+
| _ => expr
53+
| .InstanceCall target callee args =>
54+
-- `obj#method(args)` surface syntax parses to InstanceCall. Flatten it to
55+
-- a static call against the lifted name, prepending the receiver as the
56+
-- first argument to match the lifted procedure's `self` parameter.
57+
match model.get? callee with
58+
| some (.instanceProcedure typeName _) =>
59+
let lifted := liftedProcName typeName callee
60+
{ expr with val := .StaticCall lifted (target :: args) }
61+
| _ => expr
62+
| _ => expr
63+
64+
/-- Apply call-site rewriting to every expression in a procedure. -/
65+
private def rewriteCallsInProc (model : SemanticModel) (proc : Procedure) : Procedure :=
66+
let f := mapStmtExpr (rewriteCallNode model)
67+
let resolveBody : Body → Body := fun body => match body with
68+
| .Transparent b => .Transparent (f b)
69+
| .Opaque ps impl modif =>
70+
.Opaque (ps.map (·.mapCondition f)) (impl.map f) (modif.map f)
71+
| .Abstract ps => .Abstract (ps.map (·.mapCondition f))
72+
| .External => .External
73+
{ proc with
74+
body := resolveBody proc.body
75+
preconditions := proc.preconditions.map (·.mapCondition f)
76+
decreases := proc.decreases.map f
77+
invokeOn := proc.invokeOn.map f }
78+
79+
/-- Apply call-site rewriting to a constrained type's constraint and witness. -/
80+
private def rewriteCallsInType (model : SemanticModel) (td : TypeDefinition) : TypeDefinition :=
81+
match td with
82+
| .Constrained ct =>
83+
let f := mapStmtExpr (rewriteCallNode model)
84+
.Constrained { ct with constraint := f ct.constraint, witness := f ct.witness }
85+
| _ => td
86+
87+
public section
88+
89+
/--
90+
Lift every `proc ∈ ct.instanceProcedures` to a top-level static procedure
91+
named via `liftedProcName`, rewrite call sites that resolved to an instance
92+
procedure, and clear `instanceProcedures` on every composite.
93+
-/
94+
def liftInstanceProcedures (model : SemanticModel) (program : Program) : Program :=
95+
-- Step 1: collect lifted clones
96+
let liftedProcs : List Procedure :=
97+
program.types.foldl (init := []) fun acc td =>
98+
match td with
99+
| .Composite ct =>
100+
acc ++ ct.instanceProcedures.map fun proc =>
101+
{ proc with name := liftedProcName ct.name proc.name }
102+
| _ => acc
103+
104+
if liftedProcs.isEmpty then program else
105+
106+
-- Step 2: rewrite call sites in procedure bodies and constrained-type
107+
let rewrittenStaticProcs := program.staticProcedures.map (rewriteCallsInProc model)
108+
let rewrittenLiftedProcs := liftedProcs.map (rewriteCallsInProc model)
109+
let rewrittenTypes := program.types.map (rewriteCallsInType model)
110+
111+
-- Step 3: clear instanceProcedures on every composite.
112+
let cleanedTypes := rewrittenTypes.map fun td =>
113+
match td with
114+
| .Composite ct => .Composite { ct with instanceProcedures := [] }
115+
| _ => td
116+
117+
-- Step 4: append lifted procs.
118+
{ program with
119+
staticProcedures := rewrittenStaticProcs ++ rewrittenLiftedProcs
120+
types := cleanedTypes }
121+
122+
end -- public section
123+
124+
/-- Pipeline pass: lift instance procedures to top-level static procedures
125+
and rewrite call sites to use the lifted names. -/
126+
public def liftInstanceProceduresPass : LaurelPass where
127+
name := "LiftInstanceProcedures"
128+
documentation := "Lifts every procedure declared inside a `composite` block to a top-level static procedure named `<CompositeName>$<methodName>` and rewrites call sites resolved to an instance procedure (including `obj#method(args)` surface syntax) to point at the lifted name. Clears `instanceProcedures` on every composite. Must run before HeapParameterization."
129+
needsResolves := true
130+
run := fun p m => (liftInstanceProcedures m p, [], {})
131+
132+
end Strata.Laurel

Strata/Languages/Laurel/Resolution.lean

Lines changed: 39 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -158,18 +158,42 @@ def resolveRef (name : Identifier) (source : Option FileRange := none)
158158
modify fun s => { s with errors := s.errors.push diag }
159159
return { name with uniqueId := none }
160160

161+
/-- Scope key for a name nested inside a container (composite, datatype),
162+
used to disambiguate members in the flat global scope. -/
163+
private def containerScopedName (containerName memberName : Identifier) : Identifier :=
164+
mkId s!"{containerName.text}${memberName.text}"
165+
161166
/-- Extract the UserDefined type name from a resolved target expression by looking up its scope entry. -/
162167
private def targetTypeName (target : StmtExprMd) : ResolveM (Option String) := do
163168
let s ← get
164-
match target.val with
169+
match _h : target.val with
165170
| .Var (.Local ref) =>
166171
match s.scope.get? ref.text with
167172
| some (_, node) =>
168173
match node.getType.val with
169174
| .UserDefined typRef => pure (some typRef.text)
170175
| _ => pure none
171176
| none => pure none
177+
| .Var (.Field inner fieldName) => do
178+
match (← targetTypeName inner) with
179+
| none => pure none
180+
| some innerTy =>
181+
match s.typeScopes.get? innerTy with
182+
| none => pure none
183+
| some typeScope =>
184+
match typeScope.get? fieldName.text with
185+
| some (_, node) =>
186+
match node.getType.val with
187+
| .UserDefined typRef => pure (some typRef.text)
188+
| _ => pure none
189+
| none => pure none
172190
| _ => pure none
191+
termination_by sizeOf target
192+
decreasing_by
193+
have := AstNode.sizeOf_val_lt target
194+
have : sizeOf target.val = sizeOf (StmtExpr.Var (Variable.Field inner fieldName)) := congrArg sizeOf _h
195+
simp at this
196+
omega
173197

174198
/-- Try to resolve a field name via a type scope lookup. Returns `some id` on success. -/
175199
private def resolveFieldInTypeScope (typeName : String) (fieldName : Identifier) : ResolveM (Option Identifier) := do
@@ -456,8 +480,16 @@ def resolveStmtExpr (exprMd : StmtExprMd) : ResolveM StmtExprMd := do
456480
pure (.IsType target' ty')
457481
| .InstanceCall target callee args =>
458482
let target' ← resolveStmtExpr target
459-
let callee' ← resolveRef callee source
483+
-- Look up under the container-scoped key matching `preRegisterTopLevel`.
484+
-- Fall back to the bare name when the target's type can't be determined.
485+
let lookupKey ← match (← targetTypeName target') with
486+
| some tyName => pure (containerScopedName (mkId tyName) callee)
487+
| none => pure callee
488+
let resolved ← resolveRef lookupKey source
460489
(expected := #[.instanceProcedure, .staticProcedure])
490+
-- Preserve the user-facing callee text for diagnostics;
491+
-- only stamp the resolved `uniqueId` from the lifted lookup.
492+
let callee' := { callee with uniqueId := resolved.uniqueId }
461493
let args' ← args.mapM resolveStmtExpr
462494
pure (.InstanceCall target' callee' args')
463495
| .Quantifier mode param trigger body =>
@@ -557,7 +589,9 @@ def resolveField (ownerName : Identifier) (field : Field) : ResolveM Field := do
557589

558590
/-- Resolve an instance procedure on a composite type. -/
559591
def resolveInstanceProcedure (typeName : Identifier) (proc : Procedure) : ResolveM Procedure := do
560-
let procName' ← resolveRef proc.name
592+
let scopedKey := containerScopedName typeName proc.name
593+
let resolved ← resolveRef scopedKey
594+
let procName' := { proc.name with uniqueId := resolved.uniqueId }
561595
withScope do
562596
let savedInstType := (← get).instanceTypeName
563597
modify fun s => { s with instanceTypeName := some typeName.text }
@@ -955,7 +989,9 @@ private def preRegisterTopLevel (program : Program) : ResolveM Unit := do
955989
let qualifiedName := ct.name.text ++ "." ++ field.name.text
956990
let _ ← defineNameCheckDup field.name (.field ct.name field) (some qualifiedName)
957991
for proc in ct.instanceProcedures do
992+
let scopedKey := (containerScopedName ct.name proc.name).text
958993
let _ ← defineNameCheckDup proc.name (.instanceProcedure ct.name proc)
994+
(some scopedKey)
959995
| .Constrained ct =>
960996
let _ ← defineNameCheckDup ct.name (.constrainedType ct)
961997
| .Datatype dt =>
@@ -989,15 +1025,6 @@ private def preRegisterTopLevel (program : Program) : ResolveM Unit := do
9891025
public def resolve (program : Program) (existingModel: Option SemanticModel := none) : ResolutionResult :=
9901026
-- Phase 1: pre-register all top-level names, then assign IDs and resolve references
9911027
let phase1 : ResolveM Program := do
992-
993-
for td in program.types do
994-
if let .Composite ct := td then
995-
for proc in ct.instanceProcedures do
996-
let diag := diagnosticFromSource proc.name.source
997-
s!"Instance procedure '{proc.name.text}' on composite type '{ct.name.text}' is not yet supported"
998-
DiagnosticType.NotYetImplemented
999-
modify fun s => { s with errors := s.errors.push diag }
1000-
10011028
preRegisterTopLevel program
10021029
let types' ← program.types.mapM resolveTypeDefinition
10031030
let constants' ← program.constants.mapM resolveConstant

StrataTest/Languages/Laurel/DuplicateNameTests.lean

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,10 +61,8 @@ procedure foo(x: int, x: bool) opaque { };
6161
program Laurel;
6262
composite Foo {
6363
procedure bar() opaque { };
64-
// ^^^ not-yet-implemented: Instance procedure 'bar' on composite type 'Foo' is not yet supported
6564
procedure bar() opaque { };
66-
// ^^^ not-yet-implemented: Instance procedure 'bar' on composite type 'Foo' is not yet supported
67-
// ^^^ error: Duplicate definition 'bar' is already defined in this scope
65+
// ^^^ error: Duplicate definition 'Foo$bar' is already defined in this scope
6866
}
6967
#end
7068

0 commit comments

Comments
 (0)