compiler: implement blank package name semantics
This commit is contained in:
@@ -360,15 +360,23 @@ fn canonicalpkgname(path: str, name: str) bool = {
|
||||
return true;
|
||||
};
|
||||
|
||||
// A paired interface owns PATH's declared name. Compiler-private names keep
|
||||
// transitive fact sections semantic and are ignored when a real name exists.
|
||||
// Package-marker facts are canonical-origin keyed across all supplied
|
||||
// interfaces; an interface may embed transitive origins besides its container
|
||||
// owner. Compiler-private names remain recovery metadata and are ignored when
|
||||
// a real declared name exists.
|
||||
type pkgnamestate = enum i32 {
|
||||
PKGNAME_MISSING = 0,
|
||||
PKGNAME_VALID = 1,
|
||||
PKGNAME_CONFLICT = 2,
|
||||
PKGNAME_INVALID = 3,
|
||||
};
|
||||
|
||||
fn importpkgname(asts: []*syntax.node, paths: []*u8, nasts: i32, path: str,
|
||||
primary: *syntax.node, conflict: *bool) str = {
|
||||
primary: *syntax.node, resolved: *str) pkgnamestate = {
|
||||
let name: str;
|
||||
let placeholder: str;
|
||||
let i: i32 = 0;
|
||||
for (i < nasts) {
|
||||
if (!cstreq(paths[i], path)) { i += 1; continue; };
|
||||
let f: *syntax.node = asts[i];
|
||||
let p: *syntax.node = nil;
|
||||
if (f != nil) { p = f.body; };
|
||||
@@ -379,9 +387,7 @@ fn importpkgname(asts: []*syntax.node, paths: []*u8, nasts: i32, path: str,
|
||||
placeholder = p.pkgname;
|
||||
} else { if (name.len > 0
|
||||
&& !syntax.streq(name, p.pkgname)) {
|
||||
*conflict = true;
|
||||
let empty: str;
|
||||
return empty;
|
||||
return pkgnamestate.PKGNAME_CONFLICT;
|
||||
} else { name = p.pkgname; }; };
|
||||
};
|
||||
p = p.next;
|
||||
@@ -396,45 +402,70 @@ fn importpkgname(asts: []*syntax.node, paths: []*u8, nasts: i32, path: str,
|
||||
if (canonicalpkgname(path, p.pkgname)) {
|
||||
placeholder = p.pkgname;
|
||||
} else { if (name.len > 0 && !syntax.streq(name, p.pkgname)) {
|
||||
*conflict = true;
|
||||
let empty: str;
|
||||
return empty;
|
||||
return pkgnamestate.PKGNAME_CONFLICT;
|
||||
} else { name = p.pkgname; }; };
|
||||
};
|
||||
p = p.next;
|
||||
};
|
||||
if (name.len == 0) { name = placeholder; };
|
||||
return name;
|
||||
*resolved = name;
|
||||
if (name.len == 0) { return pkgnamestate.PKGNAME_MISSING; };
|
||||
if (syntax.streq(name, "_")) { return pkgnamestate.PKGNAME_INVALID; };
|
||||
return pkgnamestate.PKGNAME_VALID;
|
||||
};
|
||||
|
||||
fn pathleaf(path: str) str = {
|
||||
let start: i32 = 0;
|
||||
let i: i32 = 0;
|
||||
for (i < path.len) {
|
||||
if (path[i] == '.') { start = i + 1; };
|
||||
i += 1;
|
||||
};
|
||||
let leaf: str;
|
||||
leaf.ptr = path.ptr + (start: u64);
|
||||
leaf.len = path.len - start;
|
||||
return leaf;
|
||||
};
|
||||
|
||||
fn bindimportnames(list: *syntax.node, asts: []*syntax.node, paths: []*u8,
|
||||
nasts: i32,
|
||||
primary: *syntax.node, testsupport: *u8) bool = {
|
||||
primary: *syntax.node, testsupport: *u8,
|
||||
externalsupport: *syntax.node) bool = {
|
||||
let u: *syntax.node = list;
|
||||
for (u != nil) {
|
||||
if (u.kind == syntax.nkind.N_USE && u.usepath.len > 0) {
|
||||
let reserved: bool = testsupport != nil
|
||||
&& cstreq(testsupport, "__wwtest")
|
||||
&& syntax.streq(u.usepath, "__wwtest");
|
||||
if (!reserved) {
|
||||
let conflict: bool = false;
|
||||
let name: str = importpkgname(asts, paths, nasts, u.usepath,
|
||||
primary, &conflict);
|
||||
if (conflict) {
|
||||
let name: str;
|
||||
let state: pkgnamestate = importpkgname(asts, paths, nasts,
|
||||
u.usepath, primary, &name);
|
||||
if (state == pkgnamestate.PKGNAME_CONFLICT) {
|
||||
let pre: str = "w6c: package ";
|
||||
let post: str = " has conflicting declared names in export data\n";
|
||||
os.write(2, pre.ptr, pre.len: u64);
|
||||
os.write(2, u.usepath.ptr, u.usepath.len: u64);
|
||||
os.write(2, post.ptr, post.len: u64);
|
||||
return false;
|
||||
};
|
||||
if (name.len > 0) {
|
||||
u.usepkgname = name;
|
||||
if (u.useblank == 0) {
|
||||
};
|
||||
if (state == pkgnamestate.PKGNAME_VALID
|
||||
|| state == pkgnamestate.PKGNAME_INVALID) {
|
||||
u.usepkgname = name;
|
||||
if (state == pkgnamestate.PKGNAME_INVALID) {
|
||||
u.used = 1;
|
||||
if (u.useblank == 0 && !reserved) {
|
||||
if (u.usealias.len > 0) { u.str = u.usealias; }
|
||||
else { u.str = name; };
|
||||
else { u.str = pathleaf(u.usepath); };
|
||||
};
|
||||
} else { if (u.imported == 0) {
|
||||
} else { if (u.useblank == 0 && !reserved) {
|
||||
if (u.usealias.len > 0) { u.str = u.usealias; }
|
||||
else { u.str = name; };
|
||||
}; };
|
||||
} else { if (u == externalsupport) {
|
||||
// A bare direct -T compiler invocation deliberately leaves the
|
||||
// compiler-generated support hook external.
|
||||
u.used = 1;
|
||||
} else { if (u.imported == 0) {
|
||||
let pre: str = "w6c: import ";
|
||||
let post: str = " has no declared package name in direct export data\n";
|
||||
os.write(2, pre.ptr, pre.len: u64);
|
||||
@@ -449,14 +480,114 @@ fn bindimportnames(list: *syntax.node, asts: []*syntax.node, paths: []*u8,
|
||||
if (u.usealias.len > 0) { u.str = u.usealias; }
|
||||
else { u.str = u.usepath; };
|
||||
};
|
||||
}; };
|
||||
};
|
||||
}; }; };
|
||||
};
|
||||
u = u.next;
|
||||
};
|
||||
return true;
|
||||
};
|
||||
|
||||
fn pathsethas(paths: []str, path: str) bool = {
|
||||
if (path.len == 0) { return false; };
|
||||
let i: i32 = 0;
|
||||
for (i < paths.len) {
|
||||
if (syntax.streq(paths[i], path)) { return true; };
|
||||
i += 1;
|
||||
};
|
||||
return false;
|
||||
};
|
||||
|
||||
fn pathsetadd(paths: *[]str, path: str) bool = {
|
||||
if (path.len == 0 || pathsethas(*paths, path)) { return false; };
|
||||
append(*paths, path);
|
||||
return true;
|
||||
};
|
||||
|
||||
fn materializetestsupport(file: *syntax.node, testmode: i32,
|
||||
testsupport: *u8) *syntax.node = {
|
||||
if (testmode == 0 || testsupport == nil) { return nil; };
|
||||
let path: str = pathstr(testsupport);
|
||||
let u: *syntax.node = file.list;
|
||||
for (u != nil) {
|
||||
if (u.kind == syntax.nkind.N_USE && u.imported == 0
|
||||
&& u.sourceid == file.sourceid
|
||||
&& syntax.streq(u.usepath, path)) {
|
||||
u.used = 1;
|
||||
return nil;
|
||||
};
|
||||
u = u.next;
|
||||
};
|
||||
u = syntax.newnode(syntax.nkind.N_USE, file.file, file.line, file.col);
|
||||
u.str = path;
|
||||
u.usesource = path;
|
||||
u.usepath = path;
|
||||
u.usefile = file.file;
|
||||
u.useline = file.line;
|
||||
u.usecol = file.col;
|
||||
u.usepathfile = file.file;
|
||||
u.usepathline = file.line;
|
||||
u.usepathcol = file.col;
|
||||
u.pkgname = file.pkgname;
|
||||
u.sourceid = file.sourceid;
|
||||
u.used = 1;
|
||||
u.next = file.list;
|
||||
file.list = u;
|
||||
return u;
|
||||
};
|
||||
|
||||
fn computereachedimports(reached: *[]str, primary: *syntax.node,
|
||||
asts: []*syntax.node, paths: []*u8, nasts: i32) void = {
|
||||
let u: *syntax.node = nil;
|
||||
if (primary != nil) { u = primary.list; };
|
||||
for (u != nil) {
|
||||
if (u.kind == syntax.nkind.N_USE && u.imported == 0) {
|
||||
pathsetadd(reached, u.usepath);
|
||||
};
|
||||
u = u.next;
|
||||
};
|
||||
let changed: bool = true;
|
||||
for (changed) {
|
||||
changed = false;
|
||||
let i: i32 = 0;
|
||||
for (i < nasts) {
|
||||
u = nil;
|
||||
if (asts[i] != nil) { u = asts[i].list; };
|
||||
for (u != nil) {
|
||||
if (u.kind == syntax.nkind.N_USE && u.imported != 0
|
||||
&& u.nmod.len > 0 && u.usepath.len > 0
|
||||
&& pathsethas(*reached, u.nmod)) {
|
||||
let name: str;
|
||||
if (importpkgname(asts, paths, nasts, u.nmod, nil,
|
||||
&name) == pkgnamestate.PKGNAME_VALID
|
||||
&& pathsetadd(reached, u.usepath)) {
|
||||
changed = true;
|
||||
};
|
||||
};
|
||||
u = u.next;
|
||||
};
|
||||
i += 1;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
fn filterreachedimports(file: *syntax.node, reached: []str,
|
||||
asts: []*syntax.node, paths: []*u8, nasts: i32) void = {
|
||||
let prev: *syntax.node = nil;
|
||||
let d: *syntax.node = file.list;
|
||||
for (d != nil) {
|
||||
let next: *syntax.node = d.next;
|
||||
let name: str;
|
||||
let keep: bool = d.imported != 0 && d.nmod.len > 0
|
||||
&& pathsethas(reached, d.nmod)
|
||||
&& importpkgname(asts, paths, nasts, d.nmod, nil,
|
||||
&name) == pkgnamestate.PKGNAME_VALID;
|
||||
if (keep) { prev = d; }
|
||||
else { if (prev == nil) { file.list = next; }
|
||||
else { prev.next = next; }; };
|
||||
d = next;
|
||||
};
|
||||
};
|
||||
|
||||
export fn main(argc: i32, argv: **u8) i32 = {
|
||||
let src: *u8 = nil;
|
||||
let out: *u8 = nil;
|
||||
@@ -758,8 +889,6 @@ export fn main(argc: i32, argv: **u8) i32 = {
|
||||
targeti += 1;
|
||||
};
|
||||
|
||||
let importhead: *syntax.node = nil;
|
||||
let importtail: *syntax.node = nil;
|
||||
importi = 0;
|
||||
for (importi < nimports) {
|
||||
let ibuf: *u8;
|
||||
@@ -800,15 +929,6 @@ export fn main(argc: i32, argv: **u8) i32 = {
|
||||
let imported: *syntax.node = syntax.parsefile(&ips);
|
||||
if (il.errs > 0 || ips.errs > 0) { return 1; };
|
||||
importasts[importi] = imported;
|
||||
if (!bindimportnames(imported.list, importasts, importpaths, importi + 1,
|
||||
nil, testsupport)) { return 1; };
|
||||
let d: *syntax.node = imported.list;
|
||||
if (d != nil) {
|
||||
if (importhead == nil) { importhead = d; }
|
||||
else { importtail.next = d; };
|
||||
for (d.next != nil) { d = d.next; };
|
||||
importtail = d;
|
||||
};
|
||||
importi += 1;
|
||||
};
|
||||
|
||||
@@ -860,17 +980,34 @@ export fn main(argc: i32, argv: **u8) i32 = {
|
||||
};
|
||||
mapi += 1;
|
||||
};
|
||||
// Test compilation has a compiler-required support edge even when no
|
||||
// equivalent source import occurrence exists. Make that primary root
|
||||
// explicit before resolving interface metadata.
|
||||
let externalsupport: *syntax.node = materializetestsupport(f, testmode,
|
||||
testsupport);
|
||||
// Standalone interfaces are metadata containers, never graph roots. Reach
|
||||
// only from primary/compiler-required uses and traverse uses owned by an
|
||||
// already-reached package whose declared name is valid.
|
||||
let reached: []str = alloc([], 16u64)!;
|
||||
computereachedimports(&reached, f, importasts, importpaths, nimports);
|
||||
importi = 0;
|
||||
for (importi < nimports) {
|
||||
filterreachedimports(importasts[importi], reached, importasts,
|
||||
importpaths, nimports);
|
||||
importi += 1;
|
||||
};
|
||||
// A later direct interface may supply metadata for an origin section used
|
||||
// by an earlier interface, so bind once more against the complete set.
|
||||
// by an earlier interface. Bind each now-bounded reached list against the
|
||||
// complete metadata set, before any concatenation can widen that list.
|
||||
importi = 0;
|
||||
for (importi < nimports) {
|
||||
if (!bindimportnames(importasts[importi].list, importasts, importpaths,
|
||||
nimports,
|
||||
nil, testsupport)) { return 1; };
|
||||
nil, testsupport, nil)) { return 1; };
|
||||
importi += 1;
|
||||
};
|
||||
if (!bindimportnames(f.list, importasts, importpaths, nimports, f,
|
||||
testsupport)) {
|
||||
testsupport, externalsupport)) {
|
||||
return 1;
|
||||
};
|
||||
targeti = 0;
|
||||
@@ -881,7 +1018,12 @@ export fn main(argc: i32, argv: **u8) i32 = {
|
||||
if (targetuse.kind == syntax.nkind.N_USE
|
||||
&& targetuse.imported == 0
|
||||
&& syntax.streq(targetuse.usepath, testtargets[targeti])) {
|
||||
targetuse.str = targetuse.usepath;
|
||||
// Valid generated targets use their canonical path as the
|
||||
// compiler-owned qualifier. Preserve an invalid provider's fake
|
||||
// explicit-or-leaf spelling for source-local recovery.
|
||||
if (!syntax.streq(targetuse.usepkgname, "_")) {
|
||||
targetuse.str = targetuse.usepath;
|
||||
};
|
||||
seen += 1;
|
||||
};
|
||||
targetuse = targetuse.next;
|
||||
@@ -893,6 +1035,19 @@ export fn main(argc: i32, argv: **u8) i32 = {
|
||||
};
|
||||
targeti += 1;
|
||||
};
|
||||
let importhead: *syntax.node = nil;
|
||||
let importtail: *syntax.node = nil;
|
||||
importi = 0;
|
||||
for (importi < nimports) {
|
||||
let d: *syntax.node = importasts[importi].list;
|
||||
if (d != nil) {
|
||||
if (importhead == nil) { importhead = d; }
|
||||
else { importtail.next = d; };
|
||||
for (d.next != nil) { d = d.next; };
|
||||
importtail = d;
|
||||
};
|
||||
importi += 1;
|
||||
};
|
||||
if (importhead != nil) {
|
||||
importtail.next = f.list;
|
||||
f.list = importhead;
|
||||
|
||||
@@ -179,19 +179,18 @@ fn invalidinitimport(u: *syntax.node) bool = {
|
||||
&& 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
|
||||
// Map a source-file qualifier to its exact retained import occurrence. Looking
|
||||
// up a possible DOT must not itself count as usage; only qualified resolution
|
||||
// marks the owning occurrence.
|
||||
fn findusepath(file: *syntax.node, modtag: str, source: i32, alias: str,
|
||||
mark: bool) str = {
|
||||
let empty: str;
|
||||
if (file == nil) { return empty; };
|
||||
if (alias.len == 0) { return empty; };
|
||||
fn findusebinding(file: *syntax.node, modtag: str, source: i32, alias: str,
|
||||
mark: bool) *syntax.node = {
|
||||
if (file == nil) { return nil; };
|
||||
if (alias.len == 0) { return nil; };
|
||||
if (source == 0 && modtag.len != 0) {
|
||||
let (prefix, suffix) = strings.rcut(modtag, ".");
|
||||
let leaf: str = suffix;
|
||||
if (leaf.len == 0) { leaf = modtag; };
|
||||
if (syntax.streq(alias, leaf)) { return modtag; };
|
||||
if (syntax.streq(alias, leaf)) { return nil; };
|
||||
};
|
||||
let u: *syntax.node = file.list;
|
||||
for (u != nil) {
|
||||
@@ -204,15 +203,33 @@ fn findusepath(file: *syntax.node, modtag: str, source: i32, alias: str,
|
||||
if (modtag.len == 0) {
|
||||
if (um.len == 0) { same = true; };
|
||||
} else { if (syntax.streq(um, modtag)) { same = true; }; };
|
||||
if (same) {
|
||||
if (mark) { u.used = 1; };
|
||||
if (u.usepath.len != 0) { return u.usepath; };
|
||||
return u.str;
|
||||
if (same) {
|
||||
if (mark) { u.used = 1; };
|
||||
return u;
|
||||
};
|
||||
};
|
||||
};
|
||||
u = u.next;
|
||||
};
|
||||
return nil;
|
||||
};
|
||||
|
||||
fn findusepath(file: *syntax.node, modtag: str, source: i32, alias: str,
|
||||
mark: bool) str = {
|
||||
let empty: str;
|
||||
if (file == nil) { return empty; };
|
||||
if (alias.len == 0) { return empty; };
|
||||
if (source == 0 && modtag.len != 0) {
|
||||
let (prefix, suffix) = strings.rcut(modtag, ".");
|
||||
let leaf: str = suffix;
|
||||
if (leaf.len == 0) { leaf = modtag; };
|
||||
if (syntax.streq(alias, leaf)) { return modtag; };
|
||||
};
|
||||
let u: *syntax.node = findusebinding(file, modtag, source, alias, mark);
|
||||
if (u != nil) {
|
||||
if (u.usepath.len != 0) { return u.usepath; };
|
||||
return u.str;
|
||||
};
|
||||
return empty;
|
||||
};
|
||||
|
||||
@@ -298,6 +315,13 @@ fn localshadowsimport(c: *checker, name: str) bool = {
|
||||
return false;
|
||||
};
|
||||
|
||||
fn fakeimportalias(c: *checker, alias: str) bool = {
|
||||
if (localshadowsimport(c, alias)) { return false; };
|
||||
let u: *syntax.node = findusebinding(c.file, c.curmod, c.cursource,
|
||||
alias, true);
|
||||
return u != nil && syntax.streq(u.usepkgname, "_");
|
||||
};
|
||||
|
||||
fn lookupvisible(c: *checker, name: str) *syntax.sym = {
|
||||
let found: *syntax.sym = syntax.scopelookupprefer(c.cur, c.curmod, name);
|
||||
let builtin: *syntax.sym = nil;
|
||||
@@ -726,6 +750,14 @@ fn resolvewalk(c: *checker, n: *syntax.node) void = {
|
||||
c.nresolved += 1;
|
||||
return;
|
||||
};
|
||||
if (strings.contains(nm, ".")) {
|
||||
let (head, leaf) = strings.rcut(nm, ".");
|
||||
if (fakeimportalias(c, head)) {
|
||||
n.type_ = c.tc.tyerr: *void;
|
||||
c.nresolved += 1;
|
||||
return;
|
||||
};
|
||||
};
|
||||
let s: *syntax.sym = lookupvisibletype(c, nm);
|
||||
let builtin: bool = builtintypename(nm);
|
||||
// `pkg.Type` — strip the last dot prefix and look up
|
||||
@@ -2860,6 +2892,13 @@ fn tinfofornode(c: *checker, n: *syntax.node) *syntax.tinfo = {
|
||||
syntax.tinfocachebind(c.tc, n, c.tc.tyerr);
|
||||
return c.tc.tyerr;
|
||||
};
|
||||
if (n.file.len != 0 && strings.contains(nm, ".")) {
|
||||
let (head, leaf) = strings.rcut(nm, ".");
|
||||
if (fakeimportalias(c, head)) {
|
||||
syntax.tinfocachebind(c.tc, n, c.tc.tyerr);
|
||||
return c.tc.tyerr;
|
||||
};
|
||||
};
|
||||
if (syntax.streq(nm, "void")) { r = c.tc.tyvoid; };
|
||||
if (syntax.streq(nm, "bool")) { r = c.tc.tybool; };
|
||||
if (syntax.streq(nm, "rune")) { r = c.tc.tyrune; };
|
||||
@@ -4217,6 +4256,14 @@ fn exprtype(c: *checker, e: *syntax.node, hint: *syntax.node) *syntax.node = {
|
||||
e.type_ = c.tc.tyerr: *void;
|
||||
return nil;
|
||||
};
|
||||
if (callee.kind == syntax.nkind.N_DOT && callee.lhs != nil
|
||||
&& callee.lhs.kind == syntax.nkind.N_IDENT
|
||||
&& fakeimportalias(c, callee.lhs.str)) {
|
||||
callee.lhs.type_ = c.tc.tyerr: *void;
|
||||
callee.type_ = c.tc.tyerr: *void;
|
||||
e.type_ = c.tc.tyerr: *void;
|
||||
return nil;
|
||||
};
|
||||
// A module-qualified leaf may already have been rejected while the
|
||||
// N_DOT callee was checked on an earlier resolve walk. cstage caches
|
||||
// that failure on the call; mirror its once-only diagnostic here rather
|
||||
@@ -4738,6 +4785,12 @@ fn exprtype(c: *checker, e: *syntax.node, hint: *syntax.node) *syntax.node = {
|
||||
// harec's enum-resolve constexpr set at
|
||||
// ref/harec/src/check.c:4419-4434.
|
||||
let lhsn: *syntax.node = e.lhs;
|
||||
if (lhsn != nil && lhsn.kind == syntax.nkind.N_IDENT
|
||||
&& fakeimportalias(c, lhsn.str)) {
|
||||
lhsn.type_ = c.tc.tyerr: *void;
|
||||
e.type_ = c.tc.tyerr: *void;
|
||||
return nil;
|
||||
};
|
||||
if (lhsn != nil) { if (lhsn.kind == syntax.nkind.N_IDENT) {
|
||||
let ms: *syntax.sym = lookupvisible(c, lhsn.str);
|
||||
if (ms != nil && ms.skind != syntax.skind.SK_USE) {
|
||||
@@ -7446,6 +7499,14 @@ fn exprtypeoftry(c: *checker, e: *syntax.node) *syntax.node = {
|
||||
// nkind.N_DOT). We need the fn-decl's lhs (return-type AST).
|
||||
let callee: *syntax.node = e.lhs;
|
||||
if (callee == nil) { return nil; };
|
||||
if (callee.kind == syntax.nkind.N_DOT && callee.lhs != nil
|
||||
&& callee.lhs.kind == syntax.nkind.N_IDENT
|
||||
&& fakeimportalias(c, callee.lhs.str)) {
|
||||
callee.lhs.type_ = c.tc.tyerr: *void;
|
||||
callee.type_ = c.tc.tyerr: *void;
|
||||
e.type_ = c.tc.tyerr: *void;
|
||||
return nil;
|
||||
};
|
||||
let nm: str;
|
||||
nm.ptr = nil; nm.len = 0;
|
||||
if (callee.kind == syntax.nkind.N_IDENT) { nm = callee.str; };
|
||||
@@ -7837,6 +7898,20 @@ fn importbindingdiagprefix(n: *syntax.node) void = {
|
||||
cerr(strconv.i32tos(col, strconv.base.DEC)); cerr(": error: ");
|
||||
};
|
||||
|
||||
fn importpathdiagprefix(n: *syntax.node) void = {
|
||||
let file: str = n.usepathfile;
|
||||
let line: i32 = n.usepathline;
|
||||
let col: i32 = n.usepathcol;
|
||||
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(":");
|
||||
@@ -7860,6 +7935,35 @@ fn rejectinitimports(c: *checker, file: *syntax.node) void = {
|
||||
};
|
||||
};
|
||||
|
||||
fn rejectinvalidimports(c: *checker, file: *syntax.node) void = {
|
||||
let u: *syntax.node = file.list;
|
||||
for (u != nil) {
|
||||
if (u.kind == syntax.nkind.N_USE
|
||||
&& u.usepath.len != 0
|
||||
&& syntax.streq(u.usepkgname, "_")) {
|
||||
u.used = 1;
|
||||
let duplicate: bool = false;
|
||||
let p: *syntax.node = file.list;
|
||||
for (p != u) {
|
||||
if (p.kind == syntax.nkind.N_USE && p.usepath.len != 0
|
||||
&& syntax.streq(p.usepkgname, "_")
|
||||
&& syntax.streq(p.usepath, u.usepath)) {
|
||||
duplicate = true;
|
||||
break;
|
||||
};
|
||||
p = p.next;
|
||||
};
|
||||
if (!duplicate) {
|
||||
importpathdiagprefix(u);
|
||||
cerr("could not import "); cerr(u.usepath);
|
||||
cerr(" (invalid package name: \"_\")\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
|
||||
@@ -9051,10 +9155,25 @@ fn checktesttarget(c: *checker, path: str) bool = {
|
||||
return false;
|
||||
};
|
||||
|
||||
fn rejectblankpackagenames(c: *checker, file: *syntax.node) void = {
|
||||
let p: *syntax.node = file.body;
|
||||
for (p != nil) {
|
||||
if (p.kind == syntax.nkind.N_FILE
|
||||
&& syntax.streq(p.pkgname, "_")) {
|
||||
importdiagprefix(p);
|
||||
cerr("invalid package name _\n");
|
||||
c.errs += 1;
|
||||
};
|
||||
p = p.next;
|
||||
};
|
||||
};
|
||||
|
||||
fn checkfile(c: *checker, file: *syntax.node) void = {
|
||||
if (file == nil) { return; };
|
||||
if (file.kind != syntax.nkind.N_FILE) { return; };
|
||||
c.file = file;
|
||||
rejectblankpackagenames(c, file);
|
||||
rejectinvalidimports(c, file);
|
||||
|
||||
// Under -T, prepend the dispatcher support import before Pass 1 so
|
||||
// declmod keys the runner under the selected support module. This is a
|
||||
|
||||
Reference in New Issue
Block a user