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::Unary(n) => self.lower_unary(n),
|
||||||
Node::IfExpr(n) => self.lower_if_expr(n),
|
Node::IfExpr(n) => self.lower_if_expr(n),
|
||||||
Node::Alloc(n) => self.lower_alloc(n),
|
Node::Alloc(n) => self.lower_alloc(n),
|
||||||
Node::Mutate(n) => self.lower_hip(n.span, &n.target, &n.binding, &n.body, "mutate"),
|
Node::Mutate(n) => self.lower_mutate(n),
|
||||||
Node::Borrow(n) => self.lower_hip(n.span, &n.target, &n.binding, &n.body, "borrow"),
|
Node::Borrow(n) => self.lower_borrow(n),
|
||||||
Node::Peek(n) => self.lower_hip(n.span, &n.target, &n.binding, &n.body, "peek"),
|
Node::Peek(n) => self.lower_peek(n),
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -149,44 +149,83 @@ impl<'a> Lowerer<'a> {
|
|||||||
self.emit(Instr::Alloc { ty: TypeId(0), slots: 1 });
|
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) {
|
fn lower_peek(&mut self, n: &PeekNode) {
|
||||||
// HIP Access Pattern (Explicit Semantics):
|
|
||||||
// 1. Evaluate target (gate)
|
// 1. Evaluate target (gate)
|
||||||
self.lower_node(target);
|
self.lower_node(&n.target);
|
||||||
|
|
||||||
// 2. Preserve gate identity.
|
// 2. Preserve gate identity
|
||||||
// We MUST NOT lose the gate, as storage access must be mediated by it.
|
|
||||||
let gate_slot = self.get_next_local_slot();
|
let gate_slot = self.get_next_local_slot();
|
||||||
self.local_vars.last_mut().unwrap().insert(format!("$gate_{}", gate_slot), gate_slot);
|
self.local_vars.last_mut().unwrap().insert(format!("$gate_{}", gate_slot), gate_slot);
|
||||||
self.emit(Instr::SetLocal(gate_slot));
|
self.emit(Instr::SetLocal(gate_slot));
|
||||||
|
|
||||||
// 3. Begin Operation.
|
// 3. Begin Operation
|
||||||
// This instruction reads the gate from the local and pushes a view.
|
self.emit(Instr::BeginPeek { gate: ValueId(gate_slot) });
|
||||||
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);
|
|
||||||
|
|
||||||
// 4. Bind view to local
|
// 4. Bind view to local
|
||||||
self.local_vars.push(HashMap::new());
|
self.local_vars.push(HashMap::new());
|
||||||
let view_slot = self.get_next_local_slot();
|
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));
|
self.emit(Instr::SetLocal(view_slot));
|
||||||
|
|
||||||
// 5. Body
|
// 5. Body
|
||||||
self.lower_node(body);
|
self.lower_node(&n.body);
|
||||||
|
|
||||||
// 6. End Operation
|
// 6. End Operation
|
||||||
let end_instr = match op {
|
self.emit(Instr::EndPeek);
|
||||||
"peek" => Instr::EndPeek,
|
|
||||||
"borrow" => Instr::EndBorrow,
|
self.local_vars.pop();
|
||||||
"mutate" => Instr::EndMutate,
|
}
|
||||||
_ => unreachable!(),
|
|
||||||
};
|
fn lower_borrow(&mut self, n: &BorrowNode) {
|
||||||
self.emit(end_instr);
|
// 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();
|
self.local_vars.pop();
|
||||||
}
|
}
|
||||||
@ -525,6 +564,45 @@ mod tests {
|
|||||||
assert!(!json.contains("WriteGate"), "WriteGate should be gone");
|
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]
|
#[test]
|
||||||
fn test_host_contract_call_lowering() {
|
fn test_host_contract_call_lowering() {
|
||||||
let code = "
|
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
|
# PR-22 — Make Allocation Shape Explicit in Core IR
|
||||||
|
|
||||||
### Goal
|
### Goal
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user