Hide params from annotation type mismatches

This commit is contained in:
Agus Zubiaga 2024-08-27 19:06:31 -03:00
parent a4f4d00ff0
commit d033057a58
No known key found for this signature in database
5 changed files with 117 additions and 11 deletions

View file

@ -846,6 +846,57 @@ mod cli_run {
) )
} }
#[test]
#[cfg_attr(windows, ignore)]
fn module_params_bad_ann() {
check_compile_error_with(
CMD_DEV,
&cli_testing_dir("/module_params/bad_ann.roc"),
&[],
indoc!(
r#"
TYPE MISMATCH in tests/module_params/BadAnn.roc
Something is off with the body of the fnAnnotatedAsValue definition:
3 fnAnnotatedAsValue : Str
4> fnAnnotatedAsValue = /postId, commentId ->
5> "/posts/$(postId)/comments/$(Num.toStr commentId)"
The body is an anonymous function of type:
Str, Num * -> Str
But the type annotation on fnAnnotatedAsValue says it should be:
Str
TYPE MISMATCH in tests/module_params/BadAnn.roc
Something is off with the body of the missingArg definition:
7 missingArg : Str -> Str
8> missingArg = /postId, _ ->
9> "/posts/$(postId)/comments"
The body is an anonymous function of type:
(Str, ? -> Str)
But the type annotation on missingArg says it should be:
(Str -> Str)
Tip: It looks like it takes too many arguments. I'm seeing 1 extra.
2 errors and 1 warning found in <ignored for test> ms."#
),
);
}
#[test] #[test]
#[cfg_attr(windows, ignore)] #[cfg_attr(windows, ignore)]
fn transitive_expects() { fn transitive_expects() {

View file

@ -0,0 +1,9 @@
module { appId } -> [fnAnnotatedAsValue, missingArg]
fnAnnotatedAsValue : Str
fnAnnotatedAsValue = \postId, commentId ->
"/posts/$(postId)/comments/$(Num.toStr commentId)"
missingArg : Str -> Str
missingArg = \postId, _ ->
"/posts/$(postId)/comments"

View file

@ -0,0 +1,8 @@
app [main] {
pf: platform "../fixtures/multi-dep-str/platform/main.roc",
}
import BadAnn { appId: "one" }
main =
""

View file

@ -1,4 +1,4 @@
use roc_can::expected::Expected; use roc_can::{expected::Expected, pattern::Pattern};
use roc_module::symbol::{ModuleId, Symbol}; use roc_module::symbol::{ModuleId, Symbol};
use roc_region::all::Loc; use roc_region::all::Loc;
use roc_solve_problem::TypeError; use roc_solve_problem::TypeError;
@ -32,9 +32,47 @@ pub fn remove_module_param_arguments(
for error in errors { for error in errors {
match error { match error {
TypeError::BadExpr(_, _, found, Expected::ForReason(reason, expected, _)) => { TypeError::BadExpr(_, _, found, Expected::ForReason(reason, expected, _)) => {
remove_with_bad_expr_reason(&env, found, reason, expected); remove_for_reason(&env, found, reason, expected);
} }
TypeError::BadExpr(_, _, _, _) => todo!("{:?}", error),
TypeError::BadExpr(
_,
_,
found,
Expected::FromAnnotation(
Loc {
value: Pattern::Identifier(name),
region: _,
},
arity,
_,
expected,
),
) if env.is_extended(name) => {
if *arity > 1 {
*arity -= 1;
}
drop_last_argument(found);
drop_last_argument(expected);
if let (
ErrorType::Function(found_args, _, _),
ErrorType::Function(expected_args, _, _),
) = (found, expected)
{
if found_args.len() > expected_args.len() {
// If the found arity doesn't match the annotation's, the params
// record would appear in the error, so we replace it with `?`.
if let Some(last) = found_args.last_mut() {
*last = ErrorType::Error;
}
}
}
}
TypeError::BadExpr(_, _, _, Expected::FromAnnotation(_, _, _, _))
| TypeError::BadExpr(_, _, _, Expected::NoExpectation(_)) => {}
// Irrelevant // Irrelevant
TypeError::BadPattern(_, _, _, _) TypeError::BadPattern(_, _, _, _)
@ -80,7 +118,7 @@ impl Env {
} }
} }
fn remove_with_bad_expr_reason( fn remove_for_reason(
env: &Env, env: &Env,
found_type: &mut ErrorType, found_type: &mut ErrorType,
reason: &mut Reason, reason: &mut Reason,

View file

@ -3594,7 +3594,7 @@ pub enum Mismatch {
pub type DoesNotImplementAbility = Vec<(ErrorType, Symbol)>; pub type DoesNotImplementAbility = Vec<(ErrorType, Symbol)>;
#[derive(PartialEq, Eq, Clone, Hash)] #[derive(PartialEq, Eq, Clone, Hash, Debug)]
pub enum ErrorType { pub enum ErrorType {
Infinite, Infinite,
Type(Symbol, Vec<ErrorType>), Type(Symbol, Vec<ErrorType>),
@ -3619,12 +3619,12 @@ pub enum ErrorType {
Error, Error,
} }
impl std::fmt::Debug for ErrorType { // impl std::fmt::Debug for ErrorType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { // fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
// TODO remove clone // // TODO remove clone
write!(f, "{:?}", write_debug_error_type(self.clone())) // write!(f, "{:?}", write_debug_error_type(self.clone()))
} // }
} // }
impl ErrorType { impl ErrorType {
pub fn unwrap_structural_alias(self) -> ErrorType { pub fn unwrap_structural_alias(self) -> ErrorType {