compiler: make package exports self-contained

This commit is contained in:
2026-08-12 01:12:42 +09:00
parent 52f6d6f0d4
commit 9b970eb16a
10 changed files with 965 additions and 82 deletions

View File

@@ -631,6 +631,16 @@ eval_def_const(Checker *c, Node *n, u64 *out, int depth)
}
}
int
check_eval_const(Checker *c, Node *n, const char *owner, u64 *out)
{
const char *saved = c->cur_mod;
c->cur_mod = owner;
int ok = eval_def_const(c, n, out, 0);
c->cur_mod = saved;
return ok;
}
/* stamp_intlit — rewrite a const-folded def rhs in place to the
* literal it evaluates to, preserving the node's cexpr-resolved type
* so the downstream DATA-row emit width and the invariant checks see
@@ -3083,6 +3093,27 @@ check_module_shadow(Checker *c, const char *name, Pos pos,
kindstr, name, name);
}
/* Self-contained `.wwi` files can carry the same origin-owned type/const
* fact through two direct dependencies (a diamond), or alongside a direct
* import of that origin. In strict package mode those compiler-generated
* declarations describe one canonical package symbol: reuse the first exact
* (module, kind, name) binding so nominal Type pointer identity is preserved.
* Raw w6c mode deliberately keeps the historical duplicate diagnostics. */
static Sym *
same_import_fact(Checker *c, Node *d, const char *mod, Skind kind)
{
if (!c->sep_mode || d == NULL || !d->imported || !d->export
|| mod == NULL || mod[0] == '\0')
return NULL;
if (kind != SK_TYPE && kind != SK_DEF)
return NULL;
Sym *s = scope_lookup_in_module(c->cur, mod, d->str);
if (s == NULL || s->kind != kind || s->decl == NULL || s->decl == d
|| !s->decl->imported || !s->decl->export)
return NULL;
return s;
}
void
check_file(Checker *c, Node *file)
{
@@ -3145,9 +3176,14 @@ check_file(Checker *c, Node *file)
continue;
}
if (d->kind != N_TYPEDECL) continue;
const char *mod = decl_mod(file, d);
Sym *fact = same_import_fact(c, d, mod, SK_TYPE);
if (fact != NULL) {
d->type = fact->type;
continue;
}
Type *named = type_named(c->a, d->str, NULL);
Sym *prev = scope_lookup_local(c->cur, d->str);
const char *mod = decl_mod(file, d);
if (prev && prev->kind == SK_USE) {
/* `use mod; ... type mod = ...;` — promote the
* SK_USE to the type symbol but remember it was
@@ -3175,6 +3211,8 @@ check_file(Checker *c, Node *file)
if (d->kind != N_DEF) continue;
c->cur_mod = decl_mod(file, d);
const char *mod = decl_mod(file, d);
if (same_import_fact(c, d, mod, SK_DEF) != NULL)
continue;
Sym *prev = scope_lookup_local(c->cur, d->str);
if (prev && prev->kind == SK_USE) {
prev->kind = SK_DEF; prev->decl = d;
@@ -3200,9 +3238,14 @@ check_file(Checker *c, Node *file)
break;
case N_DEF: {
Type *t = resolve_type(c, d->lhs);
const char *mod = decl_mod(file, d);
Sym *fact = same_import_fact(c, d, mod, SK_DEF);
if (fact != NULL) {
d->type = fact->type ? fact->type : t;
break;
}
d->type = t;
Sym *prev = scope_lookup_local(c->cur, d->str);
const char *mod = decl_mod(file, d);
if (prev && prev->kind == SK_DEF && prev->decl == d) {
/* #141: the foldable stub bound before type-body
* resolution; fill in its now-resolved type. */

View File

@@ -609,4 +609,9 @@ void check_file(Checker*, Node *file);
* (eval_enum_value's leaf delegation, emit_defs's DATA-row gate). */
int fold_int_literal(Node*, u64*);
/* Re-evaluate a checked integer constant under the declaration owner's
* import scope. The compiler export writer uses this to canonicalize array
* dimensions without serializing source-level constant dependencies. */
int check_eval_const(Checker*, Node*, const char *owner, u64*);
#endif /* WW_H */