source: scrub iter-code / Decision-N residue from inline comments
Follow-up to bcd4181: the remaining ~530 inline `//` and `///`
comments still carrying opaque shorthand are now reformulated to
their content phrases. The only surviving `iter-<code>` reference
in source is the literal filename
`docs/journals/2026-05-13-iter-mq.3.md` (a real journal file).
Sweep covered:
- `// Iter X.Y: <text>` prefixes (Iter 13a / 14a / 14e / 15g-aux /
16b.x / 16d / 16e / 18b / 18c.x / 18d.x / 18e / 18g.x / 19a /
19a.1 / 19b / 20a / 20f / 22-floats.x / 22b.x / 22c / 23.x /
24.1 / cli-diag-human / hs.x / str-concat / etc.) — fully
removed; the descriptive text that followed each prefix stays.
- `// (Decision N)` and `per Decision N` and `Decision N axis 3` —
replaced with the content phrase plus the relevant contract
file (`design/contracts/tail-calls.md` for Decision 8,
`design/contracts/memory-model.md` for Decision 10,
`design/contracts/typeclasses.md` and `design/models/typeclasses.md`
for Decision 11, `design/contracts/authoring-surface.md` for
Decision 6, "the transitional dual-allocator" for Decision 9,
"Effect prose" for Decision 3).
- `// mq.X / mq.X (Task N) / mq.X journal / mq.X invariant` ->
"the canonical-class-form rule / Class-class repurpose /
method-dispatch-refactor journal / canonical-class-form
invariant".
- `// ct.X / ct.X (canonical-type-names) / ct.1.5a + ctt.2 /
ct.2 Task N` -> "the canonical-form rule for type references /
the canonical-form normalisation step / canonical-type-lookup
refactor".
- `// eob.X` -> "heap-Str-ABI" / "the Str carve-out".
- `// rpe.X` -> "the per-type-print-op retirement".
- `// post-mq.X / Pre-ct.X / pre-mq.X` -> "post-canonical-class-form" /
"Pre-canonical-type-form" etc.
- `/// Iter X regression: / /// Iter X.Y: / /// Iter A arm-close /
/// Iter ct.4 (...): / /// Iter rpe.1 ...` -> descriptive
phrases.
The journal filename in `crates/ailang-core/src/workspace.rs:573`
stays verbatim because it points at an actual file under
`docs/journals/`.
Tests: full `cargo test --workspace` green (80/80 test-result blocks
clean, no FAILED line). design_index_pin 5/5 + docs_honesty_pin 5/5
gating tests pass.
This commit is contained in:
+119
-117
@@ -40,7 +40,7 @@ use std::path::{Path, PathBuf};
|
||||
/// by `Module.name`. `root_dir` is the directory the entry file lives
|
||||
/// in; all imports are resolved relative to it.
|
||||
///
|
||||
/// Iter 22b.1 (Decision 11): `registry` is the workspace-global
|
||||
/// `registry` is the workspace-global
|
||||
/// instance registry, built at the end of [`load_workspace`] after the
|
||||
/// DFS over imports completes. It is empty for any workspace whose
|
||||
/// modules contain no [`crate::ast::Def::Instance`] defs.
|
||||
@@ -55,11 +55,11 @@ pub struct Workspace {
|
||||
/// Directory the entry file lives in; all imports are resolved
|
||||
/// relative to it.
|
||||
pub root_dir: PathBuf,
|
||||
/// Iter 22b.1: workspace-global typeclass instance registry.
|
||||
/// workspace-global typeclass instance registry.
|
||||
pub registry: Registry,
|
||||
}
|
||||
|
||||
/// Iter 22b.1: workspace-global instance registry (Decision 11).
|
||||
/// workspace-global instance registry (the typeclass design).
|
||||
///
|
||||
/// Built at the end of [`load_workspace`] after all modules are
|
||||
/// loaded. Keyed by `(class-name, canonical-type-hash)`; values are
|
||||
@@ -71,7 +71,7 @@ pub struct Workspace {
|
||||
/// 22b.1 enforces three coherence checks during build:
|
||||
///
|
||||
/// 1. **Coherence (orphan-freedom).** Every `instance C T` lives in
|
||||
/// the module of `C` or in the module of `T` (per Decision 11
|
||||
/// the module of `C` or in the module of `T` (per the typeclass design
|
||||
/// axis 3). Otherwise → [`WorkspaceLoadError::OrphanInstance`].
|
||||
/// 2. **Uniqueness.** No two entries share a key. Otherwise →
|
||||
/// [`WorkspaceLoadError::DuplicateInstance`].
|
||||
@@ -82,7 +82,7 @@ pub struct Workspace {
|
||||
pub struct Registry {
|
||||
/// Map from `(class-name, type-hash)` to the registry entry.
|
||||
pub entries: BTreeMap<(String, String), RegistryEntry>,
|
||||
/// ct.1.5a: workspace-wide map from user-defined type-name to its
|
||||
/// workspace-wide map from user-defined type-name to its
|
||||
/// defining module. Used by [`Self::normalize_type_for_lookup`] to
|
||||
/// rewrite a bare `Type::Con.name` to its always-qualified form
|
||||
/// before computing the registry key. Primitives are not present.
|
||||
@@ -104,7 +104,7 @@ pub struct Registry {
|
||||
}
|
||||
|
||||
impl Registry {
|
||||
/// ct.1.5a + ctt.2: produce the canonical form of `t` for
|
||||
/// the canonical-form normalisation step: produce the canonical form of `t` for
|
||||
/// registry-key hashing. Bare-non-primitive `Type::Con` names
|
||||
/// get qualified to `<defining_module>.<name>`; already-qualified
|
||||
/// names stay; bare names whose defining module is unknown stay
|
||||
@@ -201,10 +201,11 @@ pub enum WorkspaceLoadError {
|
||||
)]
|
||||
ModuleHashMismatch { name: String },
|
||||
|
||||
/// Iter 22b.1: an [`crate::ast::Def::Instance`] was declared in a
|
||||
/// an [`crate::ast::Def::Instance`] was declared in a
|
||||
/// module that is neither the class's defining module nor the
|
||||
/// instance type's defining module. Coherence violation per
|
||||
/// Decision 11 axis 3 ("orphan-freedom"). The lookup is hard:
|
||||
/// the orphan-freedom axis of the typeclass design. The lookup
|
||||
/// is hard:
|
||||
/// AILang does not provide a `--allow-orphans` flag.
|
||||
#[error(
|
||||
"orphan instance: `instance {class} {type_repr}` declared in module `{defining_module}`, \
|
||||
@@ -218,10 +219,10 @@ pub enum WorkspaceLoadError {
|
||||
type_module: String,
|
||||
},
|
||||
|
||||
/// Iter 22b.1: two [`crate::ast::Def::Instance`]s share the same
|
||||
/// two [`crate::ast::Def::Instance`]s share the same
|
||||
/// `(class, canonical-type-hash)` key. Coherence requires
|
||||
/// uniqueness; the registry has no way to disambiguate at
|
||||
/// resolution time. Per Decision 11 there is no
|
||||
/// resolution time. Per the typeclass design there is no
|
||||
/// `AmbiguousInstance` diagnostic — coherence makes the lookup
|
||||
/// unambiguous by construction, and a duplicate is a workspace
|
||||
/// configuration error, not a per-call-site one.
|
||||
@@ -235,11 +236,11 @@ pub enum WorkspaceLoadError {
|
||||
second_module: String,
|
||||
},
|
||||
|
||||
/// Iter 22b.1: an [`crate::ast::Def::Instance`] does not specify
|
||||
/// an [`crate::ast::Def::Instance`] does not specify
|
||||
/// a body for a required (non-default) method of its class.
|
||||
/// Default-bearing methods may be inherited; non-default
|
||||
/// (abstract-required) methods must be specified by every
|
||||
/// instance. Per Decision 11 §"Defaults and superclasses".
|
||||
/// instance. Per the typeclass design §"Defaults and superclasses".
|
||||
#[error(
|
||||
"instance `{class} {type_repr}` is missing a body for method `{method}` (no default)"
|
||||
)]
|
||||
@@ -249,8 +250,8 @@ pub enum WorkspaceLoadError {
|
||||
method: String,
|
||||
},
|
||||
|
||||
/// Iter 22b.2: class-schema validation. A class's `superclass.type`
|
||||
/// does not equal its own `param`. Decision 11 single-superclass
|
||||
/// class-schema validation. A class's `superclass.type`
|
||||
/// does not equal its own `param`. the typeclass design's single-superclass
|
||||
/// model requires the superclass to be applied to the same param
|
||||
/// (e.g. `class Ord a extends Eq a`, not `extends Eq b`).
|
||||
#[error(
|
||||
@@ -264,7 +265,7 @@ pub enum WorkspaceLoadError {
|
||||
got_type: String,
|
||||
},
|
||||
|
||||
/// Iter 22b.2: class-schema validation. A class method's
|
||||
/// class-schema validation. A class method's
|
||||
/// signature contains a constraint referencing a type variable
|
||||
/// that is neither bound by the method's `Forall.vars` nor equal
|
||||
/// to the class's `param`.
|
||||
@@ -278,7 +279,7 @@ pub enum WorkspaceLoadError {
|
||||
var: String,
|
||||
},
|
||||
|
||||
/// Iter 22b.2: an instance specifies a body for a method name
|
||||
/// an instance specifies a body for a method name
|
||||
/// that the corresponding class does not declare. Symmetric to
|
||||
/// `MissingMethod` but in the opposite direction.
|
||||
#[error(
|
||||
@@ -290,9 +291,9 @@ pub enum WorkspaceLoadError {
|
||||
method: String,
|
||||
},
|
||||
|
||||
/// Iter 22b.2: an instance `C T` was declared, but `C`'s
|
||||
/// an instance `C T` was declared, but `C`'s
|
||||
/// superclass `S` does not have an instance for the same type
|
||||
/// `T`. Decision 11 single-superclass model requires `instance S
|
||||
/// `T`. the typeclass design's single-superclass model requires `instance S
|
||||
/// T` to exist whenever `instance C T` exists.
|
||||
#[error(
|
||||
"instance `{class} {type_repr}` requires superclass instance `{superclass} {type_repr}`, but none was found"
|
||||
@@ -303,14 +304,14 @@ pub enum WorkspaceLoadError {
|
||||
type_repr: String,
|
||||
},
|
||||
|
||||
/// Iter 23.1: a user module attempted to use the reserved
|
||||
/// a user module attempted to use the reserved
|
||||
/// module name `prelude`. The prelude is auto-injected by
|
||||
/// the loader, so a user module of the same name would
|
||||
/// collide silently. Reject explicitly.
|
||||
#[error("module name {name:?} is reserved (auto-injected by the loader)")]
|
||||
ReservedModuleName { name: String },
|
||||
|
||||
/// ct.1 (canonical-type-names): a `Type::Con` whose `name` is
|
||||
/// the canonical-form rule for type references: a `Type::Con` whose `name` is
|
||||
/// neither a primitive nor a local TypeDef of the owning module
|
||||
/// was encountered. Under the canonical-form rule, bare =
|
||||
/// local; a bare cross-module ref is a schema violation.
|
||||
@@ -327,7 +328,7 @@ pub enum WorkspaceLoadError {
|
||||
candidates: Vec<String>,
|
||||
},
|
||||
|
||||
/// ct.1: a qualified `Type::Con` of the form `<owner>.<type>`
|
||||
/// a qualified `Type::Con` of the form `<owner>.<type>`
|
||||
/// was encountered, but `<owner>` is not a known module in the
|
||||
/// workspace, or `<owner>` is known but declares no TypeDef
|
||||
/// named `<type>`.
|
||||
@@ -340,11 +341,11 @@ pub enum WorkspaceLoadError {
|
||||
name: String,
|
||||
},
|
||||
|
||||
/// mq.1 (canonical-class-names): a class-reference field
|
||||
/// the canonical-form rule for class references: a class-reference field
|
||||
/// (`InstanceDef.class`, `Constraint.class`, or
|
||||
/// `SuperclassRef.class`) carries a bare name that does not resolve
|
||||
/// to a local class of the owning module. Under the canonical-form
|
||||
/// rule extended in mq.1, bare = local-class-of-owning-module; a
|
||||
/// rule extended for class references, bare = local-class-of-owning-module; a
|
||||
/// bare cross-module class reference is a schema violation.
|
||||
/// `candidates` lists the qualified forms found by scanning the
|
||||
/// owning module's imports for matching class declarations.
|
||||
@@ -359,7 +360,7 @@ pub enum WorkspaceLoadError {
|
||||
candidates: Vec<String>,
|
||||
},
|
||||
|
||||
/// mq.1 (canonical-class-names): a qualified class reference of
|
||||
/// the canonical-form rule for class references: a qualified class reference of
|
||||
/// the form `<owner>.<class>` was encountered, but `<owner>` is
|
||||
/// not a known module in the workspace, or `<owner>` is known
|
||||
/// but declares no class by that name. Sibling of
|
||||
@@ -373,14 +374,14 @@ pub enum WorkspaceLoadError {
|
||||
name: String,
|
||||
},
|
||||
|
||||
/// ct.1: a class-reference field (`InstanceDef.class`,
|
||||
/// a class-reference field (`InstanceDef.class`,
|
||||
/// `SuperclassRef.class`, `Constraint.class`, or
|
||||
/// `ClassDef.name`) contains a `.` — under this milestone class
|
||||
/// names are NOT module-qualified (see DESIGN spec §"Out of
|
||||
/// scope: Class names"). The schema rejects qualified forms so
|
||||
/// half-migrated files cannot silently load.
|
||||
///
|
||||
/// mq.1: narrowed to `ClassDef.name` only; the three other
|
||||
/// narrowed to `ClassDef.name` only; the three other
|
||||
/// fields now follow the canonical-form rule and use
|
||||
/// `BareCrossModuleClassRef` / `BadCrossModuleClassRef`.
|
||||
#[error(
|
||||
@@ -497,10 +498,10 @@ pub fn build_workspace(
|
||||
// `ailang_surface::PRELUDE_AIL` + `ailang_surface::parse_prelude`); core
|
||||
// exposes the two-phase composition.
|
||||
|
||||
/// mq.1: take a class-ref field value (`InstanceDef.class`,
|
||||
/// take a class-ref field value (`InstanceDef.class`,
|
||||
/// `SuperclassRef.class`, `Constraint.class`) and a defining context,
|
||||
/// and produce the qualified workspace key. Bare ⇒ prepend the
|
||||
/// `caller_module` argument; qualified ⇒ as-is. Symmetric to ct.1's
|
||||
/// `caller_module` argument; qualified ⇒ as-is. Symmetric to the canonical-form rule's
|
||||
/// `normalize_type_for_registry` for `Type::Con`.
|
||||
///
|
||||
/// For an `InstanceDef.class` or `Constraint.class` field the caller
|
||||
@@ -514,7 +515,7 @@ fn qualify_class_ref(class_ref: &str, caller_module: &str) -> String {
|
||||
}
|
||||
}
|
||||
|
||||
/// Iter 22b.1: build the workspace-global typeclass instance registry.
|
||||
/// build the workspace-global typeclass instance registry.
|
||||
///
|
||||
/// Two passes:
|
||||
///
|
||||
@@ -534,7 +535,7 @@ fn build_registry(
|
||||
// Pass 1: collect "where is X defined" maps, plus a class lookup
|
||||
// by name (needed for the method-completeness check).
|
||||
//
|
||||
// mq.1: `class_def_module` and `class_by_name` are keyed by the
|
||||
// `class_def_module` and `class_by_name` are keyed by the
|
||||
// qualified class name `<defining_module>.<class>`. All consumers
|
||||
// (Pass-2 coherence lookup, method-completeness check, superclass
|
||||
// walk, etc.) query with `qualify_class_ref` applied to the field
|
||||
@@ -562,7 +563,7 @@ fn build_registry(
|
||||
}
|
||||
}
|
||||
|
||||
// mq.3: the `MethodNameCollision` pre-pass (variant + Origin enum +
|
||||
// the `MethodNameCollision` pre-pass (variant + Origin enum +
|
||||
// per-def loop) was retired here. Bare-method resolution no longer
|
||||
// requires workspace-wide method-name uniqueness — synth's
|
||||
// `Term::Var` arm consults `Env.method_to_candidate_classes`
|
||||
@@ -588,7 +589,7 @@ fn build_registry(
|
||||
// user-defined module — instances on primitives
|
||||
// therefore must live in the class's module.
|
||||
//
|
||||
// mq.1: lookup keys are qualified
|
||||
// lookup keys are qualified
|
||||
// (`<defining_module>.<class>`); the `inst.class`
|
||||
// field is the canonical-form value (bare or qualified)
|
||||
// which `qualify_class_ref` lifts to the workspace key.
|
||||
@@ -597,7 +598,7 @@ fn build_registry(
|
||||
.get(&inst_class_key)
|
||||
.cloned()
|
||||
.unwrap_or_else(|| "<unknown-class>".into());
|
||||
// mq.1: type-leg lookup must accept the canonical form
|
||||
// type-leg lookup must accept the canonical form
|
||||
// for the head name. Bare head ⇒ key by
|
||||
// (caller_module, head); qualified `<owner>.<bare>` ⇒
|
||||
// key by (owner, bare) directly (the owner IS the
|
||||
@@ -625,14 +626,14 @@ fn build_registry(
|
||||
}
|
||||
|
||||
// Uniqueness: a `(class, type-hash)` key must appear
|
||||
// at most once across the whole workspace. ct.1.5a: the
|
||||
// at most once across the whole workspace. The
|
||||
// type expression is normalised to its always-qualified
|
||||
// form before hashing so a bare-local declaration in
|
||||
// the type's defining module and a qualified-cross-module
|
||||
// declaration from elsewhere produce the same key (both
|
||||
// refer to the same type under the canonical-form rule).
|
||||
//
|
||||
// mq.1: registry key is keyed by the qualified class
|
||||
// registry key is keyed by the qualified class
|
||||
// form too, so a bare same-module instance and a
|
||||
// qualified cross-module instance on the same
|
||||
// (class, type) collide on this check.
|
||||
@@ -677,7 +678,7 @@ fn build_registry(
|
||||
|
||||
// Symmetric to MissingMethod: an instance must
|
||||
// not specify a body for a method name the class
|
||||
// never declared. Decision 11 forbids ad-hoc
|
||||
// never declared. The typeclass design forbids ad-hoc
|
||||
// additions to a class's method set at the
|
||||
// instance site.
|
||||
let declared: BTreeSet<&str> =
|
||||
@@ -704,11 +705,11 @@ fn build_registry(
|
||||
}
|
||||
}
|
||||
|
||||
// Iter 22b.2: superclass-instance completeness. For every entry,
|
||||
// superclass-instance completeness. For every entry,
|
||||
// walk the class's superclass chain and require an entry for each
|
||||
// step at the same type-hash.
|
||||
//
|
||||
// mq.1: `class_name` (the entries key first half) is the qualified
|
||||
// `class_name` (the entries key first half) is the qualified
|
||||
// class name; the superclass-ref field `sc.class` is canonical-form,
|
||||
// which `qualify_class_ref` lifts to the qualified key — using the
|
||||
// parent class's defining module as the caller context (the
|
||||
@@ -716,7 +717,7 @@ fn build_registry(
|
||||
for (key, entry) in entries.iter() {
|
||||
let (class_name, type_hash) = key;
|
||||
let type_repr = type_head_name(&entry.instance.type_);
|
||||
// Iter 22b.2 leaves superclass-cycle detection to a future arm;
|
||||
// Superclass-cycle detection is left to a future arm;
|
||||
// here we just terminate the walk.
|
||||
let mut visited: BTreeSet<&str> = BTreeSet::new();
|
||||
let mut current = class_by_name.get(class_name.as_str()).copied();
|
||||
@@ -738,7 +739,7 @@ fn build_registry(
|
||||
type_repr: type_repr.clone(),
|
||||
});
|
||||
}
|
||||
// mq.1: walk lookup uses the qualified key; the next
|
||||
// walk lookup uses the qualified key; the next
|
||||
// step's owning-module context is the superclass's
|
||||
// defining module (read from `class_def_module`).
|
||||
current = class_by_name.get(sc_class_key.as_str()).copied();
|
||||
@@ -758,7 +759,7 @@ fn build_registry(
|
||||
})
|
||||
}
|
||||
|
||||
/// Iter 22b.2: class-schema validation. Runs before `build_registry`.
|
||||
/// class-schema validation. Runs before `build_registry`.
|
||||
/// Two diagnostics fire from here: `invalid-superclass-param`,
|
||||
/// `constraint-references-unbound-type-var`. The `kind-mismatch`
|
||||
/// diagnostic was retired at ctt.3 — the malformed shape now
|
||||
@@ -805,7 +806,7 @@ fn validate_classdefs(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// ct.1: the five primitive type names that are always bare under
|
||||
/// the five primitive type names that are always bare under
|
||||
/// the canonical-form rule. Kept in sync with `Type::int`,
|
||||
/// `Type::bool_`, `Type::str_`, `Type::unit`, `Type::float` in
|
||||
/// `crate::ast`.
|
||||
@@ -813,7 +814,7 @@ fn is_primitive_type_name(name: &str) -> bool {
|
||||
matches!(name, "Int" | "Bool" | "Str" | "Unit" | "Float")
|
||||
}
|
||||
|
||||
/// ct.1.5a: normalize a `Type` by qualifying every bare-non-primitive
|
||||
/// normalize a `Type` by qualifying every bare-non-primitive
|
||||
/// `Type::Con.name` to its always-qualified form
|
||||
/// (`<defining_module>.<name>`). Primitives stay bare; already-qualified
|
||||
/// names stay as-is; bare names whose defining module is unknown stay
|
||||
@@ -891,7 +892,7 @@ fn normalize_type_for_registry(
|
||||
}
|
||||
}
|
||||
|
||||
/// ct.1: enforce the canonical-form rule on every `Type::Con` and
|
||||
/// enforce the canonical-form rule on every `Type::Con` and
|
||||
/// `Term::Ctor.type_name` reference in every loaded module. Runs
|
||||
/// after prelude injection and before class-schema validation, so a
|
||||
/// stale bare cross-module ref fires the canonical-form diagnostic
|
||||
@@ -922,7 +923,7 @@ pub(crate) fn validate_canonical_type_names(
|
||||
local_types.insert(mod_name.clone(), s);
|
||||
}
|
||||
|
||||
// mq.1: symmetric pre-pass over `Def::Class` names. The map is
|
||||
// symmetric pre-pass over `Def::Class` names. The map is
|
||||
// module → bare-class-name set; used by `check_class_ref` to apply
|
||||
// the canonical-form rule to the three migrated class-ref fields
|
||||
// (`InstanceDef.class`, `Constraint.class`, `SuperclassRef.class`).
|
||||
@@ -961,7 +962,7 @@ pub(crate) fn validate_canonical_type_names(
|
||||
})?;
|
||||
check_class_name_fields(def, mod_name)?;
|
||||
|
||||
// mq.1: apply the canonical-form rule to the three
|
||||
// apply the canonical-form rule to the three
|
||||
// migrated class-ref fields.
|
||||
match def {
|
||||
Def::Instance(id) => {
|
||||
@@ -994,7 +995,7 @@ pub(crate) fn validate_canonical_type_names(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// mq.1: apply the canonical-form rule to a class-reference field
|
||||
/// apply the canonical-form rule to a class-reference field
|
||||
/// value (`InstanceDef.class`, `Constraint.class`, or
|
||||
/// `SuperclassRef.class`). Sibling of `check_type_con_name` for
|
||||
/// class refs.
|
||||
@@ -1071,7 +1072,7 @@ fn check_class_ref(
|
||||
})
|
||||
}
|
||||
|
||||
/// ct.1: apply the canonical-form rule to one `Type::Con.name`
|
||||
/// apply the canonical-form rule to one `Type::Con.name`
|
||||
/// (also reused for `Term::Ctor.type_name` in Task 2).
|
||||
fn check_type_con_name(
|
||||
name: &str,
|
||||
@@ -1140,7 +1141,7 @@ fn check_type_con_name(
|
||||
})
|
||||
}
|
||||
|
||||
/// ct.1: walk every `Type` reachable from a single `Def`, calling
|
||||
/// walk every `Type` reachable from a single `Def`, calling
|
||||
/// `f` on each. Recurses into `Type::Fn.params/ret`, `Type::Con.args`,
|
||||
/// `Type::Forall.constraints/body`, plus the obvious top-level fields
|
||||
/// of each `Def` variant AND every Type annotation embedded in a Term
|
||||
@@ -1188,7 +1189,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
/// ct.1: walk a `Term` and call `f` on every Type annotation embedded
|
||||
/// walk a `Term` and call `f` on every Type annotation embedded
|
||||
/// in it (Lam.param_tys, Lam.ret_ty, LetRec.ty). Recurses through
|
||||
/// every Term sub-position. Does NOT fire on `Term::Ctor.type_name`
|
||||
/// (that's a `String`, not a `Type`; handled by `walk_def_terms` in
|
||||
@@ -1263,7 +1264,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
/// ct.1: recursive walk of a `Type`, calling `f` at every node.
|
||||
/// recursive walk of a `Type`, calling `f` at every node.
|
||||
fn walk_type<F>(t: &Type, f: &mut F) -> Result<(), WorkspaceLoadError>
|
||||
where
|
||||
F: FnMut(&Type) -> Result<(), WorkspaceLoadError>,
|
||||
@@ -1292,7 +1293,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
/// ct.1: walk every `Term::Ctor.type_name` reachable from a single
|
||||
/// walk every `Term::Ctor.type_name` reachable from a single
|
||||
/// `Def`, calling `f` on the type_name strings. Used to enforce the
|
||||
/// canonical-form rule on term-side type references.
|
||||
fn walk_def_terms<F>(def: &Def, f: &mut F) -> Result<(), WorkspaceLoadError>
|
||||
@@ -1320,7 +1321,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
/// ct.1: recursive walk of a `Term`, calling `f` on every
|
||||
/// recursive walk of a `Term`, calling `f` on every
|
||||
/// `Term::Ctor.type_name`. Embedded `Type` annotations (Lam param /
|
||||
/// return types, LetRec types) ride the `walk_def_types` /
|
||||
/// `walk_term_embedded_types` path — but `Term::Ctor.type_name` is
|
||||
@@ -1397,7 +1398,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
/// ct.1: Pattern::Ctor carries a `ctor` name (matches against a
|
||||
/// Pattern::Ctor carries a `ctor` name (matches against a
|
||||
/// scrutinee's TypeDef) but NOT a type_name field — the type is
|
||||
/// inferred from the scrutinee. So Pattern walking only recurses;
|
||||
/// no canonical-form check fires here. `f` is kept in the signature
|
||||
@@ -1419,11 +1420,11 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
/// ct.1: reject any `.` in `ClassDef.name`. The defining-site name is
|
||||
/// reject any `.` in `ClassDef.name`. The defining-site name is
|
||||
/// bare by convention (symmetric to `TypeDef.name`); a qualified form
|
||||
/// indicates a malformed file.
|
||||
///
|
||||
/// mq.1: narrowed from the four class-reference fields to
|
||||
/// narrowed from the four class-reference fields to
|
||||
/// `ClassDef.name` only. The three referencing fields
|
||||
/// (`InstanceDef.class`, `Constraint.class`, `SuperclassRef.class`)
|
||||
/// now follow the canonical-form rule and are validated by
|
||||
@@ -1445,14 +1446,15 @@ fn check_class_name_fields(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Iter 22b.1: extract the head-constructor name of a type, for the
|
||||
/// extract the head-constructor name of a type, for the
|
||||
/// "where is this type defined" lookup and for diagnostic-message
|
||||
/// rendering.
|
||||
///
|
||||
/// For `Type::Con { name, .. }` (the only legal head shape for a
|
||||
/// non-orphan instance) returns `name`. Other variants (`Var`,
|
||||
/// `Forall`, `Fn`) are not legal as instance heads — Decision 11
|
||||
/// requires a concrete type expression at the instance head — so we
|
||||
/// `Forall`, `Fn`) are not legal as instance heads — the typeclass
|
||||
/// design requires a concrete type expression at the instance head —
|
||||
/// so we
|
||||
/// emit a stable fallback string. The fallback prevents diagnostic
|
||||
/// rendering from panicking on a malformed fixture; the "real"
|
||||
/// rejection of non-concrete instance heads will arrive as a
|
||||
@@ -1640,7 +1642,7 @@ mod tests {
|
||||
// ailang-surface dev-dep cycle disallows `surface::load_workspace`
|
||||
// calls from this in-mod test crate).
|
||||
|
||||
// Iter 22b.1: a workspace whose own modules contain no
|
||||
// a workspace whose own modules contain no
|
||||
// `Def::Instance` defs produces no non-prelude registry entries.
|
||||
// This is the happy-path baseline for the registry-build pass —
|
||||
// every pre-22b workspace falls into this case. With the
|
||||
@@ -1660,7 +1662,7 @@ mod tests {
|
||||
.join("examples")
|
||||
}
|
||||
|
||||
// Iter 22b.1: a coherent instance (in the class's module)
|
||||
// a coherent instance (in the class's module)
|
||||
// loads cleanly and produces one registry entry from the
|
||||
// fixture itself. With the auto-loaded prelude (iter 23.2)
|
||||
// the registry also contains the prelude's own entries; the
|
||||
@@ -1668,7 +1670,7 @@ mod tests {
|
||||
// `iter22b1_instance_in_class_module_loads_clean` relocated to
|
||||
// `crates/ailang-core/tests/workspace_pin.rs` in iter form-a.1 Task 5.
|
||||
|
||||
// Iter 22b.1: an instance declared in a module that is neither
|
||||
// an instance declared in a module that is neither
|
||||
// the class's module nor the type's module fires `OrphanInstance`.
|
||||
// The fixture imports `test_22b1_orphan_third_classmod` (which
|
||||
// owns `class TShow`) and the entry module declares `instance
|
||||
@@ -1678,17 +1680,17 @@ mod tests {
|
||||
// `iter22b1_orphan_instance_fires_diagnostic` relocated to
|
||||
// `crates/ailang-core/tests/workspace_pin.rs` in iter form-a.1 Task 5.
|
||||
|
||||
// Iter 22b.1 / mq.1: two instances of the same `(class, type)`
|
||||
// pair collide on the registry's uniqueness check.
|
||||
// Two instances of the same `(class, type)` pair collide on the
|
||||
// registry's uniqueness check.
|
||||
//
|
||||
// Pre-mq.1 the test used a two-module fixture
|
||||
// Pre-canonical-class-form the test used a two-module fixture
|
||||
// (`test_22b1_dup_a` declared the class + first instance,
|
||||
// `test_22b1_dup_b` declared the type + second instance) which
|
||||
// relied on bare cross-module class refs. The mq.1
|
||||
// relied on bare cross-module class refs. The canonical-form rule
|
||||
// canonical-form rule makes that shape structurally
|
||||
// unrepresentable (any second instance in a module that owns
|
||||
// neither the class nor the type fires `OrphanInstance` first).
|
||||
// Post-mq.1 the only way to land two instances on the same
|
||||
// Post-canonical-class-form the only way to land two instances on the same
|
||||
// canonical key is to have them in the same module (the class's
|
||||
// or the type's module). The fixture now declares both
|
||||
// instances in `test_22b1_dup_same_module` — both class-leg
|
||||
@@ -1697,7 +1699,7 @@ mod tests {
|
||||
// `iter22b1_duplicate_instance_fires_diagnostic` relocated to
|
||||
// `crates/ailang-core/tests/workspace_pin.rs` in iter form-a.1 Task 5.
|
||||
|
||||
// Iter 22b.1: an instance that omits a required (non-default)
|
||||
// an instance that omits a required (non-default)
|
||||
// method of its class fires `MissingMethod`. The fixture's
|
||||
// `class TEq` declares `teq` and `tne` as both non-default; the
|
||||
// instance only specifies `tne`, leaving `teq` missing.
|
||||
@@ -1713,13 +1715,13 @@ mod tests {
|
||||
// pd.2 (post-shim retirement; in-mod tests cannot reach
|
||||
// `ailang_surface::load_workspace` due to the dev-dep cycle).
|
||||
|
||||
// Iter 22b.2: an instance that specifies a body for a method
|
||||
// an instance that specifies a body for a method
|
||||
// name the class never declared must fire
|
||||
// `OverridingNonExistentMethod`. Symmetric counterpart to
|
||||
// `MissingMethod`: the latter fires when the class declares a
|
||||
// non-default method that the instance omits; this one fires
|
||||
// when the instance provides a body the class did not ask for.
|
||||
// Decision 11 forbids ad-hoc additions to a class's method set
|
||||
// The typeclass design forbids ad-hoc additions to a class's method set
|
||||
// at the instance site.
|
||||
// (Class is `TEq` rather than `Eq` to avoid colliding with the
|
||||
// auto-loaded prelude's `class Eq`.)
|
||||
@@ -1730,20 +1732,20 @@ mod tests {
|
||||
// relocated to `crates/ailang-core/tests/workspace_pin.rs` in iter
|
||||
// pd.2.
|
||||
|
||||
// mq.3: the two `..._method_name_collision_fires` pin tests
|
||||
// the two `..._method_name_collision_fires` pin tests
|
||||
// (class-class and class-fn variants) were retired here and
|
||||
// re-located as positive-load tests in
|
||||
// `crates/ailang-check/tests/method_collision_pin.rs`. Post-
|
||||
// mq.3 those on-disk fixtures load cleanly and the equivalent
|
||||
// Now those on-disk fixtures load cleanly and the equivalent
|
||||
// observations move to `env.method_to_candidate_classes`
|
||||
// (multi-entry set) plus the call-site warning.
|
||||
|
||||
// Iter 22b.2: an instance `C T` whose class `C` declares a
|
||||
// an instance `C T` whose class `C` declares a
|
||||
// superclass `S` requires that `instance S T` also exist in the
|
||||
// workspace. The fixture declares `class TEq a`, `class TOrd a
|
||||
// extends TEq a`, and `instance TOrd Int` — but no `instance TEq
|
||||
// Int` — so registry build must fire
|
||||
// `MissingSuperclassInstance`. Decision 11 single-superclass
|
||||
// `MissingSuperclassInstance`. the typeclass design's single-superclass
|
||||
// model requires `instance S T` whenever `instance C T` exists.
|
||||
// (Classes are `TEq` / `TOrd` rather than `Eq` / `Ord` to avoid
|
||||
// colliding with the auto-loaded prelude's `class Eq`.)
|
||||
@@ -1812,7 +1814,7 @@ mod tests {
|
||||
})).unwrap()
|
||||
}
|
||||
|
||||
/// ct.1: a `Type::Con` whose `name` is a primitive (`Int` / `Bool` /
|
||||
/// a `Type::Con` whose `name` is a primitive (`Int` / `Bool` /
|
||||
/// `Str` / `Unit` / `Float`) must be accepted bare. The five
|
||||
/// primitive names are the only legal bare-non-local Type::Con names
|
||||
/// under the canonical-form rule.
|
||||
@@ -1824,7 +1826,7 @@ mod tests {
|
||||
validate_canonical_type_names(&modules, &["prelude"]).expect("Float must be accepted");
|
||||
}
|
||||
|
||||
/// ct.1: a bare Type::Con whose `name` matches a local TypeDef in
|
||||
/// a bare Type::Con whose `name` matches a local TypeDef in
|
||||
/// the same module must be accepted (the canonical-form rule: bare =
|
||||
/// local).
|
||||
#[test]
|
||||
@@ -1834,7 +1836,7 @@ mod tests {
|
||||
.expect("local Foo must be accepted");
|
||||
}
|
||||
|
||||
/// ct.1: a bare Type::Con whose `name` is neither a primitive nor a
|
||||
/// a bare Type::Con whose `name` is neither a primitive nor a
|
||||
/// local TypeDef must fire `BareCrossModuleTypeRef`. With no imports,
|
||||
/// the candidates list is empty.
|
||||
#[test]
|
||||
@@ -1853,7 +1855,7 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
/// ct.1: a bare Type::Con whose `name` resolves to one imported
|
||||
/// a bare Type::Con whose `name` resolves to one imported
|
||||
/// module's TypeDef must fire `BareCrossModuleTypeRef` with that
|
||||
/// qualified form in `candidates` (so the diagnostic can suggest the
|
||||
/// fix).
|
||||
@@ -1873,7 +1875,7 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
/// ct.1: a qualified Type::Con `<owner>.<type>` where `<owner>` is a
|
||||
/// a qualified Type::Con `<owner>.<type>` where `<owner>` is a
|
||||
/// known module AND `<type>` is one of its TypeDefs must be accepted.
|
||||
#[test]
|
||||
fn ct1_validator_accepts_qualified_xmod_ref() {
|
||||
@@ -1884,7 +1886,7 @@ mod tests {
|
||||
.expect("other.Ordering must be accepted");
|
||||
}
|
||||
|
||||
/// ct.1: a qualified Type::Con `<owner>.<type>` where `<owner>` is
|
||||
/// a qualified Type::Con `<owner>.<type>` where `<owner>` is
|
||||
/// NOT a known module must fire `BadCrossModuleTypeRef`. Symmetric
|
||||
/// case: `<owner>` known but no TypeDef `<type>` in it.
|
||||
#[test]
|
||||
@@ -1901,7 +1903,7 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
/// ct.1: a Type::Con embedded inside a `Term::Lam.param_tys` is a
|
||||
/// a Type::Con embedded inside a `Term::Lam.param_tys` is a
|
||||
/// Type-position occurrence, just inside a Term tree. The validator
|
||||
/// must walk into Lam-internal types so an LLM author can't smuggle
|
||||
/// a bare cross-module ref past it by hiding it in a lambda
|
||||
@@ -1939,7 +1941,7 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
/// ct.1: a `Term::Ctor` whose `type_name` is a bare cross-module ref
|
||||
/// a `Term::Ctor` whose `type_name` is a bare cross-module ref
|
||||
/// must fire `BareCrossModuleTypeRef`. Symmetric to the Type::Con
|
||||
/// rule but the field lives on Term, not Type.
|
||||
#[test]
|
||||
@@ -1980,7 +1982,7 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
/// ct.1: a qualified `ClassDef.name` (e.g. `other.Eq`) must fire
|
||||
/// a qualified `ClassDef.name` (e.g. `other.Eq`) must fire
|
||||
/// `QualifiedClassName`. Class names stay bare in this milestone.
|
||||
#[test]
|
||||
fn ct1_validator_rejects_qualified_classdef_name() {
|
||||
@@ -2009,9 +2011,9 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
/// mq.1: a qualified `InstanceDef.class` referencing a class
|
||||
/// declared in another known module is the canonical form post-mq.1
|
||||
/// and is accepted by the validator. Inverted from the pre-mq.1
|
||||
/// a qualified `InstanceDef.class` referencing a class
|
||||
/// declared in another known module is the canonical form post-canonical-class-form
|
||||
/// and is accepted by the validator. Inverted from the pre-canonical-class-form
|
||||
/// `ct1_validator_rejects_qualified_instancedef_class` test:
|
||||
/// `InstanceDef.class` moved bare→canonical.
|
||||
#[test]
|
||||
@@ -2042,11 +2044,11 @@ mod tests {
|
||||
modules.insert("other".to_string(), other);
|
||||
modules.insert("m".to_string(), m);
|
||||
validate_canonical_type_names(&modules, &["prelude"])
|
||||
.expect("qualified InstanceDef.class is the canonical form post-mq.1");
|
||||
.expect("qualified InstanceDef.class is the canonical form post-canonical-class-form");
|
||||
}
|
||||
|
||||
/// mq.1: a qualified `SuperclassRef.class` referencing a class in
|
||||
/// another known module is the canonical form post-mq.1 and is
|
||||
/// a qualified `SuperclassRef.class` referencing a class in
|
||||
/// another known module is the canonical form post-canonical-class-form and is
|
||||
/// accepted. Inverted from
|
||||
/// `ct1_validator_rejects_qualified_superclassref_class`.
|
||||
#[test]
|
||||
@@ -2078,12 +2080,12 @@ mod tests {
|
||||
modules.insert("other".to_string(), other);
|
||||
modules.insert("m".to_string(), m);
|
||||
validate_canonical_type_names(&modules, &["prelude"])
|
||||
.expect("qualified SuperclassRef.class is the canonical form post-mq.1");
|
||||
.expect("qualified SuperclassRef.class is the canonical form post-canonical-class-form");
|
||||
}
|
||||
|
||||
/// mq.1: a qualified `Constraint.class` (inside a `Type::Forall`)
|
||||
/// a qualified `Constraint.class` (inside a `Type::Forall`)
|
||||
/// referencing a class in another known module is the canonical
|
||||
/// form post-mq.1 and is accepted. Inverted from
|
||||
/// form post-canonical-class-form and is accepted. Inverted from
|
||||
/// `ct1_validator_rejects_qualified_constraint_class`.
|
||||
#[test]
|
||||
fn ct1_validator_accepts_qualified_constraint_class() {
|
||||
@@ -2124,17 +2126,17 @@ mod tests {
|
||||
modules.insert("other".to_string(), other);
|
||||
modules.insert("m".to_string(), m);
|
||||
validate_canonical_type_names(&modules, &["prelude"])
|
||||
.expect("qualified Constraint.class is the canonical form post-mq.1");
|
||||
.expect("qualified Constraint.class is the canonical form post-canonical-class-form");
|
||||
}
|
||||
|
||||
/// ct.1.5a: registry-side duplicate detection survives the
|
||||
/// registry-side duplicate detection survives the
|
||||
/// asymmetric canonical-form representation. Two coherent instances
|
||||
/// on the same type-def, one declared bare-local (in the type's
|
||||
/// defining module) and one declared qualified-cross-module (in the
|
||||
/// class's defining module), must collide on the registry's
|
||||
/// `(class, type-hash)` key.
|
||||
///
|
||||
/// This is the regression that broke during the ct.1.5 migration
|
||||
/// This is the regression that broke during the canonical-form migration
|
||||
/// dry-run: after migrating `test_22b1_dup_a.ail.json` to qualified
|
||||
/// `test_22b1_dup_b.MyInt`, the unmigrated `test_22b1_dup_b.ail.json`
|
||||
/// (which keeps bare `MyInt` because the type IS local there)
|
||||
@@ -2185,7 +2187,7 @@ mod tests {
|
||||
// Module `other`: declares `type MyInt` and the qualified-
|
||||
// cross-module instance `instance cls.TShow MyInt`. Imports
|
||||
// `cls` for the class ref. The `class` field carries the
|
||||
// canonical form (qualified for cross-module per mq.1); the
|
||||
// canonical form (qualified for cross-module per the canonical-class-form rule); the
|
||||
// `type` field stays bare-local.
|
||||
let other: Module = serde_json::from_value(serde_json::json!({
|
||||
"schema": crate::SCHEMA,
|
||||
@@ -2231,7 +2233,7 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
/// ct.1.5a follow-up: `normalize_type_for_registry` must recurse into
|
||||
/// canonical-form normalisation follow-up: `normalize_type_for_registry` must recurse into
|
||||
/// `Type::Forall.constraints[].type_` just like it does into
|
||||
/// `Type::Forall.body`. A bare `Type::Con` nested inside a Forall
|
||||
/// constraint that lives in a different module must be rewritten to
|
||||
@@ -2291,14 +2293,14 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
/// ct.1: a qualified `Constraint.class` nested inside a
|
||||
/// a qualified `Constraint.class` nested inside a
|
||||
/// `ClassDef.methods[].ty.Forall.constraints` must fire
|
||||
/// `QualifiedClassName`. Distinct from the `Def::Fn` site: the
|
||||
/// `Def::Class` branch's per-method Forall walk needs independent
|
||||
/// coverage.
|
||||
///
|
||||
/// mq.1: inverted — qualified `Constraint.class` inside a
|
||||
/// `ClassDef.methods` Forall is the canonical form post-mq.1 and is
|
||||
/// inverted — qualified `Constraint.class` inside a
|
||||
/// `ClassDef.methods` Forall is the canonical form post-canonical-class-form and is
|
||||
/// accepted by the validator.
|
||||
#[test]
|
||||
fn ct1_validator_accepts_qualified_constraint_class_in_classdef_method() {
|
||||
@@ -2343,37 +2345,37 @@ mod tests {
|
||||
modules.insert("other".to_string(), other);
|
||||
modules.insert("m".to_string(), m);
|
||||
validate_canonical_type_names(&modules, &["prelude"])
|
||||
.expect("qualified Constraint.class in ClassDef-method Forall is the canonical form post-mq.1");
|
||||
.expect("qualified Constraint.class in ClassDef-method Forall is the canonical form post-canonical-class-form");
|
||||
}
|
||||
|
||||
/// ct.1: on-disk fixture for `BareCrossModuleTypeRef`. Bare
|
||||
/// on-disk fixture for `BareCrossModuleTypeRef`. Bare
|
||||
/// `Ordering` Term::Ctor with no imports; the validator catches it
|
||||
/// after prelude injection (so the candidate list contains
|
||||
/// `prelude.Ordering`).
|
||||
// `ct1_fixture_bare_xmod_rejected` relocated to
|
||||
// `crates/ailang-core/tests/workspace_pin.rs` in iter pd.2.
|
||||
|
||||
/// ct.1: on-disk fixture for `BadCrossModuleTypeRef`. Qualified
|
||||
/// on-disk fixture for `BadCrossModuleTypeRef`. Qualified
|
||||
/// `Mystery.Type` with `Mystery` not a known module.
|
||||
// `ct1_fixture_bad_qualifier` relocated to
|
||||
// `crates/ailang-core/tests/workspace_pin.rs` in iter pd.2.
|
||||
|
||||
/// mq.1: on-disk fixture for the post-mq.1 rejection path. The
|
||||
/// on-disk fixture for the post-canonical-class-form rejection path. The
|
||||
/// fixture declares `instance prelude.Eq Int` outside the prelude
|
||||
/// and outside Int's defining module — under the canonical-form
|
||||
/// rule the qualified `prelude.Eq` ref is now schema-valid (post-
|
||||
/// mq.1), and the downstream coherence check rejects the instance
|
||||
/// class references in canonical form), and the downstream coherence check rejects the instance
|
||||
/// with `OrphanInstance` instead.
|
||||
///
|
||||
/// Pre-mq.1 this test asserted `QualifiedClassName` on the same
|
||||
/// Pre-canonical-class-form this test asserted `QualifiedClassName` on the same
|
||||
/// fixture; the rename + reshape is the on-disk-fixture half of
|
||||
/// the four in-test inversions further up.
|
||||
// `ct1_fixture_qualified_class_orphan_post_mq1` relocated to
|
||||
// `crates/ailang-core/tests/workspace_pin.rs` in iter pd.2.
|
||||
|
||||
// mq.1: on-disk fixture pin — a workspace where the consumer's
|
||||
// on-disk fixture pin — a workspace where the consumer's
|
||||
// `Constraint.class` references a class in an imported module via
|
||||
// the qualified form loads cleanly. Symmetric to ct.1's positive
|
||||
// the qualified form loads cleanly. Symmetric to the canonical-form rule's positive
|
||||
// cross-module type-ref fixture (`ct1_validator_accepts_qualified_xmod_ref`
|
||||
// in-test sibling). Guards the full load → validator → registry
|
||||
// path on a real on-disk pair.
|
||||
@@ -2427,7 +2429,7 @@ mod tests {
|
||||
format!(r#"{{"schema":"ailang/v0","name":"{name}","imports":[],"defs":[]}}"#)
|
||||
}
|
||||
|
||||
/// mq.1.1: `BareCrossModuleClassRef` is the sibling diagnostic for
|
||||
/// `BareCrossModuleClassRef` is the sibling diagnostic for
|
||||
/// bare cross-module class references on `InstanceDef.class`,
|
||||
/// `Constraint.class`, and `SuperclassRef.class`. Verifies the
|
||||
/// variant is constructible and its Display surface names the
|
||||
@@ -2445,7 +2447,7 @@ mod tests {
|
||||
assert!(rendered.contains("prelude.Show"), "Display must list candidates, got: {rendered}");
|
||||
}
|
||||
|
||||
/// mq.1.1b: `BadCrossModuleClassRef` is the sibling diagnostic for
|
||||
/// `BadCrossModuleClassRef` is the sibling diagnostic for
|
||||
/// qualified class references whose owner module is unknown or
|
||||
/// declares no class by that name. Verifies the variant is
|
||||
/// constructible and its Display surface names the offending
|
||||
@@ -2462,7 +2464,7 @@ mod tests {
|
||||
"Display must mention class or module context, got: {rendered}");
|
||||
}
|
||||
|
||||
/// mq.1.3: `InstanceDef.class` carrying a bare name that does NOT
|
||||
/// `InstanceDef.class` carrying a bare name that does NOT
|
||||
/// resolve to a local class of the owning module must fire
|
||||
/// `BareCrossModuleClassRef`. The fixture imports a sibling module
|
||||
/// that declares the class under the bare name, so the candidate
|
||||
@@ -2505,7 +2507,7 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
/// mq.1.3: `Constraint.class` on a `Def::Fn` carrying a bare name
|
||||
/// `Constraint.class` on a `Def::Fn` carrying a bare name
|
||||
/// that does not resolve to a local class fires
|
||||
/// `BareCrossModuleClassRef`.
|
||||
#[test]
|
||||
@@ -2558,7 +2560,7 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
/// mq.1.3: `SuperclassRef.class` on a `Def::Class` carrying a bare
|
||||
/// `SuperclassRef.class` on a `Def::Class` carrying a bare
|
||||
/// name that does not resolve to a local class fires
|
||||
/// `BareCrossModuleClassRef`.
|
||||
#[test]
|
||||
@@ -2599,9 +2601,9 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
/// mq.1.3: a qualified `InstanceDef.class` referencing a class in
|
||||
/// an imported module is the canonical form post-mq.1 and is
|
||||
/// accepted by `validate_canonical_type_names`. Symmetric to ct.1's
|
||||
/// a qualified `InstanceDef.class` referencing a class in
|
||||
/// an imported module is the canonical form post-canonical-class-form and is
|
||||
/// accepted by `validate_canonical_type_names`. Symmetric to the canonical-form rule's
|
||||
/// "qualified Type::Con resolves" positive path.
|
||||
#[test]
|
||||
fn mq1_qualified_instancedef_class_accepted() {
|
||||
@@ -2665,7 +2667,7 @@ mod tests {
|
||||
fn module_with_bare_classref(name: &str, class_ref: &str) -> Module {
|
||||
// A module containing a single Def::Instance whose `class` field is
|
||||
// a bare class reference. The instance's `type` field is a local
|
||||
// ADT defined in the same module to keep ct.1 happy.
|
||||
// ADT defined in the same module to keep the canonical-form rule satisfied.
|
||||
serde_json::from_value(serde_json::json!({
|
||||
"schema": crate::SCHEMA,
|
||||
"name": name,
|
||||
|
||||
Reference in New Issue
Block a user