This commit is contained in:
Nilton Constantino 2026-01-29 17:16:01 +00:00
parent fe00eda925
commit 603c8e7862
No known key found for this signature in database
2 changed files with 104 additions and 55 deletions

View File

@ -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 = "

View File

@ -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