You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The INT-01 follow-up recorded after #244: `use Mod;` + qualified *value*
call `Mod.fn(x)` failed with Resolve.UndefinedVariable on the qualifier.
Root cause: `use Mod;` (ImportSimple) flat-imports Mod's public symbols
(import_resolved_symbols) but binds no module namespace; the parser yields
ExprField(ExprVar Mod, fn) (ExprSpan-wrapped), and resolve.ml's ExprField
case drops the field and resolves the base ExprVar Mod -> undefined. So
`Mod.fn` could never resolve even though `fn` was in scope flat.
Fix: a pure, idempotent, total parse-boundary lowering
`Resolve.lower_qualified_value_paths : program -> program` that rewrites
`ExprField(ExprVar m, fld)` -> `ExprVar fld` when `m` is an ImportSimple
qualifier (alias preferred; ImportList/ImportGlob bind no qualifier).
Span-peels the base; genuine record access `r.f` is untouched (`r` is not
an import qualifier). This is the value-expression analogue of #241/ADR-014
(qualified type/effect paths in the grammar). Applied once in
`parse_with_face` so resolve/typecheck/borrow/quantity/codegen all see the
lowered form uniformly; the formatter uses a separate path
(Formatter.format_file) so `fmt` preserves source `Mod.fn`. Embedders that
bypass parse_with_face call the exposed function (as the tests do) —
boundary documented in INT-01.
Verified (oracle): `use CrossCallee; CrossCallee.consume(42)` and
`use CrossCallee as CC; CC.consume(7)` -> Type checking passed;
`use CrossCallee::{consume}; consume(42)` still passes (no regression);
genuine `p.x` preserved. Full gate 275/275 (was 271; +4 hermetic
"E2E Qualified Value #178" regression tests + 2 fixtures).
Scope (honest): the `.`-qualified value path (the recorded gap) is closed.
`Mod::fn(x)` in *expression* position remains a parse error — a DISTINCT
parser gap (`::` is reserved for Type::Variant in expr position), not the
resolver; tracked as a separate follow-up. Refs #178 (not Closes).
Co-authored-by: hyperpolymath <hyperpolymath@users.noreply.github.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
0 commit comments