mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-03 16:44:33 +00:00
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:
parent
98515cdf23
commit
dd240cf53a
7 changed files with 104 additions and 29 deletions
|
@ -17,7 +17,7 @@ use im_rc::Vector;
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
pub enum Pattern {
|
pub enum Pattern {
|
||||||
Identifier(Symbol),
|
Identifier(Symbol),
|
||||||
AppliedTag(Variable, Symbol, Vec<Located<Pattern>>),
|
AppliedTag(Variable, Symbol, Vec<(Variable, Located<Pattern>)>),
|
||||||
IntLiteral(i64),
|
IntLiteral(i64),
|
||||||
FloatLiteral(f64),
|
FloatLiteral(f64),
|
||||||
StrLiteral(Box<str>),
|
StrLiteral(Box<str>),
|
||||||
|
@ -94,6 +94,32 @@ pub fn canonicalize_pattern<'a>(
|
||||||
vec![],
|
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 {
|
&FloatLiteral(ref string) => match pattern_type {
|
||||||
WhenBranch => {
|
WhenBranch => {
|
||||||
let float = finish_parsing_float(string)
|
let float = finish_parsing_float(string)
|
||||||
|
@ -344,13 +370,10 @@ pub fn remove_idents(pattern: &ast::Pattern, idents: &mut ImMap<Ident, (Symbol,
|
||||||
QualifiedIdentifier(_name) => {
|
QualifiedIdentifier(_name) => {
|
||||||
panic!("TODO implement QualifiedIdentifier pattern in remove_idents.");
|
panic!("TODO implement QualifiedIdentifier pattern in remove_idents.");
|
||||||
}
|
}
|
||||||
Apply(_, _) => {
|
Apply(_, patterns) => {
|
||||||
panic!("TODO implement Apply pattern in remove_idents.");
|
for loc_pattern in *patterns {
|
||||||
// AppliedVariant(_, Some(loc_args)) => {
|
remove_idents(&loc_pattern.value, idents);
|
||||||
// for loc_arg in loc_args {
|
}
|
||||||
// remove_idents(loc_arg.value, idents);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
RecordDestructure(patterns) => {
|
RecordDestructure(patterns) => {
|
||||||
for loc_pattern in patterns {
|
for loc_pattern in patterns {
|
||||||
|
@ -410,16 +433,10 @@ fn add_idents_from_pattern<'a>(
|
||||||
QualifiedIdentifier(_name) => {
|
QualifiedIdentifier(_name) => {
|
||||||
panic!("TODO implement QualifiedIdentifier pattern.");
|
panic!("TODO implement QualifiedIdentifier pattern.");
|
||||||
}
|
}
|
||||||
Apply(_, _) => {
|
Apply(_tag, patterns) => {
|
||||||
panic!("TODO implement Apply pattern.");
|
for loc_pattern in *patterns {
|
||||||
// &AppliedVariant(_, ref opt_loc_args) => match opt_loc_args {
|
add_idents_from_pattern(&loc_pattern.region, &loc_pattern.value, scope, answer);
|
||||||
// &None => (),
|
}
|
||||||
// &Some(ref loc_args) => {
|
|
||||||
// for loc_arg in loc_args.iter() {
|
|
||||||
// add_idents_from_pattern(loc_arg, scope, answer);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// },
|
|
||||||
}
|
}
|
||||||
|
|
||||||
RecordDestructure(patterns) => {
|
RecordDestructure(patterns) => {
|
||||||
|
|
|
@ -105,12 +105,23 @@ pub fn constrain_pattern(
|
||||||
|
|
||||||
state.constraints.push(record_con);
|
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(
|
let tag_con = Constraint::Pattern(
|
||||||
region,
|
region,
|
||||||
PatternCategory::Ctor(symbol.clone()),
|
PatternCategory::Ctor(symbol.clone()),
|
||||||
Type::TagUnion(
|
Type::TagUnion(
|
||||||
vec![(symbol.clone(), vec![])],
|
vec![(symbol.clone(), argument_types)],
|
||||||
Box::new(Type::Variable(*ext_var)),
|
Box::new(Type::Variable(*ext_var)),
|
||||||
),
|
),
|
||||||
expected,
|
expected,
|
||||||
|
|
|
@ -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 -> ...
|
/// This is mainly for matching tags in closure params, e.g. \@Foo -> ...
|
||||||
fn private_tag<'a>() -> impl Parser<'a, &'a str> {
|
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 -> ...
|
/// This is mainly for matching tags in closure params, e.g. \Foo -> ...
|
||||||
|
|
|
@ -174,11 +174,22 @@ fn constrain_pattern(
|
||||||
state.constraints.push(record_con);
|
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(
|
let union_type = constrain::lift(
|
||||||
var_store,
|
var_store,
|
||||||
Type::TagUnion(
|
Type::TagUnion(
|
||||||
vec![(symbol.clone(), vec![])],
|
vec![(symbol.clone(), argument_types)],
|
||||||
Box::new(Type::Variable(*ext_var)),
|
Box::new(Type::Variable(*ext_var)),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
|
@ -1038,7 +1038,7 @@ mod test_infer {
|
||||||
r#"\@Foo -> 42
|
r#"\@Foo -> 42
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
"[ Test.Foo ]* -> Int",
|
"[ Test.@Foo ]* -> Int",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1108,4 +1108,30 @@ mod test_infer {
|
||||||
"Int",
|
"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",
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1370,13 +1370,13 @@ mod test_parse {
|
||||||
let newline = bumpalo::vec![in &arena; Newline];
|
let newline = bumpalo::vec![in &arena; Newline];
|
||||||
let newlines = bumpalo::vec![in &arena; Newline, Newline];
|
let newlines = bumpalo::vec![in &arena; Newline, Newline];
|
||||||
let tag1 = Tag::Private {
|
let tag1 = Tag::Private {
|
||||||
name: Located::new(0, 0, 8, 13, "True"),
|
name: Located::new(0, 0, 8, 13, "@True"),
|
||||||
args: &[],
|
args: &[],
|
||||||
};
|
};
|
||||||
let tag2arg = Located::new(0, 0, 24, 29, TypeAnnotation::Apply(&[], "Thing", &[]));
|
let tag2arg = Located::new(0, 0, 24, 29, TypeAnnotation::Apply(&[], "Thing", &[]));
|
||||||
let tag2args = bumpalo::vec![in &arena; tag2arg];
|
let tag2args = bumpalo::vec![in &arena; tag2arg];
|
||||||
let tag2 = Tag::Private {
|
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(),
|
args: tag2args.into_bump_slice(),
|
||||||
};
|
};
|
||||||
let tags = bumpalo::vec![in &arena;
|
let tags = bumpalo::vec![in &arena;
|
||||||
|
@ -1424,13 +1424,13 @@ mod test_parse {
|
||||||
let newline = bumpalo::vec![in &arena; Newline];
|
let newline = bumpalo::vec![in &arena; Newline];
|
||||||
let newlines = bumpalo::vec![in &arena; Newline, Newline];
|
let newlines = bumpalo::vec![in &arena; Newline, Newline];
|
||||||
let tag1 = Tag::Private {
|
let tag1 = Tag::Private {
|
||||||
name: Located::new(0, 0, 8, 13, "True"),
|
name: Located::new(0, 0, 8, 13, "@True"),
|
||||||
args: &[],
|
args: &[],
|
||||||
};
|
};
|
||||||
let tag2arg = Located::new(0, 0, 24, 29, TypeAnnotation::Apply(&[], "Thing", &[]));
|
let tag2arg = Located::new(0, 0, 24, 29, TypeAnnotation::Apply(&[], "Thing", &[]));
|
||||||
let tag2args = bumpalo::vec![in &arena; tag2arg];
|
let tag2args = bumpalo::vec![in &arena; tag2arg];
|
||||||
let tag2 = Tag::Private {
|
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(),
|
args: tag2args.into_bump_slice(),
|
||||||
};
|
};
|
||||||
let tags = bumpalo::vec![in &arena;
|
let tags = bumpalo::vec![in &arena;
|
||||||
|
|
|
@ -932,7 +932,7 @@ mod test_infer_uniq {
|
||||||
r#"\@Foo -> 42
|
r#"\@Foo -> 42
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
"Attr.Attr * (Attr.Attr * [ Test.Foo ]* -> Attr.Attr * Int)",
|
"Attr.Attr * (Attr.Attr * [ Test.@Foo ]* -> Attr.Attr * Int)",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue