GeezerVisonThe World Wide Web, restored to 800 pixels of glory. | ||||||||||||||||||||||||
| Home|About|Gaming cabinet|Archives|How it works|Starter sites | ||||||||||||||||||||||||
GeezerVison is showing github.com — feat(typecheck): module-qualified type/effect path resolution (ADR-014, Refs #228) by hyperpolymath · Pull Request #447 · hyperpolymath/affinescript Conversation
Owner
SummarySymmetric to #178 ( Closes the resolution half of the #228 work whose parser half landed in #241 (ADR-014). What changes
Before / after
Tests
Full suite: Out of scope (surfaced in #228 design comment)These are real but separate; I'll file follow-ups if the seam-analyst note isn't already tracked elsewhere:
RefsRefs #228 (this is the resolution slice; parser slice was #241)
Sorry, something went wrong. Uh oh!
There was an error while loading. Please reload this page. All reactionsSymmetric to PR #178 (`Resolve.lower_qualified_value_paths`) at the value-path layer: when a folded `Mod::T` reaches `lower_type_expr` / `lower_effect_expr`, the leading `Mod::` qualifier is stripped iff `Mod` was introduced by a `use Mod;` decl in the program, raising a clear `UnknownModule` error otherwise. Before: `pub fn f(x: NoSuchMod.Thing) -> ()` passed typecheck silently (folded `TyCon "NoSuchMod::Thing"` fell through the TyCon lookup as an abstract `TCon`). After: it fails with `Unknown module 'NoSuchMod' in qualified type/effect reference (ADR-014, #228). Add `use NoSuchMod;` to bring the module into scope, …`. The same path now governs effect position — replacing the pre-existing misleading `declare `effect NoSuchMod::IO;`` hint with the correct UnknownModule message. Surface: • `type_error`: new `UnknownModule of string` constructor + formatter (cites ADR-014/#228, suggests `use M;` or `use M::{Item};`). • new `Module_resolution_error` exception (paralleling `Effect_validation_error`); caught at `check_program` boundary. • `context`: new `module_quals : (string, unit) Hashtbl.t` populated from `prog.prog_imports` at `check_program` entry — `ImportSimple` only, matching the value-path semantics in `Resolve.import_qualifiers`. • new `strip_module_qualifier` helper called from `TyCon`/`TyApp` arms of `lower_type_expr` and the `resolve` helper in `lower_effect_expr`. No AST walk; the lowering chokepoints already visit every type/effect site. Tests (`test/test_qualified_paths.ml`, 6 cases, all green): • qualified type + `use` (both `.` and `::` separators) → passes • qualified type, no `use` → UnknownModule with correct attribution • qualified effect, no `use` → UnknownModule (not UnknownEffect) • bare TyCon unchanged (regression guard for lenient-unknown pre-existing behaviour) • qualified reserved effect (`Net`) + `use` → strips & resolves into the reserved-effect path (proves strip happens before the canonical-effect lookup) Out of scope for this PR (surfaced in the #228 design comment): • lowercase-module qualified refs (`json.Value`) still parse-error because `qualified_type_name` head requires `upper_ident` • `use A.B;` registers only `B` as the qualifier • `use A::{Item}` (multi-segment + brace-list) parse-errors • bare unknown TyCons silently pass typecheck (broader, pre-existing) Build: `dune build @test/runtest` → 352/352 OK. Refs #228 Refs metadatastician/standards#124
hyperpolymath
enabled auto-merge (squash)
All reactions
Sorry, something went wrong. Uh oh!
There was an error while loading. Please reload this page. Uh oh!
There was an error while loading. Please reload this page.
This was referenced
hyperpolymath
added a commit
that referenced
this pull request
…448 item 1) (#523) ## Summary Item 1 of the qualified-path adjacent gaps surfaced by #448: the `qualified_type_name` production in `lib/parser.mly:154-161` required `upper_ident` as the head segment, so qualified type paths whose first segment was a lowercase stdlib module name (`json`, `option`, `prelude`, `dict`, `alib`, `collections`, `io`, `string`, `result`, `testing`, `effects`, `math`) parse-errored at the separator (`.` or `::`). Reported symptom: `parse error at .` on `x: json.Value` even with `use json;` in scope. ## Fix Add a parallel production with `lower_ident` head: ```ocaml qualified_type_name: | head = upper_ident qsep rest = qualified_type_name_rest { head ^ "::" ^ rest } | head = lower_ident qsep rest = qualified_type_name_rest { head ^ "::" ^ rest } ``` `qualified_type_name_rest` stays `upper_ident`-only — the tail segment is the type/effect name proper (a TyCon), so it must remain uppercase. Only the *qualifier* segment was wrongly constrained. Option (b) from #448 (relax the parser) rather than (a) (rename stdlib modules), per the original triage. ## LR(1) safety The disambiguation strategy is symmetric to the existing `upper_ident` path: a bare `lower_ident` in type position reduces to TyVar (existing rule at line 504); the parser only shifts past the `lower_ident` if the next token is a `qsep` (`.` or `::`). Menhir reports the **same conflict counts** as before the change (21 / 1 / 68 / 7), confirming no new conflicts introduced. ## Tests Three new cases in `test/test_qualified_paths.ml`: - `#448(1) lowercase qualifier head parses` — `x: json.Value` no longer emits a parse error - `#448(1) lowercase qualifier head + ::` parses — same with the `::` separator - `#448(1) fully-lowercase qualified path still rejected` — `x: json.value` MUST still parse-error because the tail segment is now reaching `qualified_type_name_rest` which still requires `upper_ident` (regression guard) Test results: `dune runtest` → **366 tests passed** (was 363); no regressions on existing `test_qualified_paths` cases. ## Scope Closes **#448 item 1** only. Does NOT address: - Item 2 (`use A.B;` leaf-only qualifier registration) - Item 3 (`use A::{Item}` multi-segment brace-list parse) - Item 4 (bare unknown TyCon permissive lookup) Those remain open under the parent issue. ## Downstream Unblocks `Pkg.Type` syntax with lowercase stdlib heads — directly helps hyperpolymath/echidna#117 (Client.res AffineScript-TEA port) which had `json.Value` / `dict.Dict` references that were stranded behind this parse error. Refs #228, refs #447, refs #241.
This was referenced
hyperpolymath
added a commit
that referenced
this pull request
…oses #547) (#550) ## Summary Closes #547. The slash-effect-row form `fn(...) -> T / { E1, E2 }` (and its single-effect short form `fn(...) -> T / E`) parses today only in fn-decl signatures (`return_type`, lines 271-282); it parse-errors in record-field and type-alias positions, forcing every effectful function-typed record field to fall back to the older `-{E}->` arrow form. This is a parser asymmetry, not a language-design question. Surfaced during the post-#228 idaptik port batch in [`hyperpolymath/idaptik#153`](https://github.com/hyperpolymath/idaptik/pull/153). ## Surface-grammar diff ``` type_expr_arrow: | T -> R (already) | T -{E}-> R (already) + | T -> R / { E1, E2, ... } (this PR) + | T -> R / E (this PR) type_expr_primary (FN form, fn-as-type): | fn(A, ...) -> R (already) | fn(A, ...) -{E}-> R (already) + | fn(A, ...) -> R / { E1, ... } (this PR) + | fn(A, ...) -> R / E (this PR) ``` Both spellings remain accepted. `-{E}->` semantics are unchanged. ## Verification - `dune build bin/main.exe` — clean - `dune runtest` — **376/376 PASS** (368 baseline + 8 new) - **Conflict count unchanged** (21 s/r, 1 r/r — same as pre-PR) - Headline probes (all `Type checking passed`): ``` pub type AsyncCall = fn(Int) -> Int / { Async }; pub type H = { call: fn(Int) -> Int / { Async } } pub type H = { call: fn(Int) -> Int / Async } // single short pub type Multi = fn(Int, String) -> Bool / { IO, Async }; pub type R = Int -> Int / { Mut }; // arrow-as-type pub type R = fn() -> () / { IO }; // zero-arg ``` ## Semantic note (which arrow the effect attaches to) - In `type_expr_arrow` (no `fn(...)` wrapper), the slash effect attaches to the **outermost** arrow — the position of the slash itself. This is the natural reading of `A -> B / { E }`. - In the FN-form (`fn(A, B) -> R / { E }`), the effect attaches to the **innermost** arrow (the call site), matching the established prefix-row `-{E}->` FN-form precedent (lines 555-582). This is what consumers expect when porting `fn(A, B) -{E}-> R`. For users who want inner-arrow effect attachment in arrow-as-type positions, the existing `-{E}->` form continues to express that. ## Refs - Closes #547 - Refs #228 (sibling parser-asymmetry gap, closed in #241 / #447 / #523) - Refs #229 (estate-wide ReScript-surface elimination) - Refs #548 (sibling gap from the same port batch — module-level mutable bindings, PR #549) - Refs hyperpolymath/idaptik#153 (the port batch that surfaced this) 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Signed-off-by: hyperpolymath <[email protected]> Signed-off-by: Jonathan D.A. Jewell <[email protected]> Co-authored-by: Claude Opus 4.7 (1M context) <[email protected]>
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
ReviewersNo reviewsUh oh!
There was an error while loading. Please reload this page. AssigneesNo one assignedLabels
None yet
ProjectsMilestoneNo milestoneDevelopmentSuccessfully merging this pull request may close these issues. Uh oh!
There was an error while loading. Please reload this page. Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later. | ||||||||||||||||||||||||
| You are visitor 01402503 — GeezerVison does not store the pages you look up. Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required. |