Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -640,6 +640,8 @@ Cleared (prior PR #521): `DerivedOpEffect { method, path_template, shape }` coll

**In progress on the current branch (pending merge):** `src/v3/compiler/src/emit.rs` now exists as the shared emit entrypoint with `EmitTarget`, `EmitMode`, `EmittedSource`, `emit(...)`, and `emit_module(...)`. The first migrated target is **Go**: its hand-written renderer moved under `emit.rs`, and `src/v3/compiler/src/emit_go.rs` is reduced to a compatibility adapter that forwards into the shared path. Coverage is locked by `m1_3_emit_go_test` plus `emit::tests::*`, including a wrapper-parity test proving `emit_go` / `emit_go_module` are thin adapters over the shared entrypoint. The authoritative scaffold receipt now lives in `docs/phase1-lane3-consolidation-build-plan.md` §"Wrapper exception receipt": Go's adapter is allowed only because its body already moved under `emit.rs`; Rust/Python do not get wrapper copies in advance, and all wrappers delete at Stage 1e.6. Follow-up namespace unification moved the remaining per-target monoliths under `src/v3/compiler/src/emit/*_target.rs`, with `emit.rs` staying the single dispatch surface and the old `emit_<target>.rs` files reduced to compatibility adapters only after their bodies moved in the same diff. **Python's Stage 1e.0 bridge is now cleared:** `spec/python.dag` authors shared `LanguageSpec`/`TypeRealization`/`OperatorRealization`/`CallableRealization`/`TypeInstantiationRealization`/`PatternRealization` data, `Dag` caches `python_language` + `python_target`, and `emit/python_target.rs` filters shared realizations by `language: python_language` while loading shared `PatternRealization` for list-pattern lowering. Rust and Python still remain target-monolithic under the shared namespace; full recursive walker unification is still the remaining Stage 1e work.

**Stage 1e.0 closeout — pattern-role authority structural** → ✅ Structurally resolved for the live single-role state (`VectorList` only): list-pattern lowering does not dispatch on a host `PatternStrategy` enum in emitters — each `spec/{rust,go,python}.dag` `*_list_pattern` declares `strategy: VectorList` plus the template bundle; Rust/Go/Python emitters validate that tag fail-closed when indexing realizations and render from the loaded templates only (`src/v3/std/emit_model.dag` documents the split). When a second distinct lowering path ships, restore strategy on the emitter binding and branch in render (still fail-closed from spec rows), and extend `PatternStrategy` + `spec/*.dag` data — YAGNI until then.

### Cross-cutting — performance

**Deferral: self-compile perf ratchet investigation (M, not on any critical path but compounding).** Self-compile time drifted from ~60s to ~70s in recent cycles (~16% growth). The ratchet keeps getting bumped without a root-cause investigation; each bump normalizes the regression. Scope: (1) profile a single `cargo test -p v3-compiler-tests` run, identify the top hot paths; (2) measure where the 10s came from across recent PRs (bisect across #479, #489, #490 if signal is unclear); (3) either fix the regression or document it as an accepted cost with a new ratchet ceiling. **Yellow-flag threshold: 90s.** If self-compile exceeds that before this deferral is scheduled, it preempts other work. No design doc needed; profiling is a data-gathering exercise.
Expand Down
14 changes: 2 additions & 12 deletions src/v3/compiler/src/emit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,14 +83,8 @@ enum CallableStrategyBinding {
ListContains,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum PatternStrategyBinding {
VectorList,
}

#[derive(Debug, Clone)]
struct PatternRealizationBinding {
strategy: PatternStrategyBinding,
scrutinee: String,
empty_pattern: String,
cons_pattern: String,
Expand Down Expand Up @@ -1208,11 +1202,8 @@ impl<'a> Ctx<'a> {
let Some(binding) = self.indexes.patterns.get(&disj_id) else {
return Ok(None);
};
match binding.strategy {
PatternStrategyBinding::VectorList => self
.render_vector_list_pattern_branch(branch, disj_id, binding, locals)
.map(Some),
}
self.render_vector_list_pattern_branch(branch, disj_id, binding, locals)
.map(Some)
}

fn render_vector_list_pattern_branch(
Expand Down Expand Up @@ -2436,7 +2427,6 @@ fn require_pattern_realization(
});
}
Ok(PatternRealizationBinding {
strategy: PatternStrategyBinding::VectorList,
scrutinee: require_field_string(fields, "scrutinee", declaration)?,
empty_pattern: require_field_string(fields, "empty_pattern", declaration)?,
cons_pattern: require_field_string(fields, "cons_pattern", declaration)?,
Expand Down
20 changes: 4 additions & 16 deletions src/v3/compiler/src/emit/python_target.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,14 +122,8 @@ enum PatternBindingRuleBinding {
NotApplicable,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum PatternStrategyBinding {
VectorList,
}

#[derive(Debug, Clone)]
struct PatternRealizationBinding {
strategy: PatternStrategyBinding,
scrutinee: String,
empty_pattern: String,
cons_pattern: String,
Expand Down Expand Up @@ -825,11 +819,8 @@ impl<'a> Ctx<'a> {
let Some(binding) = self.indexes.patterns.get(&disj_id) else {
return Ok(None);
};
match binding.strategy {
PatternStrategyBinding::VectorList => self
.render_vector_list_pattern_branch(branch, disj_id, binding, locals)
.map(Some),
}
self.render_vector_list_pattern_branch(branch, disj_id, binding, locals)
.map(Some)
}

fn render_vector_list_pattern_branch(
Expand Down Expand Up @@ -1596,16 +1587,13 @@ fn parse_pattern_realization(
detail: "PatternStrategy variants must not carry payload",
});
}
let strategy = if constructor == named_variant_id(dag, "PatternStrategy", "VectorList")? {
PatternStrategyBinding::VectorList
} else {
if constructor != named_variant_id(dag, "PatternStrategy", "VectorList")? {
return Err(EmitPythonError::MalformedSpec {
declaration,
detail: "unsupported PatternStrategy variant",
});
};
}
Ok(PatternRealizationBinding {
strategy,
scrutinee: require_field_string(fields, "scrutinee", declaration)?,
empty_pattern: require_field_string(fields, "empty_pattern", declaration)?,
cons_pattern: require_field_string(fields, "cons_pattern", declaration)?,
Expand Down
22 changes: 6 additions & 16 deletions src/v3/compiler/src/emit/rust_target.rs
Original file line number Diff line number Diff line change
Expand Up @@ -301,14 +301,8 @@ impl ParameterDispositionBinding {
}
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum RustPatternStrategyBinding {
VectorList,
}

#[derive(Debug, Clone)]
struct PatternRealizationBinding {
strategy: RustPatternStrategyBinding,
scrutinee: String,
empty_pattern: String,
cons_pattern: String,
Expand Down Expand Up @@ -1987,29 +1981,28 @@ fn require_pattern_realization(
else {
return Err(EmitError::MalformedRealization {
declaration,
detail: "PatternRealization.strategy must be a RustPatternStrategy variant",
detail: "PatternRealization.strategy must be a PatternStrategy variant",
});
};
if !payload.is_empty() {
return Err(EmitError::MalformedRealization {
declaration,
detail: "RustPatternStrategy variants must not carry payload fields",
detail: "PatternStrategy variants must not carry payload fields",
});
}
let vector_list = named_variant_id(dag, "PatternStrategy", "VectorList").ok_or(
EmitError::MalformedRealization {
declaration,
detail: "RustPatternStrategy.VectorList declaration was not found",
detail: "PatternStrategy.VectorList declaration was not found",
},
)?;
if *constructor != vector_list {
return Err(EmitError::MalformedRealization {
declaration,
detail: "RustPatternStrategy constructor must be VectorList",
detail: "PatternStrategy constructor must be VectorList",
});
}
Ok(PatternRealizationBinding {
strategy: RustPatternStrategyBinding::VectorList,
scrutinee: require_field_string(fields, "scrutinee", declaration)?,
empty_pattern: require_field_string(fields, "empty_pattern", declaration)?,
cons_pattern: require_field_string(fields, "cons_pattern", declaration)?,
Expand Down Expand Up @@ -3388,11 +3381,8 @@ impl<'a> Ctx<'a> {
let Some(binding) = self.indexes.patterns.get(&disj_id) else {
return Ok(None);
};
match binding.strategy {
RustPatternStrategyBinding::VectorList => self
.render_vector_list_pattern_branch(branch, disj_id, binding, locals)
.map(Some),
}
self.render_vector_list_pattern_branch(branch, disj_id, binding, locals)
.map(Some)
}

fn render_vector_list_pattern_branch(
Expand Down
1 change: 1 addition & 0 deletions src/v3/spec/go.dag
Original file line number Diff line number Diff line change
Expand Up @@ -794,6 +794,7 @@ data go_contains_callable: CallableRealization = {
cost: 1
}

// List structural-sum → slice carrier; same pattern-role contract as Rust/Python.
data go_list_pattern: PatternRealization = {
language: go_language
target: List
Expand Down
1 change: 1 addition & 0 deletions src/v3/spec/python.dag
Original file line number Diff line number Diff line change
Expand Up @@ -449,6 +449,7 @@ data python_list_instantiation: TypeInstantiationRealization = {
cost: 1
}

// List structural-sum → Python list surface; pattern-role + templates are spec-owned.
data python_list_pattern: PatternRealization = {
language: python_language
target: List
Expand Down
3 changes: 3 additions & 0 deletions src/v3/spec/rust.dag
Original file line number Diff line number Diff line change
Expand Up @@ -881,6 +881,9 @@ data rust_contains_callable: CallableRealization = {
cost: 1
}

// List structural-sum (`Empty`/`Cons`) → carrier patterns. `strategy` is the
// pattern-role tag (validated at emitter load); templates below are the
// emission bundle — no strategy dispatch in emitters post Stage 1e.0.
data rust_list_pattern: PatternRealization = {
language: rust_language
target: List
Expand Down
17 changes: 13 additions & 4 deletions src/v3/std/emit_model.dag
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,12 @@ type CallableStrategy
// `List<T> -> Vec<T>` or `[]T`. The terminal target is the same authority
// expressed as target-language facts consumed by `.dag` emission; this record
// remains the single authority until that stage lands.
//
// **Pattern-role authority (Stage 1e.0):** `strategy` names which lowering
// recipe applies (`VectorList` today). Emitters validate it fail-closed at
// index build and **do not** branch on it when rendering — the role is fully
// expressed by the spec data item (templates + target ref); rendering follows
// that bundle alone.
type PatternRealization {
language: DeclarationRef
target: DeclarationRef
Expand All @@ -124,10 +130,13 @@ type PatternRealization {
cost: Int
}

// Dissolution receipt — 🟡 mixed lifecycle. The current staged emitters need a
// small structural strategy tag to decide which pattern-lowering path to take.
// It dissolves with `PatternRealization` when the emitters themselves become
// data.
// List-pattern role tag — single authority lives in each target's
// `data <target>_list_pattern: PatternRealization` in `spec/*.dag`.
// Emitters map validated records to emission without per-role `match` arms.
//
// `PlaceholderPatternStrategy` keeps the coproduct non-singleton (substrate
// discipline: avoid a one-variant sum) until a second real role lands; it
// then dissolves in favor of that role (e.g. tuple-list lowering).
type PatternStrategy
= PlaceholderPatternStrategy
| VectorList
Expand Down
Loading