pr 21
This commit is contained in:
parent
fe00eda925
commit
603c8e7862
@ -135,9 +135,9 @@ impl<'a> Lowerer<'a> {
|
||||
Node::Unary(n) => self.lower_unary(n),
|
||||
Node::IfExpr(n) => self.lower_if_expr(n),
|
||||
Node::Alloc(n) => self.lower_alloc(n),
|
||||
Node::Mutate(n) => self.lower_hip(n.span, &n.target, &n.binding, &n.body, "mutate"),
|
||||
Node::Borrow(n) => self.lower_hip(n.span, &n.target, &n.binding, &n.body, "borrow"),
|
||||
Node::Peek(n) => self.lower_hip(n.span, &n.target, &n.binding, &n.body, "peek"),
|
||||
Node::Mutate(n) => self.lower_mutate(n),
|
||||
Node::Borrow(n) => self.lower_borrow(n),
|
||||
Node::Peek(n) => self.lower_peek(n),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
@ -149,44 +149,83 @@ impl<'a> Lowerer<'a> {
|
||||
self.emit(Instr::Alloc { ty: TypeId(0), slots: 1 });
|
||||
}
|
||||
|
||||
fn lower_hip(&mut self, _span: crate::common::spans::Span, target: &Node, binding: &str, body: &Node, op: &str) {
|
||||
// HIP Access Pattern (Explicit Semantics):
|
||||
fn lower_peek(&mut self, n: &PeekNode) {
|
||||
// 1. Evaluate target (gate)
|
||||
self.lower_node(target);
|
||||
self.lower_node(&n.target);
|
||||
|
||||
// 2. Preserve gate identity.
|
||||
// We MUST NOT lose the gate, as storage access must be mediated by it.
|
||||
// 2. Preserve gate identity
|
||||
let gate_slot = self.get_next_local_slot();
|
||||
self.local_vars.last_mut().unwrap().insert(format!("$gate_{}", gate_slot), gate_slot);
|
||||
self.emit(Instr::SetLocal(gate_slot));
|
||||
|
||||
// 3. Begin Operation.
|
||||
// This instruction reads the gate from the local and pushes a view.
|
||||
let instr = match op {
|
||||
"peek" => Instr::BeginPeek { gate: ValueId(gate_slot) },
|
||||
"borrow" => Instr::BeginBorrow { gate: ValueId(gate_slot) },
|
||||
"mutate" => Instr::BeginMutate { gate: ValueId(gate_slot) },
|
||||
_ => unreachable!(),
|
||||
};
|
||||
self.emit(instr);
|
||||
// 3. Begin Operation
|
||||
self.emit(Instr::BeginPeek { gate: ValueId(gate_slot) });
|
||||
|
||||
// 4. Bind view to local
|
||||
self.local_vars.push(HashMap::new());
|
||||
let view_slot = self.get_next_local_slot();
|
||||
self.local_vars.last_mut().unwrap().insert(binding.to_string(), view_slot);
|
||||
self.local_vars.last_mut().unwrap().insert(n.binding.to_string(), view_slot);
|
||||
self.emit(Instr::SetLocal(view_slot));
|
||||
|
||||
// 5. Body
|
||||
self.lower_node(body);
|
||||
self.lower_node(&n.body);
|
||||
|
||||
// 6. End Operation
|
||||
let end_instr = match op {
|
||||
"peek" => Instr::EndPeek,
|
||||
"borrow" => Instr::EndBorrow,
|
||||
"mutate" => Instr::EndMutate,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
self.emit(end_instr);
|
||||
self.emit(Instr::EndPeek);
|
||||
|
||||
self.local_vars.pop();
|
||||
}
|
||||
|
||||
fn lower_borrow(&mut self, n: &BorrowNode) {
|
||||
// 1. Evaluate target (gate)
|
||||
self.lower_node(&n.target);
|
||||
|
||||
// 2. Preserve gate identity
|
||||
let gate_slot = self.get_next_local_slot();
|
||||
self.local_vars.last_mut().unwrap().insert(format!("$gate_{}", gate_slot), gate_slot);
|
||||
self.emit(Instr::SetLocal(gate_slot));
|
||||
|
||||
// 3. Begin Operation
|
||||
self.emit(Instr::BeginBorrow { gate: ValueId(gate_slot) });
|
||||
|
||||
// 4. Bind view to local
|
||||
self.local_vars.push(HashMap::new());
|
||||
let view_slot = self.get_next_local_slot();
|
||||
self.local_vars.last_mut().unwrap().insert(n.binding.to_string(), view_slot);
|
||||
self.emit(Instr::SetLocal(view_slot));
|
||||
|
||||
// 5. Body
|
||||
self.lower_node(&n.body);
|
||||
|
||||
// 6. End Operation
|
||||
self.emit(Instr::EndBorrow);
|
||||
|
||||
self.local_vars.pop();
|
||||
}
|
||||
|
||||
fn lower_mutate(&mut self, n: &MutateNode) {
|
||||
// 1. Evaluate target (gate)
|
||||
self.lower_node(&n.target);
|
||||
|
||||
// 2. Preserve gate identity
|
||||
let gate_slot = self.get_next_local_slot();
|
||||
self.local_vars.last_mut().unwrap().insert(format!("$gate_{}", gate_slot), gate_slot);
|
||||
self.emit(Instr::SetLocal(gate_slot));
|
||||
|
||||
// 3. Begin Operation
|
||||
self.emit(Instr::BeginMutate { gate: ValueId(gate_slot) });
|
||||
|
||||
// 4. Bind view to local
|
||||
self.local_vars.push(HashMap::new());
|
||||
let view_slot = self.get_next_local_slot();
|
||||
self.local_vars.last_mut().unwrap().insert(n.binding.to_string(), view_slot);
|
||||
self.emit(Instr::SetLocal(view_slot));
|
||||
|
||||
// 5. Body
|
||||
self.lower_node(&n.body);
|
||||
|
||||
// 6. End Operation
|
||||
self.emit(Instr::EndMutate);
|
||||
|
||||
self.local_vars.pop();
|
||||
}
|
||||
@ -525,6 +564,45 @@ mod tests {
|
||||
assert!(!json.contains("WriteGate"), "WriteGate should be gone");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_hip_semantics_distinction() {
|
||||
let code = "
|
||||
fn test_hip(g: int) {
|
||||
peek g as p {
|
||||
let x = p;
|
||||
}
|
||||
borrow g as b {
|
||||
let y = b;
|
||||
}
|
||||
mutate g as m {
|
||||
let z = m;
|
||||
}
|
||||
}
|
||||
";
|
||||
let mut parser = Parser::new(code, 0);
|
||||
let ast = parser.parse_file().expect("Failed to parse");
|
||||
|
||||
let mut collector = SymbolCollector::new();
|
||||
let (type_symbols, value_symbols) = collector.collect(&ast).expect("Failed to collect symbols");
|
||||
let module_symbols = ModuleSymbols { type_symbols, value_symbols };
|
||||
|
||||
let lowerer = Lowerer::new(&module_symbols);
|
||||
let program = lowerer.lower_file(&ast, "test");
|
||||
|
||||
let func = &program.modules[0].functions[0];
|
||||
let instrs: Vec<_> = func.blocks.iter().flat_map(|b| b.instrs.iter()).collect();
|
||||
|
||||
// Assert distinct Core IR instruction sequences
|
||||
assert!(instrs.iter().any(|i| matches!(i, Instr::BeginPeek { .. })));
|
||||
assert!(instrs.iter().any(|i| matches!(i, Instr::EndPeek)));
|
||||
|
||||
assert!(instrs.iter().any(|i| matches!(i, Instr::BeginBorrow { .. })));
|
||||
assert!(instrs.iter().any(|i| matches!(i, Instr::EndBorrow)));
|
||||
|
||||
assert!(instrs.iter().any(|i| matches!(i, Instr::BeginMutate { .. })));
|
||||
assert!(instrs.iter().any(|i| matches!(i, Instr::EndMutate)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_host_contract_call_lowering() {
|
||||
let code = "
|
||||
|
||||
@ -1,32 +1,3 @@
|
||||
# PR-21 — Distinguish `peek`, `borrow`, and `mutate` in Core IR
|
||||
|
||||
### Goal
|
||||
|
||||
Restore the semantic distinction mandated by PBS.
|
||||
|
||||
### Required Semantics
|
||||
|
||||
| Operation | Effect |
|
||||
| --------- | ------------------------------- |
|
||||
| `peek` | Copy storage → stack value |
|
||||
| `borrow` | Temporary read-only view |
|
||||
| `mutate` | Temporary mutable view + commit |
|
||||
|
||||
### Required Changes
|
||||
|
||||
* Lower PBS `peek` → `BeginPeek` / `EndPeek`
|
||||
* Lower PBS `borrow` → `BeginBorrow` / `EndBorrow`
|
||||
* Lower PBS `mutate` → `BeginMutate` / `EndMutate`
|
||||
|
||||
These **must not** share the same lowering path.
|
||||
|
||||
### Tests
|
||||
|
||||
* PBS snippet with all three operations
|
||||
* Assert distinct Core IR instruction sequences
|
||||
|
||||
---
|
||||
|
||||
# PR-22 — Make Allocation Shape Explicit in Core IR
|
||||
|
||||
### Goal
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user