better error message for type start

This commit is contained in:
Folkert 2021-03-21 15:50:32 +01:00
parent 22f77ed966
commit 8d80dc97c8
4 changed files with 85 additions and 71 deletions

View file

@ -221,10 +221,7 @@ fn loc_possibly_negative_or_negated_term<'a>(
] ]
} }
fn fail_expr_start_e<'a, T>() -> impl Parser<'a, T, EExpr<'a>> fn fail_expr_start_e<'a, T: 'a>() -> impl Parser<'a, T, EExpr<'a>> {
where
T: 'a,
{
|_arena, state: State<'a>| Err((NoProgress, EExpr::Start(state.line, state.column), state)) |_arena, state: State<'a>| Err((NoProgress, EExpr::Start(state.line, state.column), state))
} }
@ -1019,7 +1016,7 @@ fn parse_expr_operator<'a>(
match expr_to_pattern_help(arena, &call.value) { match expr_to_pattern_help(arena, &call.value) {
Ok(good) => { Ok(good) => {
let (_, mut ann_type, state) = specialize( let parser = specialize(
EExpr::Type, EExpr::Type,
space0_before_e( space0_before_e(
type_annotation::located_help(indented_more), type_annotation::located_help(indented_more),
@ -1027,21 +1024,28 @@ fn parse_expr_operator<'a>(
Type::TSpace, Type::TSpace,
Type::TIndentStart, Type::TIndentStart,
), ),
) );
.parse(arena, state)?;
// put the spaces from after the operator in front of the call match parser.parse(arena, state) {
if !spaces_after_operator.is_empty() { Err((_, fail, state)) => return Err((MadeProgress, fail, state)),
ann_type = arena Ok((_, mut ann_type, state)) => {
.alloc(ann_type.value) // put the spaces from after the operator in front of the call
.with_spaces_before(spaces_after_operator, ann_type.region); if !spaces_after_operator.is_empty() {
ann_type = arena.alloc(ann_type.value).with_spaces_before(
spaces_after_operator,
ann_type.region,
);
}
let alias_region =
Region::span_across(&call.region, &ann_type.region);
let alias =
Def::Annotation(Located::at(expr_region, good), ann_type);
(&*arena.alloc(Located::at(alias_region, alias)), state)
}
} }
let alias_region = Region::span_across(&call.region, &ann_type.region);
let alias = Def::Annotation(Located::at(expr_region, good), ann_type);
(&*arena.alloc(Located::at(alias_region, alias)), state)
} }
Err(_) => { Err(_) => {
// this `:` likely occured inline; treat it as an invalid operator // this `:` likely occured inline; treat it as an invalid operator

View file

@ -45,6 +45,10 @@ fn tag_union_type<'a>(min_indent: u16) -> impl Parser<'a, TypeAnnotation<'a>, TT
} }
} }
fn fail_type_start<'a, T: 'a>() -> impl Parser<'a, T, Type<'a>> {
|_arena, state: State<'a>| Err((NoProgress, Type::TStart(state.line, state.column), state))
}
fn term<'a>(min_indent: u16) -> impl Parser<'a, Located<TypeAnnotation<'a>>, Type<'a>> { fn term<'a>(min_indent: u16) -> impl Parser<'a, Located<TypeAnnotation<'a>>, Type<'a>> {
map_with_arena!( map_with_arena!(
and!( and!(
@ -54,7 +58,8 @@ fn term<'a>(min_indent: u16) -> impl Parser<'a, Located<TypeAnnotation<'a>>, Typ
loc!(specialize(Type::TRecord, record_type(min_indent))), loc!(specialize(Type::TRecord, record_type(min_indent))),
loc!(specialize(Type::TTagUnion, tag_union_type(min_indent))), loc!(specialize(Type::TTagUnion, tag_union_type(min_indent))),
loc!(applied_type(min_indent)), loc!(applied_type(min_indent)),
loc!(parse_type_variable) loc!(parse_type_variable),
fail_type_start(),
), ),
// Inline alias notation, e.g. [ Nil, Cons a (List a) ] as List a // Inline alias notation, e.g. [ Nil, Cons a (List a) ] as List a
one_of![ one_of![

View file

@ -1781,7 +1781,13 @@ fn to_type_report<'a>(
let doc = alloc.stack(vec![ let doc = alloc.stack(vec![
alloc.reflow(r"I just started parsing a type, but I got stuck here:"), alloc.reflow(r"I just started parsing a type, but I got stuck here:"),
alloc.region_with_subregion(surroundings, region), alloc.region_with_subregion(surroundings, region),
alloc.note("I may be confused by indentation"), alloc.concat(vec![
alloc.reflow(r"I am expecting a type next, like "),
alloc.parser_suggestion("Bool"),
alloc.reflow(r" or "),
alloc.parser_suggestion("List a"),
alloc.reflow("."),
]),
]); ]);
Report { Report {

View file

@ -3265,20 +3265,20 @@ mod test_reporting {
indoc!( indoc!(
r#" r#"
TYPE MISMATCH TYPE MISMATCH
Something is off with the body of the `x` definition: Something is off with the body of the `x` definition:
4 x : AList I64 I64 4 x : AList I64 I64
5 x = ACons 0 (BCons 1 (ACons "foo" BNil )) 5 x = ACons 0 (BCons 1 (ACons "foo" BNil ))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
This `ACons` global tag application has the type: This `ACons` global tag application has the type:
[ ACons Num (Integer Signed64) [ BCons (Num a) [ ACons Str [ BNil [ ACons Num (Integer Signed64) [ BCons (Num a) [ ACons Str [ BNil
]b ]c ]d, ANil ] ]b ]c ]d, ANil ]
But the type annotation on `x` says it should be: But the type annotation on `x` says it should be:
[ ACons I64 BList I64 I64, ANil ] [ ACons I64 BList I64 I64, ANil ]
"# "#
), ),
@ -4155,12 +4155,12 @@ mod test_reporting {
indoc!( indoc!(
r#" r#"
UNKNOWN OPERATOR UNKNOWN OPERATOR
This looks like an operator, but it's not one I recognize! This looks like an operator, but it's not one I recognize!
1 f :: I64 1 f :: I64
^^ ^^
I have no specific suggestion for this operator, see TODO for the full I have no specific suggestion for this operator, see TODO for the full
list of operators in Roc. list of operators in Roc.
"# "#
@ -4188,12 +4188,12 @@ mod test_reporting {
indoc!( indoc!(
r#" r#"
TOO MANY ARGS TOO MANY ARGS
This value is not a function, but it was given 3 arguments: This value is not a function, but it was given 3 arguments:
3 x == 5 3 x == 5
^ ^
Are there any missing commas? Or missing parentheses? Are there any missing commas? Or missing parentheses?
"# "#
), ),
@ -4474,16 +4474,16 @@ mod test_reporting {
report_problem_as( report_problem_as(
"# comment with a \t\n4", "# comment with a \t\n4",
indoc!( indoc!(
r#" "
TAB CHARACTER TAB CHARACTER
I encountered a tab character I encountered a tab character
1 # comment with a 1 # comment with a \t
^ ^
Tab characters are not allowed. Tab characters are not allowed.
"# "
), ),
) )
} }
@ -4499,12 +4499,14 @@ mod test_reporting {
), ),
indoc!( indoc!(
r#" r#"
BAD TYPE VARIABLE UNFINISHED TYPE
I am expecting a type variable, but I got stuck here: I just started parsing a type, but I got stuck here:
1 f : ( 1 f : (
^ ^
I am expecting a type next, like Bool or List a.
"# "#
), ),
) )
@ -4583,7 +4585,6 @@ mod test_reporting {
} }
#[test] #[test]
#[ignore]
fn type_apply_stray_dot() { fn type_apply_stray_dot() {
// TODO good message // TODO good message
report_problem_as( report_problem_as(
@ -4594,16 +4595,14 @@ mod test_reporting {
), ),
indoc!( indoc!(
r#" r#"
UNFINISHED PARENTHESES UNFINISHED TYPE
I am partway through parsing a type in parentheses, but I got stuck I just started parsing a type, but I got stuck here:
here:
1 f : ( I64 1 f : .
^ ^
I was expecting to see a closing parenthesis before this, so try I am expecting a type next, like Bool or List a.
adding a ) and see if that helps?
"# "#
), ),
) )
@ -4658,19 +4657,19 @@ mod test_reporting {
indoc!( indoc!(
r#" r#"
MISSING FINAL EXPRESSION MISSING FINAL EXPRESSION
I am partway through parsing a definition's final expression, but I I am partway through parsing a definition's final expression, but I
got stuck here: got stuck here:
1 f : Foo.foo 1 f : Foo.foo
^ ^
This definition is missing a final expression. A nested definition This definition is missing a final expression. A nested definition
must be followed by either another definition, or an expression must be followed by either another definition, or an expression
x = 4 x = 4
y = 2 y = 2
x + y x + y
"# "#
), ),
@ -4973,13 +4972,13 @@ mod test_reporting {
indoc!( indoc!(
r#" r#"
MISSING EXPRESSION MISSING EXPRESSION
I am partway through parsing a definition, but I got stuck here: I am partway through parsing a definition, but I got stuck here:
1 when Just 4 is 1 when Just 4 is
2 Just when -> 2 Just when ->
^ ^
I was expecting to see an expression like 42 or "hello". I was expecting to see an expression like 42 or "hello".
"# "#
), ),
@ -5646,14 +5645,14 @@ mod test_reporting {
indoc!( indoc!(
r#" r#"
SYNTAX PROBLEM SYNTAX PROBLEM
I cannot find a `bar` value I cannot find a `bar` value
1 [ "foo", bar("") ] 1 [ "foo", bar("") ]
^^^ ^^^
these names seem close though: these names seem close though:
Nat Nat
Str Str
U8 U8
@ -5729,16 +5728,16 @@ mod test_reporting {
indoc!( indoc!(
r#" r#"
UNKNOWN OPERATOR UNKNOWN OPERATOR
This looks like an operator, but it's not one I recognize! This looks like an operator, but it's not one I recognize!
1 main = 1 main =
2 (\x -> x) : I64 2 (\x -> x) : I64
^ ^
The has-type operator : can only occur in a definition's type The has-type operator : can only occur in a definition's type
signature, like signature, like
increment : I64 -> I64 increment : I64 -> I64
increment = \x -> x + 1 increment = \x -> x + 1
"# "#
@ -5759,19 +5758,19 @@ mod test_reporting {
indoc!( indoc!(
r#" r#"
MISSING FINAL EXPRESSION MISSING FINAL EXPRESSION
I am partway through parsing a definition's final expression, but I I am partway through parsing a definition's final expression, but I
got stuck here: got stuck here:
1 main = 5 -> 3 1 main = 5 -> 3
^ ^
This definition is missing a final expression. A nested definition This definition is missing a final expression. A nested definition
must be followed by either another definition, or an expression must be followed by either another definition, or an expression
x = 4 x = 4
y = 2 y = 2
x + y x + y
"# "#
), ),