Commit 2096605
committed
feat(parser): accept lower_ident head in qualified_type_name (closes #448 item 1)
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:
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.
The change is option (b) from #448 (relax the parser) rather than
(a) (rename stdlib modules), per the original triage which noted
that (a) would force a cascade of multi-file renames across stdlib
and every `.affine` consumer for a stylistic convention shift,
while (b) is a single-grammar-rule change with isolated impact.
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 `::`). The Menhir
build 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 (post-parse errors like
`UnknownModule` are acceptable; what we forbid is the pre-fix
`parse error at .`).
- `#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 against accidentally relaxing
too far.
Test results: `dune runtest` → 366 tests passed (was 363); no
regressions on existing test_qualified_paths cases.
Closes #448 item 1. Does NOT address items 2 (use A.B; leaf-only
qualifier), 3 (use A::{Item} brace-list), or 4 (bare unknown TyCon
permissive lookup) — those remain open under their parent issue.
Refs #228, refs #447, refs #241.1 parent fffae8b commit 2096605
2 files changed
Lines changed: 50 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
154 | 154 | | |
155 | 155 | | |
156 | 156 | | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
157 | 165 | | |
158 | 166 | | |
159 | 167 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
103 | 103 | | |
104 | 104 | | |
105 | 105 | | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
106 | 142 | | |
107 | 143 | | |
108 | 144 | | |
| |||
116 | 152 | | |
117 | 153 | | |
118 | 154 | | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
119 | 161 | | |
0 commit comments