compiler: implement blank package name semantics

This commit is contained in:
2026-08-23 15:33:59 +09:00
parent e67b8e1bc4
commit 0b24b11d65
14 changed files with 2862 additions and 112 deletions

View File

@@ -62,6 +62,8 @@ static const char *use_path(Node *file, const char *curmod, int source,
const char *alias);
static const char *find_use_path(Node *file, const char *curmod, int source,
const char *alias, int mark);
static Node *find_use_binding(Node *file, const char *curmod, int source,
const char *alias, int mark);
static int src_imports(Node *file, const char *modtag, int source,
const char *name);
static Sym *lookup_visible(Checker *c, const char *name);
@@ -96,6 +98,11 @@ resolve_typename(Checker *c, Node *n)
char *head = astrndup(c->a, nm, hl);
Sym *m = scope_lookup(c->cur, head);
if (m && (m->kind == SK_USE || m->use_alias)) {
Node *u = find_use_binding(c->file, c->cur_mod,
c->cur_source, head, 1);
if (u != NULL && u->usepkgname != NULL
&& strcmp(u->usepkgname, "_") == 0)
return ty_err;
/* M1 #22: map the qualifier alias to its dotted
* import path (symbols are path-keyed). */
const char *mk = use_path(c->file, c->cur_mod,
@@ -1521,6 +1528,11 @@ cexpr(Checker *c, Node *n)
if (n->lhs && n->lhs->kind == N_IDENT) {
Sym *ms = lookup_visible(c, n->lhs->str);
if (ms && (ms->kind == SK_USE || ms->use_alias)) {
Node *u = find_use_binding(c->file, c->cur_mod,
c->cur_source, n->lhs->str, 1);
if (u != NULL && u->usepkgname != NULL
&& strcmp(u->usepkgname, "_") == 0)
return n->type = ty_err;
/* Module-qualified ref. `use_alias` covers
* the self-import case where the module's
* type name shadowed the SK_USE; the leaf
@@ -3016,6 +3028,18 @@ import_binding_pos(Node *u)
return p;
}
static Pos
import_path_pos(Node *u)
{
Pos p = u->pos;
if (u->usepathfile != NULL) {
p.file = u->usepathfile;
p.line = u->usepathline;
p.col = u->usepathcol;
}
return p;
}
/*
* use_path — map a source-file default qualifier (the imported package's
* declared name) to the full canonical import path it binds, for
@@ -3056,6 +3080,33 @@ find_use_path(Node *file, const char *curmod, int source, const char *alias,
return NULL;
}
static Node *
find_use_binding(Node *file, const char *curmod, int source,
const char *alias, int mark)
{
if (file == NULL || alias == NULL) return NULL;
/* Source-zero self-qualification wins before import lookup in
* find_use_path and therefore cannot denote an imported package object. */
if (source == 0 && curmod != NULL) {
const char *dot = strrchr(curmod, '.');
const char *leaf = dot ? dot + 1 : curmod;
if (strcmp(alias, leaf) == 0) return NULL;
}
for (Node *u = file->list; u; u = u->next) {
if (u->kind != N_USE || u->str == NULL || invalid_init_import(u)
|| u->sourceid != source || strcmp(u->str, alias) != 0)
continue;
const char *um = decl_mod(file, u);
int same = (um == NULL) ? (curmod == NULL)
: (curmod != NULL && strcmp(um, curmod) == 0);
if (same) {
if (mark) u->used = 1;
return u;
}
}
return NULL;
}
static const char *
use_path(Node *file, const char *curmod, int source, const char *alias)
{
@@ -4379,11 +4430,48 @@ check_test_target(const Checker *c, const char *path)
return 0;
}
static void
reject_blank_package_names(Checker *c, Node *file)
{
for (Node *p = file->body; p; p = p->next)
if (p->kind == N_FILE && p->pkgname != NULL
&& strcmp(p->pkgname, "_") == 0)
err(c, p->pos, "invalid package name _");
}
static void
reject_invalid_imports(Checker *c, Node *file)
{
for (Node *u = file->list; u; u = u->next) {
if (u->kind != N_USE || u->usepath == NULL
|| u->usepkgname == NULL
|| strcmp(u->usepkgname, "_") != 0)
continue;
u->used = 1;
int seen = 0;
for (Node *v = file->list; v != u; v = v->next) {
if (v->kind == N_USE && v->usepath != NULL
&& v->usepkgname != NULL
&& strcmp(v->usepkgname, "_") == 0
&& strcmp(v->usepath, u->usepath) == 0) {
seen = 1;
break;
}
}
if (!seen)
err(c, import_path_pos(u),
"could not import %s (invalid package name: \"_\")",
u->usepath);
}
}
void
check_file(Checker *c, Node *file)
{
if (file == NULL || file->kind != N_FILE) return;
c->file = file;
reject_blank_package_names(c, file);
reject_invalid_imports(c, file);
/* Under -T, prepend the dispatcher support import before pass 1 so
* decl_mod keys the runner under the selected support module. A pure