Repository navigation
t27c: the use splice reads a name inside a pulled declaration in that declaration's module (Closes #10556) - #11012
Merged
Merged
Conversation
… declaration's module; the rule is specs/compiler/use_splice.t27 (Closes #10556) Two imported modules that each declare one helper name made the splice drop both, so a pulled fn called a helper the generated file never declared. A name found inside a pulled declaration now resolves against the module whose text names it (its own declaration, else the one its direct imports make) when the whole closure cannot answer it; both copies are spliced under <module path>__<name> and the uses are renamed. A qualified reference the importer writes is read in the module it names. A bare name the importer writes stays UNRESOLVED. The rule, the old all_agree/normalised/without_comment and alias_target are specs/compiler/use_splice.t27, lowered by t27c gen-rust to bootstrap/gen/rust/compiler/use_splice.rs and mounted by #[path]; the hand Rust in use_resolve.rs shrinks. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…e pass in use_splice.t27 renames scoped helpers and strips imported paths (Closes #10556) compound_binop, pulled from operator_text into a converted compiler.rs, kept `type_text::same`; the flat file declared no `type_text`, so `tri t27o --check` stopped on it (BLOCKED, undeclared identifier). The importer's own paths were always flattened; pulled ones were not. use_splice.rewrite now strips `stem::` in a pulled text when the stem is a module that text's module imports, and applies the scoped renames in the same pass. rename_ident is folded into it. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…es; seal use_splice.t27 (Closes #10556) rewrite takes the names the splice pulled and strips `stem::name` in a pulled text only for those, so a path to a type the backends spell themselves (gf16::GF16) is left alone. The seal of specs/compiler/use_splice.t27 is saved with the final spec (23 tests). Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Closes #10556) Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Contributor
gHashTag
marked this pull request as ready for review
October 19, 2026 11:39
This was referenced Oct 19, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #10556. Unblocks the
same/type_textpart of epic #10879 ("t27b for t27o").What was wrong
use_resolve.rskeys every imported declaration by bare name. When two imported modules declared one name differently it refused both (// UNRESOLVED <name> ... ambiguous) and pulled neither. That is right for a name the importer wrote and wrong for a name found inside a pulled declaration:admitin service.t27 callsname_ok, and the onlyname_okits author can mean is the one in service.t27.t27c genstill exited 0 and the generated file called a function it never declared.A second defect sat on the same path and is what actually stopped
tri t27o bootstrap/src/compiler.rs --check: a path inside a pulled declaration (type_text::sameincompound_binop, pulled from operator_text) kept itstype_text::. The importer's own paths were always flattened (#5574); pulled ones were not, so the flat file declaredsameand calledtype_text.same. This one needs no ambiguity at all.The rule, and where it lives
specs/compiler/use_splice.t27(new; no spec for use resolution existed:git grep "UNRESOLVED|ambiguous" specsfinds comments only).t27c gen-rustwritesbootstrap/gen/rust/compiler/use_splice.rs(byte-equal to a regeneration), whichuse_resolve.rsmounts by#[path], as compiler.rs mounts operator_text. Five rules, each with tests:scope_index).<module path>__<name>(flat_name) and the uses in that module's texts are rewritten (rewrite). A qualified reference the importer writes (beta::name_ok) is read in beta.stem::namelosesstem::when the stem is a module that text's module imports and the splice pulledname. A path to a name not pulled (gf16::GF16) is left alone.Also moved into the spec, line for line:
all_agree/normalised/without_comment(nowsame_decl) andalias_target(nowalias_class), so the hand Rust shrinks.t27b needs no change:
cli/t27b/src/front.rscalls the sameuse_resolve::resolve(mounted by#[path]). Measured:t27b teston the issue's importer printsPASS importer: serveswith the branch; the base t27b saysunsupported construct ExprCall(undeclared fn) ... call to name_ok.specs/compiler/core/t27core.t27keeps refusing a name two modules declare (E_USE, #7939); that is conservative, not a mismatch, and it is untouched.Hand-written lines (own-language gate)
The gate compiled from the merge base's
gen/c/policy/own_language.cand fedgit diff --numstat --no-renames BASE...HEAD: rc=0 (per file <= 40, total <= 80, net <= 0). FROZEN_HASH is untouched: compiler.rs is not edited.bootstrap/gen/is gitignored, so the generated file needsgit add -f.Generated output that changed
gen,gen-rust,gen-c,gen-verilogover every spec with auseline (756, the new spec aside), merge-base t27c against this branch's: 20 differ, 736 are byte-identical.gen-verilogis identical for all. UNRESOLVED lines in the corpus go from 20 to 9; the 9 left are names the importer writes itself (R4) or two modules' real disagreement. None of the 20 compiled in Zig before and none stopped compiling; the error count never rises (it falls in 6) and the first error changes in 5.Had an UNRESOLVED line (11), before -> after:
constants.abs(jones - PHI), UNRESOLVED absmath_constants__abs(jones - PHI), no UNRESOLVEDconstants.abs(...)math_constants__abs(...); UNRESOLVED abs stays (importer writes it)[_]TernaryWord{ operand_a }, UNRESOLVED TernaryWord, pack_trit[_]fpga_mac__TernaryWord{ ... },fpga_mac__pack_trit, none left[_]TernaryWord{ ... }, 2 UNRESOLVEDfpga_mac__TernaryWord; 1 left (importer writes TernaryWord)eval.check_sacred_compliance(verilog), 5 UNRESOLVEDigla_coder_eval__check_sacred_compliance(verilog); 1 left (BeamCandidate)sacred_physics.TRINITY, UNRESOLVED TRINITYmath_sacred_physics__TRINITY, none leftsacred_physics.TRINITYmath_sacred_physics__TRINITY; UNRESOLVED TRINITY stays (importer writes it)constants.PHIPHI; UNRESOLVED abs staysgf16_decode_to_f32(a)undeclared, 2 UNRESOLVED[]Trit(pulled alias)[]vsa_vsa_core__Trit; UNRESOLVED Trit stays[]Tritin a pulled fnvsa_vsa_core__Trit; UNRESOLVED Trit staysHad no UNRESOLVED line but named an undeclared path (R5, 9): compiler/pipeline (
parser.Node->Node, 45 uses), numeric/gf4, gf8, gf12, gf20, gf24, gf32, gf64 (sacred_physics.PHI_INV->PHI_INV), ml/transformer/mha_block (C and Rust only: undeclaredgf16_GF16-> the declaredGF16).Unchanged and still refused: base_ring_32 (TRINITY), claw/control_pins (COUNT).
Seals
Only the new spec is sealed (
.trinity/seals/compiler_UseSplice.json, 23/23,seal --verifyall MATCH). No existing seal needs re-saving: a seal hashes the unspliced source, so none of the 20 changes moves a gen hash. Measured:t27c seal --verifyover all 756 importing specs prints the same bytes with the merge-base binary and this branch's (0 differ); 19 of the 20 changed specs have seals and all MATCH.tools/check_seal_coverage.pyitself was not run in full (about 2900t27c sealcalls).Tests
specs/compiler/use_splice.t27: 23 tests;t27b test23 passed,t27c test-report23/23, 0 vacuous. They pin each rule, the old agree/alias cases, and negatives (member, comment, string, field, parameter, variant, a path to a name not pulled).bootstrap/tests/unresolved_use.rs, through the shipped binary, with the issue's shape (two modules each declareok, a pulled fn calls its own): both helpers spliced underr_a__ok/r_b__ok, no UNRESOLVED; a qualifiedb::oktakesr_b__ok; negative control: a bareokthe importer writes is still refused (UNRESOLVED ok: declared in r/a.t27 and r/b.t27); a path in a pulled declaration loses its module.cargo test -p t27c --test unresolved_use: 7 passed (4 new).--bin t27c use_resolve: 31 passed (the existingtwo_real_definitions_stay_ambiguousanda_listed_item_two_modules_declare_stays_unresolvedamong them).UNRESOLVED name_okandzig testsaysuse of undeclared identifier 'name_ok'. On the branch: bothrepro_alpha__name_okandrepro_beta__name_okare declared,zig testpasses, and the control file is byte-identical. The real modules (use t27mcp::service::admit; use t27mcp::tool_schema;): baseUNRESOLVED name_okand the same zig error; branch: empty stderr,zig testpasses.tri t27oon the motivating files (branch t27c/t27b/tri, run from a t27 checkout)bootstrap/src/compiler.rs --check: merge baseBLOCKED does not compile: use of undeclared identifier 'type_text'(rc=2; t27b also saidundeclared fn ... type_text::same). Branch: t27b stops only on@max(a t27b gap, not this change), t27c judges: 87 tests, 87 pass, 4 vacuous, rc=0.bootstrap/src/main.rs --check: theUNRESOLVED same(sha256 vs type_text) andtype_texterrors are gone. Still BLOCKED (rc=2) ont27a_ASM_NO_MNEMONICundeclared (the converter writes the Rust patht27a::ASM_NO_MNEMONIC) and t27btrim_end_matches: separate defects, not touched.Traps and what was not run
identifiersreads;prose lines, so a comment in the importer that names the ambiguous name makes it a name the importer wrote. The issue'simporter.t27has one in its header: on the branch its stderr still printsUNRESOLVED name_okalthough the output is right; with that line dropped stderr is empty. Not changed here: it would change the output of specs that resolve today.module::nameinside string literals of the importer, so a test string in a spec that imports type_text cannot containtype_text::same.dupe_scan.pyis red on this branch with 12 copied bodies (at_text, code_at, ..., weight) and on the merge base with the identical 12; this change adds no group.check_devhome_paths.py: OK.cargo test -p t27csuite andcore_selfhost;deterministic_output(1 passed) anddotted_module_name(9 passed) ran on an earlier commit of this branch, not on the final head; the wasm-explorer crate (it mounts use_resolve.rs the way compiler.rs is mounted) was not built;tools/check_seal_coverage.pyin full; the full 2398-spec tree (specs without auseline return fromresolveuntouched).home_ofwithservice::admitinclaw_serves(PR t27f: frontend.t27 -- T27F is t27's frontend, every visual surface in one law, served by TRI CLAW (Closes #10537) #10551's follow-up).🤖 Generated with Claude Code