typecheck tags with arguments

also fixes an issue where private tags in patterns would not have the @ symbol in their name
This commit is contained in:
Folkert 2020-01-09 13:20:21 +01:00
parent 98515cdf23
commit dd240cf53a
7 changed files with 104 additions and 29 deletions

View file

@ -17,7 +17,7 @@ use im_rc::Vector;
#[derive(Clone, Debug, PartialEq)]
pub enum Pattern {
Identifier(Symbol),
AppliedTag(Variable, Symbol, Vec<Located<Pattern>>),
AppliedTag(Variable, Symbol, Vec<(Variable, Located<Pattern>)>),
IntLiteral(i64),
FloatLiteral(f64),
StrLiteral(Box<str>),
@ -94,6 +94,32 @@ pub fn canonicalize_pattern<'a>(
vec![],
)
}
&Apply(tag, patterns) => {
let mut can_patterns = Vec::with_capacity(patterns.len());
for loc_pattern in *patterns {
can_patterns.push((
var_store.fresh(),
canonicalize_pattern(
env,
var_store,
scope,
pattern_type,
&loc_pattern.value,
loc_pattern.region,
shadowable_idents,
),
));
}
let symbol = match tag.value {
GlobalTag(name) => Symbol::from_global_tag(name),
PrivateTag(name) => Symbol::from_private_tag(&env.home, name),
_ => unreachable!("Other patterns cannot be applied"),
};
Pattern::AppliedTag(var_store.fresh(), symbol, can_patterns)
}
&FloatLiteral(ref string) => match pattern_type {
WhenBranch => {
let float = finish_parsing_float(string)
@ -344,13 +370,10 @@ pub fn remove_idents(pattern: &ast::Pattern, idents: &mut ImMap<Ident, (Symbol,
QualifiedIdentifier(_name) => {
panic!("TODO implement QualifiedIdentifier pattern in remove_idents.");
}
Apply(_, _) => {
panic!("TODO implement Apply pattern in remove_idents.");
// AppliedVariant(_, Some(loc_args)) => {
// for loc_arg in loc_args {
// remove_idents(loc_arg.value, idents);
// }
// }
Apply(_, patterns) => {
for loc_pattern in *patterns {
remove_idents(&loc_pattern.value, idents);
}
}
RecordDestructure(patterns) => {
for loc_pattern in patterns {
@ -410,16 +433,10 @@ fn add_idents_from_pattern<'a>(
QualifiedIdentifier(_name) => {
panic!("TODO implement QualifiedIdentifier pattern.");
}
Apply(_, _) => {
panic!("TODO implement Apply pattern.");
// &AppliedVariant(_, ref opt_loc_args) => match opt_loc_args {
// &None => (),
// &Some(ref loc_args) => {
// for loc_arg in loc_args.iter() {
// add_idents_from_pattern(loc_arg, scope, answer);
// }
// }
// },
Apply(_tag, patterns) => {
for loc_pattern in *patterns {
add_idents_from_pattern(&loc_pattern.region, &loc_pattern.value, scope, answer);
}
}
RecordDestructure(patterns) => {

View file

@ -105,12 +105,23 @@ pub fn constrain_pattern(
state.constraints.push(record_con);
}
AppliedTag(ext_var, symbol, _arguments) => {
AppliedTag(ext_var, symbol, patterns) => {
let mut argument_types = Vec::with_capacity(patterns.len());
for (pattern_var, loc_pattern) in patterns {
state.vars.push(*pattern_var);
let pattern_type = Type::Variable(*pattern_var);
argument_types.push(pattern_type.clone());
let expected = PExpected::NoExpectation(pattern_type);
constrain_pattern(&loc_pattern.value, loc_pattern.region, expected, state);
}
let tag_con = Constraint::Pattern(
region,
PatternCategory::Ctor(symbol.clone()),
Type::TagUnion(
vec![(symbol.clone(), vec![])],
vec![(symbol.clone(), argument_types)],
Box::new(Type::Variable(*ext_var)),
),
expected,

View file

@ -1426,7 +1426,17 @@ pub fn record_literal<'a>(min_indent: u16) -> impl Parser<'a, Expr<'a>> {
/// This is mainly for matching tags in closure params, e.g. \@Foo -> ...
fn private_tag<'a>() -> impl Parser<'a, &'a str> {
skip_first!(char('@'), global_tag())
// TODO should be refactored so the name is not allocated again.
map_with_arena!(
skip_first!(char('@'), global_tag()),
|arena: &'a Bump, name: &'a str| {
use bumpalo::collections::string::String;
let mut buf = String::with_capacity_in(1 + name.len(), arena);
buf.push('@');
buf.push_str(name);
buf.into_bump_str()
}
)
}
/// This is mainly for matching tags in closure params, e.g. \Foo -> ...

View file

@ -174,11 +174,22 @@ fn constrain_pattern(
state.constraints.push(record_con);
}
AppliedTag(ext_var, symbol, _arguments) => {
AppliedTag(ext_var, symbol, patterns) => {
let mut argument_types = Vec::with_capacity(patterns.len());
for (pattern_var, loc_pattern) in patterns {
state.vars.push(*pattern_var);
let pattern_type = Type::Variable(*pattern_var);
argument_types.push(pattern_type.clone());
let expected = PExpected::NoExpectation(pattern_type);
constrain_pattern(var_store, state, loc_pattern, expected);
}
let union_type = constrain::lift(
var_store,
Type::TagUnion(
vec![(symbol.clone(), vec![])],
vec![(symbol.clone(), argument_types)],
Box::new(Type::Variable(*ext_var)),
),
);

View file

@ -1038,7 +1038,7 @@ mod test_infer {
r#"\@Foo -> 42
"#
),
"[ Test.Foo ]* -> Int",
"[ Test.@Foo ]* -> Int",
);
}
@ -1108,4 +1108,30 @@ mod test_infer {
"Int",
);
}
#[test]
fn global_tag_with_field() {
infer_eq(
indoc!(
r#"
when Foo 4 is
Foo x -> x
"#
),
"Int",
);
}
#[test]
fn private_tag_with_field() {
infer_eq(
indoc!(
r#"
when @Foo 4 is
@Foo x -> x
"#
),
"Int",
);
}
}

View file

@ -1370,13 +1370,13 @@ mod test_parse {
let newline = bumpalo::vec![in &arena; Newline];
let newlines = bumpalo::vec![in &arena; Newline, Newline];
let tag1 = Tag::Private {
name: Located::new(0, 0, 8, 13, "True"),
name: Located::new(0, 0, 8, 13, "@True"),
args: &[],
};
let tag2arg = Located::new(0, 0, 24, 29, TypeAnnotation::Apply(&[], "Thing", &[]));
let tag2args = bumpalo::vec![in &arena; tag2arg];
let tag2 = Tag::Private {
name: Located::new(0, 0, 15, 23, "Perhaps"),
name: Located::new(0, 0, 15, 23, "@Perhaps"),
args: tag2args.into_bump_slice(),
};
let tags = bumpalo::vec![in &arena;
@ -1424,13 +1424,13 @@ mod test_parse {
let newline = bumpalo::vec![in &arena; Newline];
let newlines = bumpalo::vec![in &arena; Newline, Newline];
let tag1 = Tag::Private {
name: Located::new(0, 0, 8, 13, "True"),
name: Located::new(0, 0, 8, 13, "@True"),
args: &[],
};
let tag2arg = Located::new(0, 0, 24, 29, TypeAnnotation::Apply(&[], "Thing", &[]));
let tag2args = bumpalo::vec![in &arena; tag2arg];
let tag2 = Tag::Private {
name: Located::new(0, 0, 15, 23, "Perhaps"),
name: Located::new(0, 0, 15, 23, "@Perhaps"),
args: tag2args.into_bump_slice(),
};
let tags = bumpalo::vec![in &arena;

View file

@ -932,7 +932,7 @@ mod test_infer_uniq {
r#"\@Foo -> 42
"#
),
"Attr.Attr * (Attr.Attr * [ Test.Foo ]* -> Attr.Attr * Int)",
"Attr.Attr * (Attr.Attr * [ Test.@Foo ]* -> Attr.Attr * Int)",
);
}