Re-exported extension members cannot be imported through the re-exporting module #182
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?
Problem
A module that re-exports an extension member (
public use List.doubled from "./ext") cannot be imported by name from the outside:use List.doubled from "../src/lib"(or from the package path) fails with "Listis not exported by ..., It is declared there, but notpublic".Cause (reading of
compiler/src/semantics/scope.trb)bindMemberImporthands on the entries of the re-exporting module withentry.copy(span: ...), soentry.pathstays the original"./ext".memberImportOfonly accepts an entry whosepathequals the path written in the importinguse, so the importer's item is not recognized as a member import and falls through to the export check.Reproduction
Package
me/scr:src/ext.trbholdsextend Bytes { fn doubled(): Bytes { ... } },src/lib.trbholdspublic use List.doubled from "./ext", a test doesuse List.doubled from "../src/lib". Importing from./extdirectly works.Acceptance
public use List.x from "./file"can be imported from the re-exporting module and from the package path.compiler/testscovers the chain.Found while implementing #175 (methods live in
std/compression/src/lib.trbmeanwhile). Touchescompiler/src/semantics, no syntax change; seed impact to be checked on refine.Bytes(slice of #146) #175[loop:torbscript] claim refine by session:loop-torbscript-20261008 until 2026-10-08T12:38:42Z
[loop:torbscript] refine: ready. Cause verified against current main:
bindMemberImport(compiler/src/semantics/scope.trb) hands on the re-exporting module's entries withentry.copy(span: item.name().span), soentry.pathstays"./ext";memberImportOfmatchesentry.span == at && entry.path == path && entry.name == nameagainst the path written in the importinguse, finds nothing,isMemberImportis false and the item falls into the export check ("Listis not exported by ...").entry.pathis also whatcheckOneMemberImportprints in "<path>adds no member ...".Goal: a member re-exported with
public use List.x from "./file"is importable by name from the re-exporting module and from the package path.Acceptance criteria:
compiler/tests/check.test.trb(samemessages(files)style as the existing member-import tests):ext.trbholdsextend Bytes { fn doubled(): Bytes {...} },lib.trbholdspublic use Bytes.doubled from "./ext",main.trbholdsuse Bytes.doubled from "./lib"and callsvalue.doubled();messages(files).isEmpty(). Same chain imported by the package path if the fixture helper can express a second package; otherwise note why in the PR.main->lib->mid->ext) andasrenaming through the re-export resolve too.useline, naming the path written there (not the original./ext); the existing member-import tests and the prelude re-exports (public use Int64.seconds from "std/time") are unchanged.memberImportOfand let span + name decide); watchbindMember, which de-duplicates on package + name, so an importer that already holds the original entry must still get an entry for its own item span.Pinned records: CONCEPT.md "An extension member is named where it is used" (members imported by path
use Type.member from ..., the prelude re-exports them by name withpublic use) and the re-export form in section Modules (public use ... from). It implements existing documented behavior, so no ROADMAP milestone is touched and no design choice is open (no language change, no new syntax, not breaking, no CONCEPT Open Question).Seed: no. No syntax change, no new native, no driver flag, no std name looked up by string; the compiler source stays within the forms the current seed already accepts.
Size: one PR, one Conventional Commit (
fix(semantics): ...), touchingcompiler/src/semantics/scope.trbandcompiler/tests/check.test.trb. Tier A gates in CI; tier B is not required (nocompiler/src/ir,backendorruntimechange). Once it lands, the follow-up of moving the #175 methods back is a separate issue if wanted.Implementer model: opus/high (compiler/src). Worker usage: n/a (not reported by the runtime). next: implement
[loop:torbscript] claim implement by session:loop-torbscript-20261008 until 2026-10-08T16:42:23Z