mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-02 08:11:12 +00:00
add FnCall error message
This commit is contained in:
parent
1a3356ff0c
commit
ccd021a755
2 changed files with 227 additions and 23 deletions
|
@ -129,7 +129,9 @@ fn to_expr_report(
|
||||||
use ReportText::*;
|
use ReportText::*;
|
||||||
|
|
||||||
match expected {
|
match expected {
|
||||||
Expected::NoExpectation(expected_type) => todo!("hit no expectation with type {:?}", expected_type),
|
Expected::NoExpectation(expected_type) => {
|
||||||
|
todo!("hit no expectation with type {:?}", expected_type)
|
||||||
|
}
|
||||||
Expected::FromAnnotation(name, _arity, annotation_source, expected_type) => {
|
Expected::FromAnnotation(name, _arity, annotation_source, expected_type) => {
|
||||||
use roc_types::types::AnnotationSource::*;
|
use roc_types::types::AnnotationSource::*;
|
||||||
|
|
||||||
|
@ -137,9 +139,21 @@ fn to_expr_report(
|
||||||
|
|
||||||
// TODO special-case 2-branch if
|
// TODO special-case 2-branch if
|
||||||
let thing = match annotation_source {
|
let thing = match annotation_source {
|
||||||
TypedIfBranch ( index ) => Concat(vec![ plain_text(&format!("{} branch of this ", int_to_ordinal(index))), keyword_text("if"), plain_text(" expression:") ]),
|
TypedIfBranch(index) => Concat(vec![
|
||||||
TypedWhenBranch ( index ) => Concat(vec![ plain_text(&format!("{} branch of this ", int_to_ordinal(index))), keyword_text("when"), plain_text(" expression:") ]),
|
plain_text(&format!("{} branch of this ", int_to_ordinal(index))),
|
||||||
TypedBody => Concat(vec![ plain_text("body of the "), name_text.clone(), plain_text(" definition:") ]),
|
keyword_text("if"),
|
||||||
|
plain_text(" expression:"),
|
||||||
|
]),
|
||||||
|
TypedWhenBranch(index) => Concat(vec![
|
||||||
|
plain_text(&format!("{} branch of this ", int_to_ordinal(index))),
|
||||||
|
keyword_text("when"),
|
||||||
|
plain_text(" expression:"),
|
||||||
|
]),
|
||||||
|
TypedBody => Concat(vec![
|
||||||
|
plain_text("body of the "),
|
||||||
|
name_text.clone(),
|
||||||
|
plain_text(" definition:"),
|
||||||
|
]),
|
||||||
};
|
};
|
||||||
|
|
||||||
let it_is = match annotation_source {
|
let it_is = match annotation_source {
|
||||||
|
@ -148,19 +162,27 @@ fn to_expr_report(
|
||||||
TypedBody => "The body is".into(),
|
TypedBody => "The body is".into(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let comparison =
|
let comparison = type_comparison(
|
||||||
type_comparison(
|
|
||||||
found,
|
found,
|
||||||
expected_type,
|
expected_type,
|
||||||
add_category(plain_text(&it_is), &category),
|
add_category(plain_text(&it_is), &category),
|
||||||
Concat(vec![ plain_text("But the type annotation on "), name_text, plain_text(" says it should be:")]),
|
Concat(vec![
|
||||||
|
plain_text("But the type annotation on "),
|
||||||
|
name_text,
|
||||||
|
plain_text(" says it should be:"),
|
||||||
|
]),
|
||||||
Concat(vec![]),
|
Concat(vec![]),
|
||||||
);
|
);
|
||||||
|
|
||||||
Report {
|
Report {
|
||||||
title: "TYPE MISMATCH".to_string(),
|
title: "TYPE MISMATCH".to_string(),
|
||||||
filename,
|
filename,
|
||||||
text: Concat(vec![ plain_text("Something is off with the "), thing , Region(expr_region), comparison ]),
|
text: Concat(vec![
|
||||||
|
plain_text("Something is off with the "),
|
||||||
|
thing,
|
||||||
|
Region(expr_region),
|
||||||
|
comparison,
|
||||||
|
]),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Expected::ForReason(reason, expected_type, region) => match reason {
|
Expected::ForReason(reason, expected_type, region) => match reason {
|
||||||
|
@ -337,7 +359,7 @@ fn to_expr_report(
|
||||||
plain_text("I need all elements of a list to have the same type!"),
|
plain_text("I need all elements of a list to have the same type!"),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Reason::RecordUpdateValue(field) => { report_mismatch(
|
Reason::RecordUpdateValue(field) => report_mismatch(
|
||||||
filename,
|
filename,
|
||||||
&category,
|
&category,
|
||||||
found,
|
found,
|
||||||
|
@ -355,8 +377,104 @@ fn to_expr_report(
|
||||||
plain_text(" to be"),
|
plain_text(" to be"),
|
||||||
]),
|
]),
|
||||||
plain_text("But it should be:"),
|
plain_text("But it should be:"),
|
||||||
plain_text("Record update syntax does not allow you to change the type of fields. You can achieve that with record literal syntax."),
|
plain_text(
|
||||||
)}
|
r#"Record update syntax does not allow you to change the type of fields. You can achieve that with record literal syntax."#,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Reason::FnCall { name, arity } => match count_arguments(&found) {
|
||||||
|
0 => {
|
||||||
|
let this_value = match name {
|
||||||
|
None => plain_text("This value"),
|
||||||
|
Some(symbol) => Concat(vec![
|
||||||
|
plain_text("The "),
|
||||||
|
Value(symbol),
|
||||||
|
plain_text(" value"),
|
||||||
|
]),
|
||||||
|
};
|
||||||
|
|
||||||
|
let lines = vec![
|
||||||
|
Concat(vec![
|
||||||
|
this_value,
|
||||||
|
plain_text(&format!(
|
||||||
|
" is not a function, but it was given {}:",
|
||||||
|
if arity == 1 {
|
||||||
|
"1 argument".into()
|
||||||
|
} else {
|
||||||
|
format!("{} arguments", arity)
|
||||||
|
}
|
||||||
|
)),
|
||||||
|
]),
|
||||||
|
ReportText::Region(expr_region),
|
||||||
|
plain_text("Are there any missing commas? Or missing parentheses?"),
|
||||||
|
];
|
||||||
|
|
||||||
|
Report {
|
||||||
|
filename,
|
||||||
|
title: "TOO MANY ARGS".to_string(),
|
||||||
|
text: Concat(lines),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
n => {
|
||||||
|
let this_function = match name {
|
||||||
|
None => plain_text("This function"),
|
||||||
|
Some(symbol) => Concat(vec![
|
||||||
|
plain_text("The "),
|
||||||
|
Value(symbol),
|
||||||
|
plain_text(" function"),
|
||||||
|
]),
|
||||||
|
};
|
||||||
|
|
||||||
|
if n < arity as usize {
|
||||||
|
let lines = vec![
|
||||||
|
Concat(vec![
|
||||||
|
this_function,
|
||||||
|
plain_text(&format!(
|
||||||
|
" expects {}, but it got {} instead:",
|
||||||
|
if n == 1 {
|
||||||
|
"1 argument".into()
|
||||||
|
} else {
|
||||||
|
format!("{} arguments", n)
|
||||||
|
},
|
||||||
|
arity
|
||||||
|
)),
|
||||||
|
]),
|
||||||
|
ReportText::Region(expr_region),
|
||||||
|
plain_text("Are there any missing commas? Or missing parentheses?"),
|
||||||
|
];
|
||||||
|
|
||||||
|
Report {
|
||||||
|
filename,
|
||||||
|
title: "TOO MANY ARGS".to_string(),
|
||||||
|
text: Concat(lines),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let lines = vec![
|
||||||
|
Concat(vec![
|
||||||
|
this_function,
|
||||||
|
plain_text(&format!(
|
||||||
|
" expects {}, but it got only {}:",
|
||||||
|
if n == 1 {
|
||||||
|
"1 argument".into()
|
||||||
|
} else {
|
||||||
|
format!("{} arguments", n)
|
||||||
|
},
|
||||||
|
arity
|
||||||
|
)),
|
||||||
|
]),
|
||||||
|
ReportText::Region(expr_region),
|
||||||
|
plain_text(
|
||||||
|
r#"Roc does not allow functions to be partially applied. Use a closure to make partial application explicit."#,
|
||||||
|
),
|
||||||
|
];
|
||||||
|
|
||||||
|
Report {
|
||||||
|
filename,
|
||||||
|
title: "TOO FEW ARGS".to_string(),
|
||||||
|
text: Concat(lines),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
Reason::FnArg { name, arg_index } => {
|
Reason::FnArg { name, arg_index } => {
|
||||||
let ith = int_to_ordinal(arg_index as usize + 1);
|
let ith = int_to_ordinal(arg_index as usize + 1);
|
||||||
|
|
||||||
|
@ -372,13 +490,19 @@ fn to_expr_report(
|
||||||
expected_type,
|
expected_type,
|
||||||
region,
|
region,
|
||||||
Some(expr_region),
|
Some(expr_region),
|
||||||
Concat(vec![ plain_text(&format!("The {} argument to ", ith))
|
Concat(vec![
|
||||||
, this_function.clone(), plain_text(" is not what I expect:" )]),
|
plain_text(&format!("The {} argument to ", ith)),
|
||||||
|
this_function.clone(),
|
||||||
|
plain_text(" is not what I expect:"),
|
||||||
|
]),
|
||||||
plain_text("This argument is"),
|
plain_text("This argument is"),
|
||||||
Concat(vec![ plain_text("But "), this_function, plain_text(&format!(" needs the {} argument to be:", ith))]),
|
Concat(vec![
|
||||||
|
plain_text("But "),
|
||||||
|
this_function,
|
||||||
|
plain_text(&format!(" needs the {} argument to be:", ith)),
|
||||||
|
]),
|
||||||
plain_text(""),
|
plain_text(""),
|
||||||
)
|
)
|
||||||
|
|
||||||
}
|
}
|
||||||
other => {
|
other => {
|
||||||
// NamedFnArg(String /* function name */, u8 /* arg index */),
|
// NamedFnArg(String /* function name */, u8 /* arg index */),
|
||||||
|
@ -398,6 +522,17 @@ fn to_expr_report(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn count_arguments(tipe: &ErrorType) -> usize {
|
||||||
|
use ErrorType::*;
|
||||||
|
|
||||||
|
match tipe {
|
||||||
|
Function(args, _) => args.len(),
|
||||||
|
Type(Symbol::ATTR_ATTR, args) => count_arguments(&args[1]),
|
||||||
|
Alias(_, _, actual) => count_arguments(actual),
|
||||||
|
_ => 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn type_comparison(
|
fn type_comparison(
|
||||||
actual: ErrorType,
|
actual: ErrorType,
|
||||||
expected: ErrorType,
|
expected: ErrorType,
|
||||||
|
|
|
@ -1357,4 +1357,73 @@ mod test_reporting {
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn fncall_value() {
|
||||||
|
report_problem_as(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
x : Int
|
||||||
|
x = 42
|
||||||
|
|
||||||
|
x 3
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
The `x` value is not a function, but it was given 1 argument:
|
||||||
|
|
||||||
|
4 ┆ x 3
|
||||||
|
┆ ^
|
||||||
|
|
||||||
|
Are there any missing commas? Or missing parentheses?"#
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn fncall_overapplied() {
|
||||||
|
report_problem_as(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
f : Int -> Int
|
||||||
|
f = \_ -> 42
|
||||||
|
|
||||||
|
f 1 2
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
The `f` function expects 1 argument, but it got 2 instead:
|
||||||
|
|
||||||
|
4 ┆ f 1 2
|
||||||
|
┆ ^
|
||||||
|
|
||||||
|
Are there any missing commas? Or missing parentheses?"#
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn fncall_underapplied() {
|
||||||
|
report_problem_as(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
f : Int, Int -> Int
|
||||||
|
f = \_, _ -> 42
|
||||||
|
|
||||||
|
f 1
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
The `f` function expects 2 arguments, but it got only 1:
|
||||||
|
|
||||||
|
4 ┆ f 1
|
||||||
|
┆ ^
|
||||||
|
|
||||||
|
Roc does not allow functions to be partially applied. Use a closure to make partial application explicit."#
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue