iter 23.4-prep.1: linearity — register Def::Class method types in globals
This commit is contained in:
@@ -205,11 +205,19 @@ pub(crate) fn check_module(m: &Module) -> Vec<Diagnostic> {
|
|||||||
ctors.insert(name.clone(), fields.clone());
|
ctors.insert(name.clone(), fields.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Iter 22b.1: class/instance defs are skipped here. Once
|
// Iter 23.4-prep: class methods register their types into
|
||||||
// 22b.3 monomorphisation materialises class methods as
|
// the globals map so `callee_arg_modes` can see their
|
||||||
// ordinary `FnDef`s, the lift's globals map will pick
|
// `param_modes`. Without this, a borrow-mode fn that
|
||||||
// them up automatically.
|
// forwards its borrow params into a class-method call
|
||||||
Def::Class(_) | Def::Instance(_) => {}
|
// fires `consume-while-borrowed` false positives.
|
||||||
|
// Instance defs stay a no-op: instance method bodies are
|
||||||
|
// walked separately via `Def::Fn` after monomorphisation.
|
||||||
|
Def::Class(c) => {
|
||||||
|
for m in &c.methods {
|
||||||
|
globals.insert(m.name.clone(), strip_forall(&m.ty).clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Def::Instance(_) => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1426,4 +1434,76 @@ mod tests {
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Iter 23.4-prep Task 1: a borrow-mode fn that forwards its borrow
|
||||||
|
/// params into a class-method call must not fire
|
||||||
|
/// `consume-while-borrowed` false positives. The pre-fix behaviour
|
||||||
|
/// is two diagnostics (one per param) because
|
||||||
|
/// `linearity::check_module`'s globals-construction loop skips
|
||||||
|
/// `Def::Class`, so `callee_arg_modes` cannot see the method's
|
||||||
|
/// `param_modes` and defaults each call argument to `Consume`.
|
||||||
|
#[test]
|
||||||
|
fn class_method_borrow_call_does_not_fire_consume_while_borrowed() {
|
||||||
|
use ailang_core::ast::{ClassDef, ClassMethod};
|
||||||
|
|
||||||
|
let class_eq = Def::Class(ClassDef {
|
||||||
|
name: "TestEq".into(),
|
||||||
|
param: "a".into(),
|
||||||
|
superclass: None,
|
||||||
|
methods: vec![ClassMethod {
|
||||||
|
name: "teq".into(),
|
||||||
|
ty: Type::Fn {
|
||||||
|
params: vec![
|
||||||
|
Type::Var { name: "a".into() },
|
||||||
|
Type::Var { name: "a".into() },
|
||||||
|
],
|
||||||
|
param_modes: vec![ParamMode::Borrow, ParamMode::Borrow],
|
||||||
|
ret: Box::new(Type::bool_()),
|
||||||
|
ret_mode: ParamMode::Implicit,
|
||||||
|
effects: vec![],
|
||||||
|
},
|
||||||
|
default: None,
|
||||||
|
}],
|
||||||
|
doc: None,
|
||||||
|
});
|
||||||
|
|
||||||
|
let ne = Def::Fn(FnDef {
|
||||||
|
name: "tne".into(),
|
||||||
|
ty: Type::Fn {
|
||||||
|
params: vec![
|
||||||
|
Type::Var { name: "a".into() },
|
||||||
|
Type::Var { name: "a".into() },
|
||||||
|
],
|
||||||
|
param_modes: vec![ParamMode::Borrow, ParamMode::Borrow],
|
||||||
|
ret: Box::new(Type::bool_()),
|
||||||
|
ret_mode: ParamMode::Implicit,
|
||||||
|
effects: vec![],
|
||||||
|
},
|
||||||
|
params: vec!["x".into(), "y".into()],
|
||||||
|
body: Term::App {
|
||||||
|
callee: Box::new(Term::Var { name: "teq".into() }),
|
||||||
|
args: vec![
|
||||||
|
Term::Var { name: "x".into() },
|
||||||
|
Term::Var { name: "y".into() },
|
||||||
|
],
|
||||||
|
tail: false,
|
||||||
|
},
|
||||||
|
suppress: vec![],
|
||||||
|
doc: None,
|
||||||
|
});
|
||||||
|
|
||||||
|
let m = Module {
|
||||||
|
schema: ailang_core::SCHEMA.into(),
|
||||||
|
name: "m".into(),
|
||||||
|
imports: vec![],
|
||||||
|
defs: vec![class_eq, ne],
|
||||||
|
};
|
||||||
|
|
||||||
|
let diags = check_module(&m);
|
||||||
|
assert!(
|
||||||
|
diags.is_empty(),
|
||||||
|
"expected no diagnostics but got {:#?}",
|
||||||
|
diags
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user