parse records with type signatures

{ x, y } : { x : Int, y : Float }
This commit is contained in:
Folkert 2019-12-22 20:23:12 +01:00
parent 97f2c57a39
commit 9d7ce6ff15
2 changed files with 53 additions and 2 deletions

View file

@ -1235,7 +1235,10 @@ pub fn record_literal<'a>(min_indent: u16) -> impl Parser<'a, Expr<'a>> {
Attempting::Record, Attempting::Record,
loc!(record!(loc!(expr(min_indent)), min_indent)) loc!(record!(loc!(expr(min_indent)), min_indent))
), ),
optional(and!(space0(min_indent), equals_with_indent())) optional(and!(
space0(min_indent),
either!(equals_with_indent(), colon_with_indent())
))
), ),
move |arena, state, (loc_assigned_fields, opt_def)| match opt_def { move |arena, state, (loc_assigned_fields, opt_def)| match opt_def {
None => { None => {
@ -1258,7 +1261,7 @@ pub fn record_literal<'a>(min_indent: u16) -> impl Parser<'a, Expr<'a>> {
Ok((value, state)) Ok((value, state))
} }
Some((spaces_before_equals, equals_indent)) => { Some((spaces_before_equals, Either::First(equals_indent))) => {
// This is a record destructure def. // This is a record destructure def.
let region = loc_assigned_fields.region; let region = loc_assigned_fields.region;
let assigned_fields = loc_assigned_fields.value; let assigned_fields = loc_assigned_fields.value;
@ -1291,6 +1294,40 @@ pub fn record_literal<'a>(min_indent: u16) -> impl Parser<'a, Expr<'a>> {
Expr::SpaceBefore(arena.alloc(parsed_expr), spaces_after_equals) Expr::SpaceBefore(arena.alloc(parsed_expr), spaces_after_equals)
}; };
Ok((answer, state))
}
Some((spaces_before_colon, Either::Second(colon_indent))) => {
// This is a record type annotation
let region = loc_assigned_fields.region;
let assigned_fields = loc_assigned_fields.value;
let mut loc_patterns = Vec::with_capacity_in(assigned_fields.len(), arena);
for loc_assigned_field in assigned_fields {
let region = loc_assigned_field.region;
match assigned_field_to_pattern(arena, &loc_assigned_field.value) {
Ok(value) => loc_patterns.push(Located { region, value }),
// an Expr became a pattern that should not be.
Err(e) => return Err((e, state)),
}
}
let pattern = Pattern::RecordDestructure(loc_patterns);
let value = if spaces_before_colon.is_empty() {
pattern
} else {
Pattern::SpaceAfter(arena.alloc(pattern), spaces_before_colon)
};
let loc_pattern = Located { region, value };
let (spaces_after_equals, state) = space0(min_indent).parse(arena, state)?;
let (parsed_expr, state) =
parse_def_signature(min_indent, colon_indent, arena, state, loc_pattern)?;
let answer = if spaces_after_equals.is_empty() {
parsed_expr
} else {
Expr::SpaceBefore(arena.alloc(parsed_expr), spaces_after_equals)
};
Ok((answer, state)) Ok((answer, state))
} }
}, },

View file

@ -902,4 +902,18 @@ mod test_infer {
fn accessor_function() { fn accessor_function() {
infer_eq(".foo", "{ foo : a }* -> a"); infer_eq(".foo", "{ foo : a }* -> a");
} }
#[test]
fn type_signature_without_body_record() {
infer_eq(
indoc!(
r#"
{ x, y } : { x : (Int -> custom) , y : Int }
x
"#
),
"Int -> custom",
);
}
} }