ww: resolve self-named import to the dir-package, not a sibling file (M4 E3, #98)
The driver searchpath is srcd-first (srcd = the entry file's directory).
A co-located black-box test lib/<mod>/<mod>test.ww makes srcd=lib/<mod>,
so resolving `import <mod>` hit the sibling-FILE branch lib/<mod>/<mod>.ww
and folded it inline into the consumer unit under the wrong module tag
("package <mod> does not match import path <importer>") — 7 lib-run tests
fail under separate compilation. The combined amalgamator tolerated the
co-location; only sep surfaced it.
Resolve a package directory-first: walk ALL searchpath entries for a
directory match, and only fall back to a file match if no directory
exists anywhere. A dir-package now beats a same-named sibling file (fixes
the self-named shadow), while a leaf package with no directory (e.g.
lib/encoding/hex) still resolves via its file. This realizes the driver's
"a module is the directory" intent; the originally-specced per-directory
suppression was rejected because it broke leaf packages (rob-pike). Both
stages (cmd/ww/main.c + selfhost twin). The dir-beats-earlier-file
precedence change is latent and loud-failing (#101).
Move-set: ww + ww_ww (driver) only; w6c_ww/wwdump_ww/w6a_ww/w6l_ww HOLD.
Gate: test/wcc/989_coloimport_sep.c (table-driven, both stages).
This commit is contained in:
@@ -119,21 +119,24 @@ import_path_form(const char *name, char *out, size_t outsz)
|
||||
out[i] = '\0';
|
||||
}
|
||||
|
||||
/* try <dir>/<path>/ as a directory, then <dir>/<path>.ww as a file.
|
||||
* Sets *is_dir on hit. Symmetric with wwstage locatein for byte-id
|
||||
* driver output (rule 10). The legacy <dir>/<name>/<name>.ww form
|
||||
* was dropped in task #22 — directory-as-module enumeration replaces
|
||||
* it, mirroring ref/hare/hare/module/srcs.ha (Hare has no fallback
|
||||
* matching `foo/foo.ha`; a module IS the directory). */
|
||||
/* try <dir>/<path>/ as a directory (want_dir), else <dir>/<path>.ww as
|
||||
* a file. Sets *is_dir on hit. Symmetric with wwstage locatein for
|
||||
* byte-id driver output (rule 10). The legacy <dir>/<name>/<name>.ww
|
||||
* form was dropped in task #22 — directory-as-module enumeration
|
||||
* replaces it, mirroring ref/hare/hare/module/srcs.ha (Hare has no
|
||||
* fallback matching `foo/foo.ha`; a module IS the directory). */
|
||||
static int
|
||||
locate_import_in(const char *dir, const char *path_form, char *out,
|
||||
size_t outsz, int *is_dir)
|
||||
size_t outsz, int *is_dir, int want_dir)
|
||||
{
|
||||
struct stat st;
|
||||
snprintf(out, outsz, "%s/%s", dir, path_form);
|
||||
if (stat(out, &st) == 0 && S_ISDIR(st.st_mode)) {
|
||||
*is_dir = 1;
|
||||
return 1;
|
||||
if (want_dir) {
|
||||
snprintf(out, outsz, "%s/%s", dir, path_form);
|
||||
if (stat(out, &st) == 0 && S_ISDIR(st.st_mode)) {
|
||||
*is_dir = 1;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
snprintf(out, outsz, "%s/%s.ww", dir, path_form);
|
||||
if (access(out, 0) == 0) {
|
||||
@@ -144,25 +147,41 @@ locate_import_in(const char *dir, const char *path_form, char *out,
|
||||
}
|
||||
|
||||
/* Walk a colon-separated dirlist trying to resolve `path_form`. Returns
|
||||
* 1 on the first hit and writes the concrete path + dir/file marker. */
|
||||
* 1 on the first hit and writes the concrete path + dir/file marker.
|
||||
*
|
||||
* #98: "a module IS the directory" — a directory-package on ANY entry
|
||||
* wins over a same-named sibling FILE on an EARLIER entry. The driver
|
||||
* builds the searchpath srcd-first; a co-located `lib/<mod>/<mod>test.ww`
|
||||
* entry makes srcd = lib/<mod>, so a self-named `import <mod>` would
|
||||
* else file-hit the sibling lib/<mod>/<mod>.ww and (under --sep) fold
|
||||
* inline under the wrong module-reset → "package <mod> does not match
|
||||
* import path <importer>". Two passes — directories first, files only
|
||||
* if no directory matches anywhere — let lib/<mod>/ resolve as the dir
|
||||
* while a genuine leaf package with no directory (e.g. lib/encoding/hex
|
||||
* imported bare as `hex`, reachable only via its file in srcd) still
|
||||
* resolves in the file pass. Latent: a dir-package now beats an
|
||||
* earlier-entry same-named sibling FILE — loud-failing, none in the
|
||||
* corpus; tracked as #101. */
|
||||
static int
|
||||
locate_import(const char *dirs, const char *path_form, char *out,
|
||||
size_t outsz, int *is_dir)
|
||||
{
|
||||
const char *p = dirs;
|
||||
while (*p) {
|
||||
const char *e = strchr(p, ':');
|
||||
size_t n = e ? (size_t)(e - p) : strlen(p);
|
||||
if (n > 0 && n < outsz) {
|
||||
char dir[1024];
|
||||
if (n >= sizeof dir) n = sizeof dir - 1;
|
||||
memcpy(dir, p, n);
|
||||
dir[n] = '\0';
|
||||
if (locate_import_in(dir, path_form, out, outsz,
|
||||
is_dir)) return 1;
|
||||
for (int want_dir = 1; want_dir >= 0; want_dir--) {
|
||||
const char *p = dirs;
|
||||
while (*p) {
|
||||
const char *e = strchr(p, ':');
|
||||
size_t n = e ? (size_t)(e - p) : strlen(p);
|
||||
if (n > 0 && n < outsz) {
|
||||
char dir[1024];
|
||||
if (n >= sizeof dir) n = sizeof dir - 1;
|
||||
memcpy(dir, p, n);
|
||||
dir[n] = '\0';
|
||||
if (locate_import_in(dir, path_form, out,
|
||||
outsz, is_dir, want_dir)) return 1;
|
||||
}
|
||||
if (!e) break;
|
||||
p = e + 1;
|
||||
}
|
||||
if (!e) break;
|
||||
p = e + 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user