Use smart-constructor for UnexpectedLabeledArg errors.
Reduce duplications and keep the formatting of the error inside the error module.
This commit is contained in:
parent
dca633da48
commit
ce0c6e0d0f
|
@ -10,10 +10,9 @@ use crate::{
|
|||
ast::{
|
||||
Annotation, CallArg, DataType, Definition, Function, ModuleConstant, Pattern,
|
||||
RecordConstructor, RecordConstructorArg, Span, TypeAlias, TypedDefinition,
|
||||
UnqualifiedImport, UntypedDefinition, UntypedPattern, Use, PIPE_VARIABLE,
|
||||
UnqualifiedImport, UntypedDefinition, Use, PIPE_VARIABLE,
|
||||
},
|
||||
builtins::{self, function, generic_var, tuple, unbound_var},
|
||||
format::Formatter,
|
||||
tipo::fields::FieldMap,
|
||||
IdGenerator,
|
||||
};
|
||||
|
@ -1584,57 +1583,13 @@ fn assert_unique_const_name<'a>(
|
|||
}
|
||||
}
|
||||
|
||||
pub(super) fn assert_no_labeled_arguments_in_pattern<'a>(
|
||||
name: &str,
|
||||
args: &[CallArg<UntypedPattern>],
|
||||
module: &'a Option<String>,
|
||||
with_spread: bool,
|
||||
) -> Result<(), Error> {
|
||||
pub(super) fn assert_no_labeled_arguments<A>(args: &[CallArg<A>]) -> Option<(Span, String)> {
|
||||
for arg in args {
|
||||
if let Some(label) = &arg.label {
|
||||
let fixed_args = args
|
||||
.iter()
|
||||
.map(|arg| CallArg {
|
||||
label: None,
|
||||
location: arg.location,
|
||||
value: arg.value.clone(),
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let suggestion = Formatter::new()
|
||||
.pattern_constructor(name, &fixed_args, module, with_spread, false)
|
||||
.to_pretty_string(70);
|
||||
|
||||
let hint = format!(
|
||||
r#"The constructor '{name}' does not have any labeled field. Its fields
|
||||
must therefore be matched only by position.
|
||||
|
||||
Perhaps, try the following:
|
||||
|
||||
╰─▶ {suggestion}"#
|
||||
);
|
||||
|
||||
return Err(Error::UnexpectedLabeledArg {
|
||||
location: arg.location,
|
||||
label: label.to_string(),
|
||||
hint: Some(hint),
|
||||
});
|
||||
return Some((arg.location, label.to_string()));
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(super) fn assert_no_labeled_arguments<A>(args: &[CallArg<A>]) -> Result<(), Error> {
|
||||
for arg in args {
|
||||
if let Some(label) = &arg.label {
|
||||
return Err(Error::UnexpectedLabeledArg {
|
||||
location: arg.location,
|
||||
label: label.to_string(),
|
||||
hint: None,
|
||||
});
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
None
|
||||
}
|
||||
|
||||
pub(super) fn collapse_links(t: Arc<Type>) -> Arc<Type> {
|
||||
|
|
|
@ -5,7 +5,8 @@ use ordinal::Ordinal;
|
|||
use miette::Diagnostic;
|
||||
|
||||
use crate::{
|
||||
ast::{BinOp, Span, TodoKind},
|
||||
ast::{BinOp, CallArg, Span, TodoKind, UntypedPattern},
|
||||
format::Formatter,
|
||||
levenshtein,
|
||||
};
|
||||
|
||||
|
@ -489,6 +490,51 @@ with the module's name.
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn unexpected_labeled_arg<'a>(location: Span, label: String) -> Self {
|
||||
Self::UnexpectedLabeledArg {
|
||||
location,
|
||||
label,
|
||||
hint: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn unexpected_labeled_arg_in_pattern(
|
||||
location: Span,
|
||||
label: String,
|
||||
name: &str,
|
||||
args: &[CallArg<UntypedPattern>],
|
||||
module: &Option<String>,
|
||||
with_spread: bool,
|
||||
) -> Self {
|
||||
let fixed_args = args
|
||||
.iter()
|
||||
.map(|arg| CallArg {
|
||||
label: None,
|
||||
location: arg.location,
|
||||
value: arg.value.clone(),
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let suggestion = Formatter::new()
|
||||
.pattern_constructor(name, &fixed_args, module, with_spread, false)
|
||||
.to_pretty_string(70);
|
||||
|
||||
let hint = format!(
|
||||
r#"The constructor '{name}' does not have any labeled field. Its fields
|
||||
must therefore be matched only by position.
|
||||
|
||||
Perhaps, try the following:
|
||||
|
||||
╰─▶ {suggestion}"#
|
||||
);
|
||||
|
||||
Self::UnexpectedLabeledArg {
|
||||
location,
|
||||
label: label.to_string(),
|
||||
hint: Some(hint),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone, thiserror::Error, Diagnostic)]
|
||||
|
|
|
@ -111,7 +111,9 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
|||
Some(field_map) => field_map.reorder(&mut args, location)?,
|
||||
|
||||
// The fun has no field map and so we error if arguments have been labelled
|
||||
None => assert_no_labeled_arguments(&args)?,
|
||||
None => assert_no_labeled_arguments(&args)
|
||||
.map(|(location, label)| Err(Error::unexpected_labeled_arg(location, label)))
|
||||
.unwrap_or(Ok(()))?,
|
||||
}
|
||||
|
||||
// Extract the type of the fun, ensuring it actually is a function
|
||||
|
@ -1350,7 +1352,11 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
|||
Some(field_map) => field_map.reorder(&mut args, location)?,
|
||||
|
||||
// The fun has no field map and so we error if arguments have been labelled
|
||||
None => assert_no_labeled_arguments(&args)?,
|
||||
None => assert_no_labeled_arguments(&args)
|
||||
.map(|(location, label)| {
|
||||
Err(Error::unexpected_labeled_arg(location, label))
|
||||
})
|
||||
.unwrap_or(Ok(()))?,
|
||||
}
|
||||
|
||||
let (mut args_types, return_type) = self.environment.match_fun_type(
|
||||
|
|
|
@ -9,9 +9,7 @@ use std::{
|
|||
use itertools::Itertools;
|
||||
|
||||
use super::{
|
||||
environment::{
|
||||
assert_no_labeled_arguments_in_pattern, collapse_links, EntityKind, Environment,
|
||||
},
|
||||
environment::{assert_no_labeled_arguments, collapse_links, EntityKind, Environment},
|
||||
error::Error,
|
||||
hydrator::Hydrator,
|
||||
PatternConstructor, Type, ValueConstructor, ValueConstructorVariant,
|
||||
|
@ -487,12 +485,18 @@ impl<'a, 'b> PatternTyper<'a, 'b> {
|
|||
}
|
||||
|
||||
// The fun has no field map and so we error if arguments have been labelled
|
||||
None => assert_no_labeled_arguments_in_pattern(
|
||||
None => assert_no_labeled_arguments(&pattern_args)
|
||||
.map(|(location, label)| {
|
||||
Err(Error::unexpected_labeled_arg_in_pattern(
|
||||
location,
|
||||
label,
|
||||
&name,
|
||||
&pattern_args,
|
||||
&module,
|
||||
with_spread,
|
||||
)?,
|
||||
))
|
||||
})
|
||||
.unwrap_or(Ok(()))?,
|
||||
}
|
||||
|
||||
let constructor_typ = cons.tipo.clone();
|
||||
|
|
Loading…
Reference in New Issue