Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion ndc_analyser/src/analyser/declarations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ impl Analyser {
}
let first_use = self.uses.len();
let first_literal = self.number_literals.len();
let first_check = self.checks.len();
let (annotations, iterates): (Vec<_>, Vec<_>) = parameters
.iter()
.map(|param| self.lower_parameter_annotation(param.annotation.as_ref()))
Expand Down Expand Up @@ -200,7 +201,12 @@ impl Analyser {
self.vars.leave_level();
self.declaring = None;
self.declared_in_batch.insert(symbol);
self.generalize(symbol, &signature, id, first_use, first_literal)
self.generalize(
symbol,
&signature,
id,
[first_use, first_literal, first_check],
)
}
_ => signature,
};
Expand Down
25 changes: 20 additions & 5 deletions ndc_analyser/src/analyser/generics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,7 @@ impl Analyser {
symbol: SymbolId,
signature: &StaticType,
declaration: NodeId,
first_use: usize,
first_literal: usize,
[first_use, first_literal, first_check]: [usize; 3],
) -> StaticType {
self.solve_waiting();
// A literal in the body that its type parameters don't reach has
Expand Down Expand Up @@ -191,15 +190,30 @@ impl Analyser {
self.pick_for_any_arguments(call);
}
}
// An instance is for the types of the type parameters the
// constraints and uses depend on.
// A value of type `Any` that the body passes where a type parameter
// is expected, as `a` in `fn f(x) { let a: Any = 5; [x].push(a) }`,
// is checked against what each call makes it.
let checks = self.checks[first_check..]
.iter()
.filter(|(instance, ..)| instance.is_none())
.map(|(_, node, typ, expected)| {
(*node, self.vars.resolve(typ), self.vars.resolve(expected))
})
.filter(|(_, typ, expected)| {
*typ == StaticType::Any
&& expected.contains(&|part| matches!(part, StaticType::Generic(_)))
})
.collect::<Vec<_>>();
// An instance is for the types of the type parameters that what it
// compiles differently depends on: the constraints and uses it
// picks for, the literals typed by a type parameter, and the checks.
let mut key: Vec<Box<str>> = Vec::new();
// The literals typed by a type parameter compile to what it is.
for typ in scheme
.iter()
.flat_map(|waiting| waiting.constraint.inputs())
.chain(uses.iter().flat_map(|generic_use| &generic_use.key))
.chain(literal_nodes.iter().map(|(_, typ)| typ))
.chain(checks.iter().map(|(_, _, expected)| expected))
{
for name in typ.type_parameters() {
if !key.contains(&name) {
Expand All @@ -217,6 +231,7 @@ impl Analyser {
recursive_calls: std::mem::take(&mut self.recursive_calls).into(),
literals: literals.into(),
literal_nodes: literal_nodes.into(),
checks: checks.into(),
},
);
self.vars.resolve(signature)
Expand Down
9 changes: 9 additions & 0 deletions ndc_analyser/src/analyser/instances.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ pub(super) struct Scheme {
/// parameters, with that type, which an instance records its own types
/// for.
pub(super) literal_nodes: Rc<[(NodeId, StaticType)]>,
/// The values its body checks as the program runs against a type that
/// has its type parameters in it, with their types and that type, which
/// an instance checks against what its types make it.
pub(super) checks: Rc<[(NodeId, StaticType, StaticType)]>,
}

/// A call of a generic function, or its name used as a value, which needs
Expand Down Expand Up @@ -300,6 +304,11 @@ impl Analyser {
self.wait_as(copy);
}
}
for (node, typ, expected) in scheme.checks.iter() {
let typ = self.vars.instantiate_with(typ, &mut made);
let expected = self.vars.instantiate_with(expected, &mut made);
self.expect_if_any(*node, typ, expected);
}
for &call in scheme.recursive_calls.iter() {
self.pick_tables(Some(instance)).insert(
CallSite::Call(call),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// A value of type `Any` passed where a generic function's type parameter is
// expected is checked against what each call makes it: `with_five("s")`
// pushes the Int 5 into a list of Strings.
// expect-error: expected String but found Int
fn with_five(x) {
let five: Any = 5;
let xs = [x];
xs.push(five);
xs
}
print(with_five(1));
print(with_five("s"));
Loading