From a4cc1487c4a825fd0c4c7ed7510eb07744af4931 Mon Sep 17 00:00:00 2001 From: bQUARKz Date: Tue, 10 Feb 2026 20:03:03 +0000 Subject: [PATCH] pr 03.04 --- crates/frontend-api/src/types.rs | 25 +++- .../src/backend/emit_bytecode.rs | 9 +- .../src/frontends/pbs/lowering.rs | 4 +- crates/prometeu-compiler/src/ir_core/instr.rs | 4 +- crates/prometeu-compiler/src/ir_vm/instr.rs | 6 + .../src/lowering/core_to_vm.rs | 3 +- files/Hard Reset FE API.md | 123 +----------------- test-cartridges/canonical/golden/program.pbc | Bin 629 -> 629 bytes 8 files changed, 48 insertions(+), 126 deletions(-) diff --git a/crates/frontend-api/src/types.rs b/crates/frontend-api/src/types.rs index 80aa83ef..9ecc994b 100644 --- a/crates/frontend-api/src/types.rs +++ b/crates/frontend-api/src/types.rs @@ -192,17 +192,32 @@ impl ExportRef { } } -/// Canonical function key, identifying an overload by arity only (for now). -/// This will be extended in PR-03.04 with types and calling convention. +/// Canonical function identity. +/// +/// JVM-like canonical pieces to uniquely identify an overload across projects: +/// - `owner`: optional service/type name for methods (e.g., `Some("Log")`) or `None` for free fns +/// - `name`: unqualified function/method name (e.g., `"debug"`) +/// - `sig`: canonical signature id produced by the frontend #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[derive(Debug, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)] pub struct CanonicalFnKey { - pub import: ImportRef, - pub arity: u16, + pub owner: Option, + pub name: ItemName, + pub sig: SignatureRef, } impl CanonicalFnKey { - pub fn new(import: ImportRef, arity: u16) -> Self { Self { import, arity } } + pub fn new(owner: Option, name: ItemName, sig: SignatureRef) -> Self { + Self { owner, name, sig } + } + + /// Returns a human-friendly display name like "Log.debug" or just "debug". + pub fn debug_name(&self) -> String { + match &self.owner { + Some(o) => format!("{}.{}", o.as_str(), self.name.as_str()), + None => self.name.as_str().to_string(), + } + } } /// Opaque canonical reference to a type known to the Frontend. diff --git a/crates/prometeu-compiler/src/backend/emit_bytecode.rs b/crates/prometeu-compiler/src/backend/emit_bytecode.rs index 124f2bd0..f5f3e21b 100644 --- a/crates/prometeu-compiler/src/backend/emit_bytecode.rs +++ b/crates/prometeu-compiler/src/backend/emit_bytecode.rs @@ -293,8 +293,13 @@ impl BytecodeEmitter { stack_height = (stack_height - (*arg_count as i32)).max(0); } } - InstrKind::ImportCall { dep_alias, module_path, base_name, sig, arg_count } => { - let label = format!("@{}::{}:{}#sig{}", dep_alias, module_path, base_name, sig.0); + InstrKind::ImportCall { dep_alias, module_path, owner, base_name, sig, arg_count } => { + let display_name = if let Some(o) = owner { + format!("{}.{}", o, base_name) + } else { + base_name.clone() + }; + let label = format!("@{}::{}:{}#sig{}", dep_alias, module_path, display_name, sig.0); asm_instrs.push(Asm::Op(OpCode::Call, vec![Operand::Label(label)])); stack_height = (stack_height - (*arg_count as i32)).max(0); } diff --git a/crates/prometeu-compiler/src/frontends/pbs/lowering.rs b/crates/prometeu-compiler/src/frontends/pbs/lowering.rs index 6a805375..17d49756 100644 --- a/crates/prometeu-compiler/src/frontends/pbs/lowering.rs +++ b/crates/prometeu-compiler/src/frontends/pbs/lowering.rs @@ -1160,6 +1160,7 @@ impl<'a> Lowerer<'a> { self.emit(InstrKind::ImportCall { dep_alias, module_path, + owner: None, base_name, sig, arg_count: n.args.len() as u32, @@ -1385,10 +1386,11 @@ impl<'a> Lowerer<'a> { }; if let Some(sig) = sig_opt { - let base_name = format!("{}.{}", obj_name, member_name); + let base_name = member_name.to_string(); self.emit(InstrKind::ImportCall { dep_alias, module_path, + owner: Some(obj_name.to_string()), base_name, sig, arg_count: n.args.len() as u32, diff --git a/crates/prometeu-compiler/src/ir_core/instr.rs b/crates/prometeu-compiler/src/ir_core/instr.rs index ee18dac9..8c7e836a 100644 --- a/crates/prometeu-compiler/src/ir_core/instr.rs +++ b/crates/prometeu-compiler/src/ir_core/instr.rs @@ -24,10 +24,12 @@ pub enum InstrKind { /// Placeholder for function calls. Call(FunctionId, u32), /// External calls (imports). - /// Carries dependency alias, module path, base function name, precise signature id, and arg count. + /// Carries dependency alias, module path, optional owner (service), base function name, + /// precise signature id, and arg count. ImportCall { dep_alias: String, module_path: String, + owner: Option, base_name: String, sig: SigId, arg_count: u32, diff --git a/crates/prometeu-compiler/src/ir_vm/instr.rs b/crates/prometeu-compiler/src/ir_vm/instr.rs index 00f90153..cf270a21 100644 --- a/crates/prometeu-compiler/src/ir_vm/instr.rs +++ b/crates/prometeu-compiler/src/ir_vm/instr.rs @@ -134,7 +134,11 @@ pub enum InstrKind { ImportCall { dep_alias: String, module_path: String, + /// Optional service/type owner for methods (e.g., "Log"). `None` for free functions. + owner: Option, + /// Unqualified function/method name (e.g., "debug"). base_name: String, + /// Exact signature id selected by the frontend. sig: SigId, arg_count: u32, }, @@ -249,6 +253,7 @@ mod tests { InstrKind::ImportCall { dep_alias: "std".to_string(), module_path: "math".to_string(), + owner: None, base_name: "abs".to_string(), sig: SigId(1), arg_count: 1, @@ -343,6 +348,7 @@ mod tests { "ImportCall": { "dep_alias": "std", "module_path": "math", + "owner": null, "base_name": "abs", "sig": 1, "arg_count": 1 diff --git a/crates/prometeu-compiler/src/lowering/core_to_vm.rs b/crates/prometeu-compiler/src/lowering/core_to_vm.rs index 238e6ac9..a3cb883e 100644 --- a/crates/prometeu-compiler/src/lowering/core_to_vm.rs +++ b/crates/prometeu-compiler/src/lowering/core_to_vm.rs @@ -124,7 +124,7 @@ pub fn lower_function( arg_count: *arg_count }, None)); } - ir_core::InstrKind::ImportCall { dep_alias, module_path, base_name, sig, arg_count } => { + ir_core::InstrKind::ImportCall { dep_alias, module_path, owner, base_name, sig, arg_count } => { // Pop arguments from type stack for _ in 0..*arg_count { stack_types.pop(); @@ -133,6 +133,7 @@ pub fn lower_function( vm_func.body.push(ir_vm::Instruction::new(ir_vm::InstrKind::ImportCall { dep_alias: dep_alias.clone(), module_path: module_path.clone(), + owner: owner.clone(), base_name: base_name.clone(), sig: *sig, arg_count: *arg_count, diff --git a/files/Hard Reset FE API.md b/files/Hard Reset FE API.md index a33d03f3..b2c87d29 100644 --- a/files/Hard Reset FE API.md +++ b/files/Hard Reset FE API.md @@ -4,112 +4,13 @@ > > Strategy: **surgical PRs** that (1) stop PBS types from leaking, (2) replace stringy protocols with canonical models, and (3) make imports/exports/overloads deterministic across deps. ---- +# Notes / Operating Rules (for Junie) -## PR-03.03 — Canonical import syntax → `ImportRef` (no dual styles) - -### Title - -Define single canonical import model and parse PBS imports into `ImportRef` - -### Briefing / Context - -We currently support multiple synthetic import path styles (`"alias/module"` and `"@alias:module"`). This amplifies ambiguity and is a root cause of mismatch in imported service method overloads. - -We want **one** canonical representation: - -* PBS syntax: `import { Test } from "@sdk:input/testing"` -* Canonical model: `ImportRef { project: "sdk", module: "input/testing", item: "Test" }` - -### Target - -* PBS FE produces a list of canonical `ImportRef`. -* BE consumes only `ImportRef`. -* Remove support for dual synthetic path style in the BE pipeline. - -### Scope - -* In PBS FE: - - * Parse `@:` into `ImportRef`. - * Validate module path normalization. - * Validate that `item` is a single symbol name (service/struct/host/contract/etc). -* In BE: - - * Replace “synthetic path generation” with canonical module lookup using `(alias, module_path)`. - -### Out of scope - -* Export naming canonicalization (PR-03.04/03.05). - -### Checklist - -* [ ] Implement import parser → `ImportRef`. -* [ ] Remove `alias/module` synthetic path support. -* [ ] Update resolver/module-provider lookup to accept `(alias, module_path)`. -* [ ] Add diagnostics for invalid import string. - -### Tests - -* Unit tests in PBS FE for: - - * valid: `"@sdk:input/testing"` - * invalid forms - * normalization edge cases (leading `/`, `./`, `\\` on Windows paths) -* Integration test (golden-style) compiling a small project importing a service. - -### Risk - -Medium. Changes import resolution plumbing. - ---- - -## PR-03.04 — Canonical function identity: `CanonicalFnKey` (JVM-like) - -### Title - -Introduce canonical function identity for exports/import calls (no string prefix matching) - -### Briefing / Context - -Phase 03 currently tries to match overloads using `name#sigN` strings + prefix logic + origin checks. This breaks easily and is exactly what produced `E_OVERLOAD_NOT_FOUND` for `Log.debug`. - -We need a **canonical function key** that is not “string protocol”: - -* `CanonicalFnKey { owner: Option, name: ItemName, sig: SigId }` - - * Free fn: `owner=None, name=foo, sig=...` - * Service method: `owner=Some(Log), name=debug, sig=...` - -### Target - -* BE uses `CanonicalFnKey` for export surface and import relocation. -* FE supplies `owner/name` and produces/requests signatures deterministically. - -### Scope - -* Add `CanonicalFnKey` to `frontend-api`. -* Update VM import call instruction payload to carry canonical pieces: - - * `ImportCall { dep_alias, module_path, fn_key: CanonicalFnKey, arg_count }` - * (or equivalent) -* Eliminate string matching / prefix matching for overload selection. - -### Checklist - -* [ ] Define `CanonicalFnKey` and helpers. -* [ ] Update IR / bytecode instruction structures if needed. -* [ ] Update lowering call sites. -* [ ] Ensure debug info keeps readable names (owner.name). - -### Tests - -* Unit: canonical formatting for debug name `Log.debug`. -* Integration: two overloads of `Log.debug` across deps resolved by exact signature. - -### Risk - -High-ish. Touches instruction encoding and matching logic. +1. **BE is the source of truth**: `frontend-api` defines canonical models; FE conforms. +2. **No string protocols** across layers. Strings may exist only as *display/debug*. +3. **No FE implementation imports from other FE implementations**. +4. **No BE imports PBS modules** (hard boundary). +5. **Overload resolution is signature-based** (arity alone is not valid). --- @@ -240,14 +141,4 @@ After canonical models are in place, we must delete compatibility code paths (`a ### Risk -Low/Medium. Mostly deletion + docs, but could expose hidden dependencies. - ---- - -# Notes / Operating Rules (for Junie) - -1. **BE is the source of truth**: `frontend-api` defines canonical models; FE conforms. -2. **No string protocols** across layers. Strings may exist only as *display/debug*. -3. **No FE implementation imports from other FE implementations**. -4. **No BE imports PBS modules** (hard boundary). -5. **Overload resolution is signature-based** (arity alone is not valid). +Low/Medium. Mostly deletion + docs, but could expose hidden dependencies. \ No newline at end of file diff --git a/test-cartridges/canonical/golden/program.pbc b/test-cartridges/canonical/golden/program.pbc index 3646ac8573f5be88286c9c5f6abe6e09b079a715..5a70490d7e7f3a43ff64e865774031b80c27af1b 100644 GIT binary patch delta 25 dcmey$@|9(SAJgP$CMjM9AYcXJw4%h^Q~+Fo1{weW delta 21 ccmey$@|9(S9}_1l0|P@^QDScDWG^N;07?P|2><{9