iter 22b.2.3: invalid-superclass-param class-schema diagnostic
This commit is contained in:
@@ -1049,6 +1049,25 @@ fn workspace_error_to_diagnostic(
|
||||
"defining_module": defining_module,
|
||||
})),
|
||||
),
|
||||
W::InvalidSuperclassParam {
|
||||
class,
|
||||
superclass,
|
||||
expected_param,
|
||||
got_type,
|
||||
} => Some(
|
||||
ailang_check::Diagnostic::error(
|
||||
"invalid-superclass-param",
|
||||
format!(
|
||||
"class `{class}` declares superclass `{superclass} {got_type}`, but its own parameter is `{expected_param}` — superclass `type` must equal class `param`"
|
||||
),
|
||||
)
|
||||
.with_ctx(serde_json::json!({
|
||||
"class": class,
|
||||
"superclass": superclass,
|
||||
"expected_param": expected_param,
|
||||
"got_type": got_type,
|
||||
})),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -215,6 +215,21 @@ pub enum WorkspaceLoadError {
|
||||
method: String,
|
||||
defining_module: String,
|
||||
},
|
||||
|
||||
/// Iter 22b.2: class-schema validation. A class's `superclass.type`
|
||||
/// does not equal its own `param`. Decision 11 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(
|
||||
"class `{class}` declares superclass `{superclass} {got_type}`, but its own parameter is `{expected_param}` \
|
||||
— superclass `type` must equal class `param`"
|
||||
)]
|
||||
InvalidSuperclassParam {
|
||||
class: String,
|
||||
superclass: String,
|
||||
expected_param: String,
|
||||
got_type: String,
|
||||
},
|
||||
}
|
||||
|
||||
/// Hash over the canonical bytes of a complete module.
|
||||
@@ -425,6 +440,16 @@ fn validate_classdefs(
|
||||
defining_module: mod_name.clone(),
|
||||
})?;
|
||||
}
|
||||
if let Some(sc) = &c.superclass {
|
||||
if sc.type_ != c.param {
|
||||
return Err(WorkspaceLoadError::InvalidSuperclassParam {
|
||||
class: c.name.clone(),
|
||||
superclass: sc.class.clone(),
|
||||
expected_param: c.param.clone(),
|
||||
got_type: sc.type_.clone(),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -806,4 +831,29 @@ mod tests {
|
||||
other => panic!("expected KindMismatch, got {other:?}"),
|
||||
}
|
||||
}
|
||||
|
||||
/// Iter 22b.2: a class whose `superclass.type` differs from its
|
||||
/// own `param` (e.g. `class Ord a extends Eq b`) must fire
|
||||
/// `InvalidSuperclassParam`. Decision 11 axis 1 ("single
|
||||
/// superclass, applied to the same param") makes the only legal
|
||||
/// shape `extends Eq a` when the parent class has `param: "a"`.
|
||||
#[test]
|
||||
fn superclass_with_wrong_param_fires_invalid_superclass_param() {
|
||||
let entry = std::path::PathBuf::from(
|
||||
"../../examples/test_22b2_invalid_superclass_param.ail.json",
|
||||
);
|
||||
let err = load_workspace(&entry)
|
||||
.expect_err("must fire invalid-superclass-param");
|
||||
match err {
|
||||
WorkspaceLoadError::InvalidSuperclassParam {
|
||||
class, superclass, expected_param, got_type,
|
||||
} => {
|
||||
assert_eq!(class, "Ord");
|
||||
assert_eq!(superclass, "Eq");
|
||||
assert_eq!(expected_param, "a");
|
||||
assert_eq!(got_type, "b");
|
||||
}
|
||||
other => panic!("expected InvalidSuperclassParam, got {other:?}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
{
|
||||
"schema": "ailang/v0",
|
||||
"name": "test_22b2_invalid_superclass_param",
|
||||
"imports": [],
|
||||
"defs": [
|
||||
{
|
||||
"kind": "class", "name": "Eq", "param": "a",
|
||||
"methods": [
|
||||
{
|
||||
"name": "eq",
|
||||
"type": {
|
||||
"k": "fn",
|
||||
"params": [
|
||||
{ "k": "var", "name": "a" },
|
||||
{ "k": "var", "name": "a" }
|
||||
],
|
||||
"ret": { "k": "con", "name": "Bool" },
|
||||
"effects": []
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"kind": "class", "name": "Ord", "param": "a",
|
||||
"superclass": { "class": "Eq", "type": "b" },
|
||||
"methods": [
|
||||
{
|
||||
"name": "lt",
|
||||
"type": {
|
||||
"k": "fn",
|
||||
"params": [
|
||||
{ "k": "var", "name": "a" },
|
||||
{ "k": "var", "name": "a" }
|
||||
],
|
||||
"ret": { "k": "con", "name": "Bool" },
|
||||
"effects": []
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user