iter 23.2.3-prep: reconcile workspace tests with auto-loaded prelude class Eq
The auto-loaded prelude (iter 23.2 work-in-progress) injects `class Eq` plus three primitive instances (Eq Int, Eq Bool, Eq Str) into every workspace. Five workspace::tests assertions broke against this new baseline: - iter22b1_missing_method_fires_diagnostic - instance_without_superclass_instance_fires - instance_overriding_nonexistent_method_fires Their fixtures redeclare `class Eq` (and `class Ord` in one case), which now collides with the prelude. Renamed each fixture's `Eq`/`eq` -> `TEq`/`teq` and `Ord`/`lt` -> `TOrd`/`tlt`, matching the scheme already used in the two earlier-renamed test_22b2 fixtures. Method `ne` stays (does not collide). Assertion strings in workspace.rs updated to match. - iter22b1_workspace_with_no_classes_has_empty_registry - iter22b1_instance_in_class_module_loads_clean Their asserted registry counts assumed an otherwise-empty registry. Rewritten to filter by `defining_module != "prelude"`: the property is "no NON-prelude entries" / "exactly one fixture-owned entry", not raw count. Doc comments updated alongside each assertion change so the rationale for TEq/TOrd (collision avoidance) is local. No production code touched.
This commit is contained in:
@@ -976,10 +976,13 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
/// Iter 22b.1: a workspace whose modules contain no
|
||||
/// `Def::Instance` defs has an empty registry. This is the
|
||||
/// happy-path baseline for the registry-build pass — every
|
||||
/// pre-22b workspace falls into this case.
|
||||
/// Iter 22b.1: 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
|
||||
/// auto-loaded prelude (iter 23.2) the registry is no longer
|
||||
/// strictly empty, so the invariant is now "no entries whose
|
||||
/// `defining_module` is anything other than `prelude`".
|
||||
#[test]
|
||||
fn iter22b1_workspace_with_no_classes_has_empty_registry() {
|
||||
let manifest_dir = env!("CARGO_MANIFEST_DIR");
|
||||
@@ -989,8 +992,14 @@ mod tests {
|
||||
|
||||
let ws = load_workspace(&entry).expect("sum.ail.json loads");
|
||||
assert!(
|
||||
ws.registry.entries.is_empty(),
|
||||
"pre-22b fixture has no class/instance defs, registry must be empty"
|
||||
ws.registry.entries.values().all(|e| e.defining_module == "prelude"),
|
||||
"pre-22b fixture has no class/instance defs of its own; \
|
||||
all registry entries must come from the auto-injected prelude. \
|
||||
got non-prelude entries: {:?}",
|
||||
ws.registry.entries.values()
|
||||
.filter(|e| e.defining_module != "prelude")
|
||||
.map(|e| &e.defining_module)
|
||||
.collect::<Vec<_>>()
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1005,13 +1014,19 @@ mod tests {
|
||||
}
|
||||
|
||||
/// Iter 22b.1: a coherent instance (in the class's module)
|
||||
/// loads cleanly and produces one registry entry.
|
||||
/// 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
|
||||
/// invariant is filtered to fixture-only entries.
|
||||
#[test]
|
||||
fn iter22b1_instance_in_class_module_loads_clean() {
|
||||
let entry = examples_dir().join("test_22b1_orphan_class.ail.json");
|
||||
let ws = load_workspace(&entry).expect("coherent instance loads");
|
||||
assert_eq!(ws.registry.entries.len(), 1);
|
||||
let (key, entry) = ws.registry.entries.iter().next().unwrap();
|
||||
let fixture_entries: Vec<_> = ws.registry.entries.iter()
|
||||
.filter(|(_, e)| e.defining_module != "prelude")
|
||||
.collect();
|
||||
assert_eq!(fixture_entries.len(), 1);
|
||||
let (key, entry) = fixture_entries[0];
|
||||
assert_eq!(&key.0, "Show");
|
||||
assert_eq!(entry.defining_module, "test_22b1_orphan_class");
|
||||
assert_eq!(entry.instance.class, "Show");
|
||||
@@ -1079,8 +1094,10 @@ mod tests {
|
||||
|
||||
/// Iter 22b.1: an instance that omits a required (non-default)
|
||||
/// method of its class fires `MissingMethod`. The fixture's
|
||||
/// `class Eq` declares `eq` and `ne` as both non-default; the
|
||||
/// instance only specifies `ne`, leaving `eq` missing.
|
||||
/// `class TEq` declares `teq` and `ne` as both non-default; the
|
||||
/// instance only specifies `ne`, leaving `teq` missing.
|
||||
/// (Class is `TEq` rather than `Eq` to avoid colliding with the
|
||||
/// auto-loaded prelude's `class Eq`.)
|
||||
#[test]
|
||||
fn iter22b1_missing_method_fires_diagnostic() {
|
||||
let entry = examples_dir().join("test_22b1_missing_method.ail.json");
|
||||
@@ -1091,9 +1108,9 @@ mod tests {
|
||||
type_repr,
|
||||
method,
|
||||
} => {
|
||||
assert_eq!(class, "Eq");
|
||||
assert_eq!(class, "TEq");
|
||||
assert_eq!(type_repr, "Int");
|
||||
assert_eq!(method, "eq");
|
||||
assert_eq!(method, "teq");
|
||||
}
|
||||
other => panic!("expected MissingMethod, got {other:?}"),
|
||||
}
|
||||
@@ -1154,6 +1171,8 @@ mod tests {
|
||||
/// when the instance provides a body the class did not ask for.
|
||||
/// Decision 11 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`.)
|
||||
#[test]
|
||||
fn instance_overriding_nonexistent_method_fires() {
|
||||
let entry = std::path::PathBuf::from(
|
||||
@@ -1165,7 +1184,7 @@ mod tests {
|
||||
WorkspaceLoadError::OverridingNonExistentMethod {
|
||||
class, type_repr, method,
|
||||
} => {
|
||||
assert_eq!(class, "Eq");
|
||||
assert_eq!(class, "TEq");
|
||||
assert_eq!(type_repr, "Int");
|
||||
assert_eq!(method, "ne");
|
||||
}
|
||||
@@ -1269,11 +1288,13 @@ mod tests {
|
||||
|
||||
/// Iter 22b.2: 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 Eq a`, `class Ord a
|
||||
/// extends Eq a`, and `instance Ord Int` — but no `instance Eq
|
||||
/// 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
|
||||
/// 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`.)
|
||||
#[test]
|
||||
fn instance_without_superclass_instance_fires() {
|
||||
let entry = examples_dir().join("test_22b2_missing_superclass_instance.ail.json");
|
||||
@@ -1283,8 +1304,8 @@ mod tests {
|
||||
WorkspaceLoadError::MissingSuperclassInstance {
|
||||
class, superclass, type_repr,
|
||||
} => {
|
||||
assert_eq!(class, "Ord");
|
||||
assert_eq!(superclass, "Eq");
|
||||
assert_eq!(class, "TOrd");
|
||||
assert_eq!(superclass, "TEq");
|
||||
assert_eq!(type_repr, "Int");
|
||||
}
|
||||
other => panic!("expected MissingSuperclassInstance, got {other:?}"),
|
||||
|
||||
@@ -5,11 +5,11 @@
|
||||
"defs": [
|
||||
{
|
||||
"kind": "class",
|
||||
"name": "Eq",
|
||||
"name": "TEq",
|
||||
"param": "a",
|
||||
"methods": [
|
||||
{
|
||||
"name": "eq",
|
||||
"name": "teq",
|
||||
"type": {
|
||||
"k": "fn",
|
||||
"params": [
|
||||
@@ -36,7 +36,7 @@
|
||||
},
|
||||
{
|
||||
"kind": "instance",
|
||||
"class": "Eq",
|
||||
"class": "TEq",
|
||||
"type": { "k": "con", "name": "Int" },
|
||||
"methods": [
|
||||
{
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
"imports": [],
|
||||
"defs": [
|
||||
{
|
||||
"kind": "class", "name": "Eq", "param": "a",
|
||||
"kind": "class", "name": "TEq", "param": "a",
|
||||
"methods": [{
|
||||
"name": "eq",
|
||||
"name": "teq",
|
||||
"type": {
|
||||
"k": "fn",
|
||||
"params": [{ "k": "var", "name": "a" }, { "k": "var", "name": "a" }],
|
||||
@@ -15,10 +15,10 @@
|
||||
}]
|
||||
},
|
||||
{
|
||||
"kind": "class", "name": "Ord", "param": "a",
|
||||
"superclass": { "class": "Eq", "type": "a" },
|
||||
"kind": "class", "name": "TOrd", "param": "a",
|
||||
"superclass": { "class": "TEq", "type": "a" },
|
||||
"methods": [{
|
||||
"name": "lt",
|
||||
"name": "tlt",
|
||||
"type": {
|
||||
"k": "fn",
|
||||
"params": [{ "k": "var", "name": "a" }, { "k": "var", "name": "a" }],
|
||||
@@ -28,10 +28,10 @@
|
||||
},
|
||||
{
|
||||
"kind": "instance",
|
||||
"class": "Ord",
|
||||
"class": "TOrd",
|
||||
"type": { "k": "con", "name": "Int" },
|
||||
"methods": [{
|
||||
"name": "lt",
|
||||
"name": "tlt",
|
||||
"body": { "t": "lit", "lit": { "kind": "bool", "value": true } }
|
||||
}]
|
||||
}
|
||||
|
||||
@@ -5,11 +5,11 @@
|
||||
"defs": [
|
||||
{
|
||||
"kind": "class",
|
||||
"name": "Eq",
|
||||
"name": "TEq",
|
||||
"param": "a",
|
||||
"methods": [
|
||||
{
|
||||
"name": "eq",
|
||||
"name": "teq",
|
||||
"type": {
|
||||
"k": "fn",
|
||||
"params": [{ "k": "var", "name": "a" }, { "k": "var", "name": "a" }],
|
||||
@@ -21,11 +21,11 @@
|
||||
},
|
||||
{
|
||||
"kind": "instance",
|
||||
"class": "Eq",
|
||||
"class": "TEq",
|
||||
"type": { "k": "con", "name": "Int" },
|
||||
"methods": [
|
||||
{
|
||||
"name": "eq",
|
||||
"name": "teq",
|
||||
"body": { "t": "lit", "lit": { "kind": "bool", "value": true } }
|
||||
},
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user