spec: canonical type names — class-names out-of-scope rationale
This commit is contained in:
@@ -85,7 +85,7 @@ The milestone decomposes into four iterations.
|
||||
|
||||
| Iter | Scope |
|
||||
|------|-------|
|
||||
| **ct.1** | `.ail.json` schema validator at `load_workspace` (the rule above) + one-time migration. The migration is targeted: a workspace-walker tool (small Rust binary or test-driven script under `crates/ail/src/bin/`) reads every `.ail.json` under `examples/`, finds bare cross-module Type::Con names (i.e. bare names that don't resolve to a local type def in the same file), looks up the qualified form via the import graph, rewrites in place. Files with only intra-module refs are unchanged. Single bulk commit for the rewritten fixtures. |
|
||||
| **ct.1** | `.ail.json` schema validator at `load_workspace` (the rule above) + one-time migration. The migration is targeted: a workspace-walker tool (small Rust binary or test-driven script under `crates/ail/src/bin/`) reads every `.ail.json` under `examples/`, finds bare cross-module Type::Con names (i.e. bare names that don't resolve to a local type def in the same file), looks up the qualified form via the import graph, rewrites in place. Files with only intra-module refs are unchanged. Single bulk commit for the rewritten fixtures. The validator also rejects *qualified* class-name fields (`InstanceDef.class`, `SuperclassRef.class`, `Constraint.class`) — those stay bare per the Out-of-scope note. |
|
||||
| **ct.2** | Remove obsolete typechecker mechanisms that papered over bare cross-module refs: `Pattern::Ctor`'s imports-fallback (iter 15a, ~`crates/ailang-check/src/lib.rs:2486-2521`) and `Term::Ctor`'s synth imports-fallback (iter 23.1.3, ~lib.rs:1979-2025). Both become unreachable because bare-non-primitive type-name reaches them only when local (direct lookup succeeds) — never as a stale cross-module ref. **`qualify_local_types` (iter 15a, ~lib.rs:1848) STAYS** — it correctly handles the cross-boundary translation when a cross-module fn signature is pulled into the current module's typecheck context. Under the new rule it becomes more prominent (called uniformly at every cross-module fn-lookup boundary, where today it runs only at the Term::Var prefix-qualified path); this iter audits its call sites for consistency. |
|
||||
| **ct.3** | Remove obsolete codegen + mono mechanisms: `lookup_ctor_by_type`'s imports-fallback (iter 23.1.4) and `apply_per_module_ctor_index_overlay` in mono (iter 23.2 fix `84dcc46`). The codegen `lower_workspace_inner` implicit-prelude import_map entry (iter 23.2.4 fix `be882c4`) STAYS — fn-name resolution for mono symbols, not Type::Con names. |
|
||||
| **ct.4** | DESIGN.md amendments + JOURNAL migration entry + re-baseline of hash-pinned regression tests that touched cross-module-ref fixtures + IR snapshot refresh (where affected). Form-B prose round-trip test extended to cover the qualifier-trim-on-print behaviour for intra-module refs. |
|
||||
@@ -261,12 +261,41 @@ many ambiguity cases are caught earlier by the validator.
|
||||
local-to-this-file, qualified = explicit cross-module). No
|
||||
imports-fallback needed in the pattern path.
|
||||
|
||||
- **Class names** (`class Eq`, `instance Eq Int`, `class Ord extends Eq`,
|
||||
`Constraint.class`): same conceptual shape as Type::Con but separate
|
||||
namespace, separate uniqueness check (`MethodNameCollision`). Whether
|
||||
class names should also follow the same module-scoping rule is a
|
||||
separate spec question deferred to a future milestone. This spec
|
||||
touches Type::Con only.
|
||||
- **Class names** (`ClassDef.name`, `InstanceDef.class`,
|
||||
`SuperclassRef.class`, `Constraint.class`): NOT migrated to the
|
||||
module-scoped canonical form in this milestone. The asymmetry to
|
||||
Type::Con is intentional and rests on a real semantic difference:
|
||||
|
||||
- For types, no workspace-global uniqueness rule exists. Two modules
|
||||
may independently declare `type Foo`. Bare cross-module references
|
||||
are therefore genuinely ambiguous; the iter-23.3 bug is the
|
||||
concrete instance of that ambiguity surfacing in unification.
|
||||
|
||||
- For classes, workspace-global uniqueness is enforced one level
|
||||
deeper: `WorkspaceLoadError::MethodNameCollision` (iter 22b.2,
|
||||
`workspace.rs:472`) rejects two classes that share any method
|
||||
name. Two `class Eq`s with the conventional `eq` method cannot
|
||||
coexist; `class_by_name: BTreeMap<String, &ClassDef>` (workspace-
|
||||
flat) is consistent with that invariant. Empirically no
|
||||
`examples/` fixture today has a bare cross-module class
|
||||
reference that resolves ambiguously — the cross-module fixtures
|
||||
that exist (`test_22b3_xmod_e2e_main`) call methods bare and rely
|
||||
on the method→class→instance chain, never on a direct class-name
|
||||
reference.
|
||||
|
||||
Three class-reference fields (`InstanceDef.class`,
|
||||
`SuperclassRef.class`, `Constraint.class`) gain a *defensive*
|
||||
validator check in ct.1: reject qualified forms (containing `'.'`)
|
||||
explicitly, since the schema does not currently model qualified
|
||||
class names. This prevents half-migrated files from silently
|
||||
loading.
|
||||
|
||||
If AILang ever revisits workspace-global method-name uniqueness
|
||||
(e.g. introduces module-qualified method names so two libraries
|
||||
can each declare `class Eq` with its own `eq`), the symmetry to
|
||||
Type::Con returns and class names will need the same module-scoped
|
||||
treatment. That is a separate DESIGN-level milestone and is not
|
||||
this spec's scope.
|
||||
|
||||
- **Surface notation in `.ailx`**: bare local names continue to be
|
||||
the LLM-author convention. Prose parser/printer bridge — no
|
||||
|
||||
Reference in New Issue
Block a user