fix(check): param-not-in-restricted-set names the allowed set (closes #48)
The ParamNotInRestrictedSet diagnostic named the offending type, the
type-variable and the home type, but not the allowed set {Int, Float,
Bool} that design/models/0007 §4 promises it names. A downstream author
was told what is wrong but not what is right, and the kernel source that
carries the set is not available to a downstream consumer.
The allowed set already travels on the error struct (it flows into the
JSON `details.allowed`); only the human-readable `#[error]` render
dropped it. Append it to the Display string. JSON details unchanged.
Surfaced by the raw-buf fieldtest (finding B3, docs/specs/0058).
RED-first: param_in_reject_message_names_allowed_set pins the message
content before the one-line render fix.
This commit is contained in:
@@ -747,7 +747,7 @@ pub enum CheckError {
|
||||
/// (`allowed`, deterministically alphabetical from the BTreeSet
|
||||
/// source). Code: `param-not-in-restricted-set`.
|
||||
#[error(
|
||||
"type-arg `{found}` is not in the restricted set for type-variable `{var}` of `{type_name}`"
|
||||
"type-arg `{found}` is not in the restricted set for type-variable `{var}` of `{type_name}` (allowed: one of {allowed:?})"
|
||||
)]
|
||||
ParamNotInRestrictedSet {
|
||||
type_name: String,
|
||||
@@ -8221,6 +8221,51 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
/// fieldtest B3 (raw-buf, #7): the rendered `param-not-in-restricted-set`
|
||||
/// message must name the *allowed set*, not only the offending type.
|
||||
/// Property per design/models/0007-kernel-extensions.md §4
|
||||
/// ("ParamNotInRestrictedSet names the offending type AND the allowed
|
||||
/// set"): a downstream author rejected for `(con StubT (con Str))`
|
||||
/// under `param-in = {"a": {"Int", "Float"}}` must be told `Int` and
|
||||
/// `Float` are the permitted choices, so the message is actionable.
|
||||
#[test]
|
||||
fn param_in_reject_message_names_allowed_set() {
|
||||
let m: Module = serde_json::from_value(serde_json::json!({
|
||||
"schema": SCHEMA,
|
||||
"name": "k",
|
||||
"defs": [
|
||||
{"kind": "type", "name": "StubT", "vars": ["a"],
|
||||
"ctors": [{"name": "Stub", "fields": [{"k": "var", "name": "a"}]}],
|
||||
"param-in": {"a": ["Int", "Float"]}},
|
||||
{"kind": "fn", "name": "bad",
|
||||
"type": {"k": "fn", "params": [],
|
||||
"ret": {"k": "con", "name": "StubT",
|
||||
"args": [{"k": "con", "name": "Str"}]},
|
||||
"effects": []},
|
||||
"params": [],
|
||||
"body": {"t": "lit", "lit": {"kind": "unit"}}}
|
||||
]
|
||||
})).unwrap();
|
||||
let mut modules = BTreeMap::new();
|
||||
modules.insert("k".to_string(), m);
|
||||
let ws = Workspace {
|
||||
entry: "k".into(),
|
||||
modules,
|
||||
root_dir: std::path::PathBuf::from("."),
|
||||
registry: ailang_core::workspace::Registry::default(),
|
||||
};
|
||||
let diags = check_workspace(&ws);
|
||||
let d = diags
|
||||
.iter()
|
||||
.find(|d| d.code == "param-not-in-restricted-set")
|
||||
.unwrap_or_else(|| panic!("expected param-not-in-restricted-set, got {diags:?}"));
|
||||
assert!(
|
||||
d.message.contains("Int") && d.message.contains("Float"),
|
||||
"message must name the allowed set {{Int, Float}}, got: {:?}",
|
||||
d.message
|
||||
);
|
||||
}
|
||||
|
||||
/// prep.3 (kernel-extension-mechanics): `param-in` enforcement
|
||||
/// accepts a type-arg inside the allowed set. Same TypeDef as
|
||||
/// the RED test, but `(con StubT (con Int))` — Int is in
|
||||
|
||||
Reference in New Issue
Block a user