Merge branch 'trunk' into fix-uniq-principality

This commit is contained in:
Richard Feldman 2020-01-08 22:47:12 -05:00 committed by GitHub
commit e019a4b662
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 82 additions and 28 deletions

View file

@ -73,8 +73,9 @@ pub fn fmt_expr<'a>(
} }
buf.push_str("\"\"\""); buf.push_str("\"\"\"");
} }
Int(string) => buf.push_str(string), Int(string) | Float(string) | GlobalTag(string) | PrivateTag(string) => {
Float(string) => buf.push_str(string), buf.push_str(string)
}
NonBase10Int { NonBase10Int {
base, base,
string, string,
@ -480,7 +481,7 @@ pub fn fmt_closure<'a>(
any_args_printed = true; any_args_printed = true;
} }
fmt_pattern(buf, &loc_pattern.value, indent, true); fmt_pattern(buf, &loc_pattern.value, indent, false);
} }
if !arguments_are_multiline { if !arguments_are_multiline {

View file

@ -430,7 +430,7 @@ pub fn loc_parenthetical_def<'a>(min_indent: u16) -> impl Parser<'a, Located<Exp
space0_after( space0_after(
between!( between!(
char('('), char('('),
space0_around(loc!(pattern(min_indent)), min_indent), space0_around(loc_pattern(min_indent), min_indent),
char(')') char(')')
), ),
min_indent, min_indent,
@ -752,23 +752,32 @@ fn parse_closure_param<'a>(
// e.g. \User.UserId userId -> ... // e.g. \User.UserId userId -> ...
between!( between!(
char('('), char('('),
space0_around(loc!(pattern(min_indent)), min_indent), space0_around(loc_pattern(min_indent), min_indent),
char(')') char(')')
), ),
// The least common, but still allowed, e.g. \Foo -> ... // The least common, but still allowed, e.g. \Foo -> ...
loc!(tag_pattern()) loc_tag_pattern(min_indent)
) )
.parse(arena, state) .parse(arena, state)
} }
fn pattern<'a>(min_indent: u16) -> impl Parser<'a, Pattern<'a>> { fn loc_pattern<'a>(min_indent: u16) -> impl Parser<'a, Located<Pattern<'a>>> {
one_of!( one_of!(
underscore_pattern(), loc_parenthetical_pattern(min_indent),
tag_pattern(), loc!(underscore_pattern()),
ident_pattern(), loc_tag_pattern(min_indent),
record_destructure(min_indent), loc!(ident_pattern()),
string_pattern(), loc!(record_destructure(min_indent)),
int_pattern() loc!(string_pattern()),
loc!(int_pattern())
)
}
fn loc_parenthetical_pattern<'a>(min_indent: u16) -> impl Parser<'a, Located<Pattern<'a>>> {
between!(
char('('),
move |arena, state| loc_pattern(min_indent).parse(arena, state),
char(')')
) )
} }
@ -796,7 +805,7 @@ fn underscore_pattern<'a>() -> impl Parser<'a, Pattern<'a>> {
fn record_destructure<'a>(min_indent: u16) -> impl Parser<'a, Pattern<'a>> { fn record_destructure<'a>(min_indent: u16) -> impl Parser<'a, Pattern<'a>> {
then( then(
record_without_update!(loc!(pattern(min_indent)), min_indent), record_without_update!(loc_pattern(min_indent), min_indent),
move |arena, state, assigned_fields| { move |arena, state, assigned_fields| {
let mut patterns = Vec::with_capacity_in(assigned_fields.len(), arena); let mut patterns = Vec::with_capacity_in(assigned_fields.len(), arena);
for assigned_field in assigned_fields { for assigned_field in assigned_fields {
@ -815,10 +824,29 @@ fn record_destructure<'a>(min_indent: u16) -> impl Parser<'a, Pattern<'a>> {
) )
} }
fn tag_pattern<'a>() -> impl Parser<'a, Pattern<'a>> { fn loc_tag_pattern<'a>(min_indent: u16) -> impl Parser<'a, Located<Pattern<'a>>> {
one_of!( map_with_arena!(
map!(private_tag(), Pattern::PrivateTag), and!(
map!(global_tag(), Pattern::GlobalTag) loc!(one_of!(
map!(private_tag(), Pattern::PrivateTag),
map!(global_tag(), Pattern::GlobalTag)
)),
// This can optionally be an applied pattern, e.g. (Foo bar) instead of (Foo)
zero_or_more!(space1_before(loc_pattern(min_indent), min_indent))
),
|arena: &'a Bump,
(loc_tag, loc_args): (Located<Pattern<'a>>, Vec<'a, Located<Pattern<'a>>>)| {
if loc_args.is_empty() {
loc_tag
} else {
// TODO FIME this region doesn't cover the tag's
// arguments; need to add them to the region!
let region = loc_tag.region;
let value = Pattern::Apply(&*arena.alloc(loc_tag), loc_args.into_bump_slice());
Located { region, value }
}
}
) )
} }
@ -868,7 +896,7 @@ pub fn case_branches<'a>(
// 2. Parse the other branches. Their indentation levels must be == the first branch's. // 2. Parse the other branches. Their indentation levels must be == the first branch's.
let (mut loc_first_pattern, state) = let (mut loc_first_pattern, state) =
space1_before(loc!(pattern(min_indent)), min_indent).parse(arena, state)?; space1_before(loc_pattern(min_indent), min_indent).parse(arena, state)?;
let original_indent = state.indent_col; let original_indent = state.indent_col;
let indented_more = original_indent + 1; let indented_more = original_indent + 1;
let (spaces_before_arrow, state) = space0(min_indent).parse(arena, state)?; let (spaces_before_arrow, state) = space0(min_indent).parse(arena, state)?;
@ -898,7 +926,7 @@ pub fn case_branches<'a>(
let branch_parser = and!( let branch_parser = and!(
then( then(
space1_around(loc!(pattern(min_indent)), min_indent), space1_around(loc_pattern(min_indent), min_indent),
move |_arena, state, loc_pattern| { move |_arena, state, loc_pattern| {
if state.indent_col == original_indent { if state.indent_col == original_indent {
Ok((loc_pattern, state)) Ok((loc_pattern, state))

View file

@ -208,6 +208,13 @@ fn write_flat_type(flat_type: FlatType, subs: &mut Subs, buf: &mut String, paren
EmptyTagUnion => buf.push_str(EMPTY_TAG_UNION), EmptyTagUnion => buf.push_str(EMPTY_TAG_UNION),
Func(args, ret) => write_fn(args, ret, subs, buf, parens), Func(args, ret) => write_fn(args, ret, subs, buf, parens),
Record(fields, ext_var) => { Record(fields, ext_var) => {
use crate::unify::gather_fields;
use crate::unify::RecordStructure;
// If the `ext` has concrete fields (e.g. { foo : Int}{ bar : Bool }), merge them
let RecordStructure { fields, ext } = gather_fields(subs, fields, ext_var);
let ext_var = ext;
if fields.is_empty() { if fields.is_empty() {
buf.push_str(EMPTY_RECORD) buf.push_str(EMPTY_RECORD)
} else { } else {

View file

@ -16,9 +16,9 @@ struct Context {
second_desc: Descriptor, second_desc: Descriptor,
} }
struct RecordStructure { pub struct RecordStructure {
fields: ImMap<RecordFieldLabel, Variable>, pub fields: ImMap<RecordFieldLabel, Variable>,
ext: Variable, pub ext: Variable,
} }
struct TagUnionStructure { struct TagUnionStructure {
@ -519,7 +519,7 @@ fn unify_flex(
} }
} }
fn gather_fields( pub fn gather_fields(
subs: &mut Subs, subs: &mut Subs,
fields: ImMap<RecordFieldLabel, Variable>, fields: ImMap<RecordFieldLabel, Variable>,
var: Variable, var: Variable,

View file

@ -294,6 +294,24 @@ mod test_format {
)); ));
} }
#[test]
fn destructure_tag_closure() {
expr_formats_same(indoc!(
r#"
\Foo a -> Foo a
"#
));
}
#[test]
fn destructure_nested_tag_closure() {
expr_formats_same(indoc!(
r#"
\Foo (Bar a) -> Foo (Bar a)
"#
));
}
// DEFS // DEFS
#[test] #[test]

View file

@ -1005,7 +1005,7 @@ mod test_infer {
{ user & year: "foo" } { user & year: "foo" }
"# "#
), ),
"{ year : Str }{ name : Str }", "{ name : Str, year : Str }",
); );
} }

View file

@ -641,7 +641,7 @@ mod test_parse {
assert_eq!(Ok(expected), actual); assert_eq!(Ok(expected), actual);
} }
// VARIANT // TAG
#[test] #[test]
fn basic_global_tag() { fn basic_global_tag() {

View file

@ -899,7 +899,7 @@ mod test_infer_uniq {
{ user & year: "foo" } { user & year: "foo" }
"# "#
), ),
"Attr.Attr * { year : (Attr.Attr * Str) }{ name : (Attr.Attr * Str) }", "Attr.Attr * { name : (Attr.Attr * Str), year : (Attr.Attr * Str) }",
); );
} }