From ce0c6e0d0ff7449d4eb4cee62f4b52ddf1b54108 Mon Sep 17 00:00:00 2001 From: KtorZ Date: Fri, 23 Dec 2022 00:24:57 +0100 Subject: [PATCH] Use smart-constructor for UnexpectedLabeledArg errors. Reduce duplications and keep the formatting of the error inside the error module. --- crates/aiken-lang/src/tipo/environment.rs | 53 ++--------------------- crates/aiken-lang/src/tipo/error.rs | 48 +++++++++++++++++++- crates/aiken-lang/src/tipo/expr.rs | 10 ++++- crates/aiken-lang/src/tipo/pattern.rs | 22 ++++++---- 4 files changed, 72 insertions(+), 61 deletions(-) diff --git a/crates/aiken-lang/src/tipo/environment.rs b/crates/aiken-lang/src/tipo/environment.rs index 95766f8b..1477bf4d 100644 --- a/crates/aiken-lang/src/tipo/environment.rs +++ b/crates/aiken-lang/src/tipo/environment.rs @@ -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], - module: &'a Option, - with_spread: bool, -) -> Result<(), Error> { +pub(super) fn assert_no_labeled_arguments(args: &[CallArg]) -> 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::>(); - - 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(args: &[CallArg]) -> 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) -> Arc { diff --git a/crates/aiken-lang/src/tipo/error.rs b/crates/aiken-lang/src/tipo/error.rs index 2ed3e122..13429383 100644 --- a/crates/aiken-lang/src/tipo/error.rs +++ b/crates/aiken-lang/src/tipo/error.rs @@ -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], + module: &Option, + with_spread: bool, + ) -> Self { + let fixed_args = args + .iter() + .map(|arg| CallArg { + label: None, + location: arg.location, + value: arg.value.clone(), + }) + .collect::>(); + + 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)] diff --git a/crates/aiken-lang/src/tipo/expr.rs b/crates/aiken-lang/src/tipo/expr.rs index 24b18eb8..63088090 100644 --- a/crates/aiken-lang/src/tipo/expr.rs +++ b/crates/aiken-lang/src/tipo/expr.rs @@ -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( diff --git a/crates/aiken-lang/src/tipo/pattern.rs b/crates/aiken-lang/src/tipo/pattern.rs index f778be63..87b04aef 100644 --- a/crates/aiken-lang/src/tipo/pattern.rs +++ b/crates/aiken-lang/src/tipo/pattern.rs @@ -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( - &name, - &pattern_args, - &module, - with_spread, - )?, + 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();