language: the rule for a prelude name that collides with an imported name #50
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Context
If an imported name and a prelude name collide, adding to the prelude breaks programs. The answer decides whether the prelude may grow in a minor release. A 1.0 blocker.
Source
Acceptance criteria
Dependencies
None known.
Moved from the planning lists of the docs; the design record stays the specification.
[loop:torbscript] intake: in scope (author orion, label loop), source RELEASE.md 1.0 list, not a duplicate. It decides a language rule (prelude name vs imported name), so refine has to read CONCEPT and the language reference first; the loop decides the technical design itself and escalates only if the rule changes a published contract. next: refine, waiting (ready buffer full: #4, #163, #164, #223 are ready) until 2026-10-10T04:00:00Z
[loop:torbscript] claim refine by session:loop-torbscript-20261012 until 2026-10-12T18:08Z
[loop:torbscript] decided by the loop: the prelude ranks below everything a file wrote or imported, in every lookup. A new prelude name, member or trait can then never break or silently change a program, so the prelude may grow in a minor release (additions only, as RELEASE.md section 3 already promises for
std).What the checker does today (read from
maind679af0e)Binder.addPreludes(compiler/src/semantics/scope.trb) adds a prelude name only if the file has none of that name; TYPECHECKER 3.1 puts "file scope" (own declarations and imports) before "prelude", andcheck.test.trbhas "a declaration of the file shadows the prelude". So a prelude that gainsSlugnever touches a file that declares or imports its ownSlug. Bare cases are ranked the same way (CLOSED-TRAITS decision 6.2: "the prelude comes after the cases").closures.test.trb~211); the bare name never reads the function type. TYPECHECKER 3.1 still says it is an error, which is stale.public use Int64.seconds from "std/time") andaddPreludesmerges them into every file's member imports.extensionMember(checker/member.trb) then treats a prelude-reached extension and a file-imported one as equals: the same member name for the same type is`shout` comes from `a` and from `b`at the use, and a more specific extension wins silently. So (1) if the prelude gainsString.shoutand the file importsString.shout from "acme/text", the program stops compiling, and (2) if the prelude gains aList-specific member while the file uses its ownextend<Item> Iterate<Item>member of that name, the call silently changes meaning. The same tie exists for the members of a trait the prelude names and one the file names.The rule
mof a type, candidates come in two classes: written or named by the file (an extension of the receiver's own package, an extension reached through the file's ownuseof a module or a member import, a trait the file names) and reached only through the prelude (a prelude re-export of a foreign-type extension, a trait that only the prelude names). A candidate of the first class always beats one of the second, whatever their specificity. Inside a class the current rules stay: the more specific extension wins, otherwise the ambiguity error at the use withasas the fix.stdand wait for a major (RELEASE.md section 3).Why this and not the alternatives: an error for every collision would make every prelude addition a breaking change (the exact problem of #50); "prelude wins" would take away the names a user wrote; keeping specificity first leaves case (2) as a silent behaviour change, which is worse than an error. The rule is a loosening: a program that compiled today means the same afterwards, except where a file-written member now beats a more specific prelude-only one; nothing in
std/orcompiler/is allowed to change meaning (the gates show it). No published contract with real users is broken (0.x), and no design record reserves this for the owner, so the loop decides; the PR review stays the veto point.Definition of ready
stdrow: "The prelude rule of section 2 decides how far additions only reaches for the prelude"); CLOSED-TRAITS 6.2; CONCEPT "Imports" (the extend-visibility bullets and the prelude bullet).extensionMemberandtraitMembers(compiler/src/semantics/checker/member.trb) rank file-written/named candidates above prelude-only ones, then apply specificity, then the ambiguity error. The provenance of a candidate is derived inchecker/implementation.trb(visibleModulesOf, which today merges the prelude's modules and the imported ones; a module reached both ways counts as the file's).compiler/tests/implementations.test.trb("The visibility of anextend") andcheck.test.trb: (a) a prelude gainingString.shoutand a file importingString.shoutfrom another package: no error, the file's member is used; (b) a preludeList-specific member and a file'sIterateextension of the same name: the file's is used, and the answer does not depend on whether the prelude has the member; (c) two prelude-only candidates and two file-class candidates still report the ambiguity; (d) names: a file declaring or importingXwhile the prelude gainsXis unchanged (declaration, import,asrename, bare case position); (e) a trait named by the file and one named only by the prelude with the same member.stdrow, the ROADMAP row of #50 (remove from "designed and not built", milestone 8 text), and any generatedskills/(torb docs skill docs skills,--checkis a tier A gate).torb lint: the existing rule warning about a declaration that shadows a prelude name is not extended here (follow-up only if one is missing; not part of this PR).std/,compiler/orexamples/(the suite and the fixpoint compare show it). If some std code does depend on specificity beating provenance, stop and record the case in the PR instead of special-casing it.feat(checker): rank file members above prelude members(code and tests) anddocs: the prelude rule for collisions(reference, RELEASE, ROADMAP, regenerated skills).[loop:torbscript] refine: rule decided (the prelude ranks below everything a file wrote or imported, for names and members), acceptance criteria, tests and docs listed, no seed impact, one PR; label
readyset. Tokens: about 130k. next: implement[loop:torbscript] claim implement by session:loop-torbscript-20261012 until 2026-10-12T22:14Z
[loop:torbscript] release implement: the worker was terminated by a gateway restart before pushing anything; nothing to keep, restarting implementation.
[loop:torbscript] claim implement by session:loop-torbscript-20261012 until 2026-10-12T22:22Z
[loop:torbscript] implement: PR #346 is open and forge CI is green (gates, tier A); the worker ended on a usage limit after pushing. next: waiting (merge gate review of PR #346)