ww imports: reject init bindings before recovery

This commit is contained in:
2026-08-22 04:27:23 +09:00
parent 4069eda942
commit 78c9eee82d
10 changed files with 789 additions and 15 deletions

View File

@@ -175,6 +175,11 @@ fn declmod(file: *syntax.node, d: *syntax.node) str = {
return empty;
};
fn invalidinitimport(u: *syntax.node) bool = {
return u != nil && u.kind == syntax.nkind.N_USE && u.useblank == 0
&& syntax.streq(u.str, "init");
};
// Map a source-file qualifier to canonical identity. Looking up the marker for
// a possible DOT must not itself count as usage; only qualified resolution
// marks the owning occurrence.
@@ -192,6 +197,7 @@ fn findusepath(file: *syntax.node, modtag: str, source: i32, alias: str,
let u: *syntax.node = file.list;
for (u != nil) {
if (u.kind == syntax.nkind.N_USE && u.useblank == 0
&& !invalidinitimport(u)
&& u.sourceid == source) {
if (syntax.streq(u.str, alias)) {
let um: str = declmod(file, u);
@@ -425,12 +431,7 @@ fn installdecl(c: *checker, file: *syntax.node, d: *syntax.node) void = {
cerr("' cannot import itself\n"); c.errs += 1i32;
};
if (d.useblank != 0) { return; };
if (syntax.streq(nm, "init")) {
importdiagprefix(d);
cerr("cannot import package as init - init must be a func\n");
c.errs += 1;
return;
};
if (invalidinitimport(d)) { return; };
// #30 value-before-use: a same-leaf VALUE/type decl is already
// installed (source order placed `fn aa` before `import aa`).
// Promote it in place with use_alias instead of installing a
@@ -7527,6 +7528,20 @@ fn importdiagprefix(n: *syntax.node) void = {
cerr(strconv.i32tos(n.col, strconv.base.DEC)); cerr(": error: ");
};
fn importbindingdiagprefix(n: *syntax.node) void = {
let file: str = n.usefile;
let line: i32 = n.useline;
let col: i32 = n.usecol;
if (file.len == 0) {
file = n.file;
line = n.line;
col = n.col;
};
cerr(file); cerr(":");
cerr(strconv.i32tos(line, strconv.base.DEC)); cerr(":");
cerr(strconv.i32tos(col, strconv.base.DEC)); cerr(": error: ");
};
fn importdiagalt(n: *syntax.node, name: str) void = {
cerr("\t"); cerr(n.file); cerr(":");
cerr(strconv.i32tos(n.line, strconv.base.DEC)); cerr(":");
@@ -7534,6 +7549,22 @@ fn importdiagalt(n: *syntax.node, name: str) void = {
cerr(": other declaration of "); cerr(name); cerr("\n");
};
// Pinned Go 1.26.5 types2 rejects an effective import binding named init and
// immediately continues before creating its PkgName. Diagnose every resolved
// occurrence at the first import-spec token, while retaining its loader-owned
// dependency edge and excluding it from binding recovery below.
fn rejectinitimports(c: *checker, file: *syntax.node) void = {
let u: *syntax.node = file.list;
for (u != nil) {
if (invalidinitimport(u)) {
importbindingdiagprefix(u);
cerr("cannot import package as init - init must be a func\n");
c.errs += 1;
};
u = u.next;
};
};
fn topdeclkind(d: *syntax.node) bool = {
return d != nil && (d.kind == syntax.nkind.N_TYPEDECL
|| d.kind == syntax.nkind.N_DEF || d.kind == syntax.nkind.N_FNDECL
@@ -7581,10 +7612,12 @@ fn checkimportredeclarations(c: *checker, file: *syntax.node) void = {
let u: *syntax.node = file.list;
for (u != nil) {
if (u.kind == syntax.nkind.N_USE && u.useblank == 0
&& !invalidinitimport(u)
&& u.imported == 0) {
let v: *syntax.node = file.list;
for (v != u) {
if (v.kind == syntax.nkind.N_USE && v.useblank == 0
&& !invalidinitimport(v)
&& v.imported == 0
&& v.sourceid == u.sourceid && syntax.streq(v.str, u.str)) {
importdiagprefix(u); cerr(u.str);
@@ -7605,6 +7638,7 @@ fn checkimportusageandcollisions(c: *checker, file: *syntax.node) void = {
let u: *syntax.node = file.list;
for (u != nil) {
if (u.kind == syntax.nkind.N_USE && u.useblank == 0
&& !invalidinitimport(u)
&& u.imported == 0 && u.used == 0) {
let path: str = u.usesource;
if (path.len == 0) { path = u.usepath; };
@@ -7629,6 +7663,7 @@ fn checkimportusageandcollisions(c: *checker, file: *syntax.node) void = {
u = file.list;
for (u != nil) {
if (u.kind == syntax.nkind.N_USE && u.useblank == 0
&& !invalidinitimport(u)
&& u.imported == 0
&& syntax.streq(d.str, u.str)) {
let path: str = u.usesource;
@@ -8608,6 +8643,7 @@ fn checkfile(c: *checker, file: *syntax.node) void = {
file.list = usenode;
};
};
rejectinitimports(c, file);
rejectnonfunctionmaindecls(c, file);
markimportuses(c, file);
checkimportredeclarations(c, file);