From 308ab1c9f7526242c1fda3ec2ec25cadcfbcd700 Mon Sep 17 00:00:00 2001 From: Shunsuke Shibayama Date: Mon, 14 Nov 2022 11:13:30 +0900 Subject: [PATCH 01/23] Remove Location::RangePair --- compiler/erg_common/error.rs | 105 ++------------------------------- compiler/erg_common/traits.rs | 14 +---- compiler/erg_compiler/error.rs | 18 ------ 3 files changed, 8 insertions(+), 129 deletions(-) diff --git a/compiler/erg_common/error.rs b/compiler/erg_common/error.rs index 5ba416bc..5fefd9a4 100644 --- a/compiler/erg_common/error.rs +++ b/compiler/erg_common/error.rs @@ -229,37 +229,6 @@ impl From<&str> for ErrorKind { /// #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)] pub enum Location { - /// - /// Error used when the error is caused by a discrepancy with a code on another line - /// - /// # Example - /// - /// Ownership error - /// - /// ```erg - /// a: Nat = 1 - /// a.consume_ownership() // move occurs - /// - /// function(a) // borrowed after moved - /// ``` - /// - /// `a` moves ownership in a method(or function) that are defined and consume it. - /// - /// ```erg - /// Location::RangePair { - /// ln_first: (2, 2), - /// col_first: (0, 1), - /// ln_second: (4, 4), - /// col_second: (9, 10), - /// } - /// ``` - /// - RangePair { - ln_first: (usize, usize), - col_first: (usize, usize), - ln_second: (usize, usize), - col_second: (usize, usize), - }, /// /// Location used for basic errors /// ```erg @@ -311,59 +280,34 @@ impl Location { } } - pub fn pair(lhs: Self, rhs: Self) -> Self { - Self::RangePair { - ln_first: (lhs.ln_begin().unwrap(), lhs.ln_end().unwrap()), - col_first: (lhs.col_begin().unwrap(), lhs.col_end().unwrap()), - ln_second: (rhs.ln_begin().unwrap(), rhs.ln_end().unwrap()), - col_second: (rhs.col_begin().unwrap(), rhs.col_end().unwrap()), - } - } - pub const fn ln_begin(&self) -> Option { match self { - Self::RangePair { - ln_first: (ln_begin, _), - .. + Self::Range { ln_begin, .. } | Self::LineRange(ln_begin, _) | Self::Line(ln_begin) => { + Some(*ln_begin) } - | Self::Range { ln_begin, .. } - | Self::LineRange(ln_begin, _) - | Self::Line(ln_begin) => Some(*ln_begin), Self::Unknown => None, } } pub const fn ln_end(&self) -> Option { match self { - Self::RangePair { - ln_second: (_, ln_end), - .. + Self::Range { ln_end, .. } | Self::LineRange(ln_end, _) | Self::Line(ln_end) => { + Some(*ln_end) } - | Self::Range { ln_end, .. } - | Self::LineRange(ln_end, _) - | Self::Line(ln_end) => Some(*ln_end), Self::Unknown => None, } } pub const fn col_begin(&self) -> Option { match self { - Self::RangePair { - col_first: (col_begin, _), - .. - } - | Self::Range { col_begin, .. } => Some(*col_begin), + Self::Range { col_begin, .. } => Some(*col_begin), _ => None, } } pub const fn col_end(&self) -> Option { match self { - Self::RangePair { - col_second: (_, col_end), - .. - } - | Self::Range { col_end, .. } => Some(*col_end), + Self::Range { col_end, .. } => Some(*col_end), _ => None, } } @@ -659,11 +603,6 @@ pub trait ErrorDisplay { ln_begin, ln_end, .. } | Location::LineRange(ln_begin, ln_end) => format!(", line {ln_begin}..{ln_end}"), - Location::RangePair { - ln_first: (l1, l2), - ln_second: (l3, l4), - .. - } => format!(", line {l1}..{l2}, {l3}..{l4}"), Location::Line(lineno) => format!(", line {lineno}"), Location::Unknown => "".to_string(), }; @@ -686,38 +625,6 @@ pub trait ErrorDisplay { chars: &Characters, ) -> String { match self.core().loc { - // TODO: Current implementation does not allow for multiple descriptions of errors to be given at each location - // In the future, this will be implemented in a different structure that can handle multiple lines and files - Location::RangePair { - ln_first, - col_first, - ln_second, - col_second, - } => { - format_context( - self, - ln_first.0, - ln_first.1, - col_first.0, - col_first.1, - err_color, - gutter_color, - chars, - mark, - ) + - "\n" // TODO: dealing with error chains - + &format_context( - self, - ln_second.0, - ln_second.1, - col_second.0, - col_second.1, - err_color, - gutter_color, - chars, - mark, - ) - } Location::Range { ln_begin, col_begin, diff --git a/compiler/erg_common/traits.rs b/compiler/erg_common/traits.rs index f7ccee7e..6225bfc7 100644 --- a/compiler/erg_common/traits.rs +++ b/compiler/erg_common/traits.rs @@ -477,12 +477,7 @@ pub trait Locational { fn ln_begin(&self) -> Option { match self.loc() { - Location::RangePair { - ln_first: (ln_begin, _), - .. - } - | Location::Range { ln_begin, .. } - | Location::LineRange(ln_begin, _) => Some(ln_begin), + Location::Range { ln_begin, .. } | Location::LineRange(ln_begin, _) => Some(ln_begin), Location::Line(lineno) => Some(lineno), Location::Unknown => None, } @@ -490,12 +485,7 @@ pub trait Locational { fn ln_end(&self) -> Option { match self.loc() { - Location::RangePair { - ln_second: (_, ln_end), - .. - } - | Location::Range { ln_end, .. } - | Location::LineRange(_, ln_end) => Some(ln_end), + Location::Range { ln_end, .. } | Location::LineRange(_, ln_end) => Some(ln_end), Location::Line(lineno) => Some(lineno), Location::Unknown => None, } diff --git a/compiler/erg_compiler/error.rs b/compiler/erg_compiler/error.rs index d287a8f3..6d0299c6 100644 --- a/compiler/erg_compiler/error.rs +++ b/compiler/erg_compiler/error.rs @@ -1862,24 +1862,6 @@ if True: ); print!("{}", err); - let loc = Location::RangePair { - ln_first: (1, 2), - col_first: (0, 1), - ln_second: (4, 4), - col_second: (9, 10), - }; - let input = Input::Pipe( - "\ -a: Nat = 1 -a.ownership_is_moved() - -function(a) -" - .to_string(), - ); - let err = TyCheckError::checker_bug(input, 0, loc, "file_name", 0); - print!("{}", err); - let loc = Location::Range { ln_begin: 1, col_begin: 0, From 823773def1b1065e65fb53c73403cebc8f99f871 Mon Sep 17 00:00:00 2001 From: GreasySlug <9619abgoni@gmail.com> Date: Thu, 17 Nov 2022 23:22:49 +0900 Subject: [PATCH 02/23] Change: add `main_msg` and `SubMessage` --- compiler/erg_common/error.rs | 471 +++++++++++++++++------------------ 1 file changed, 223 insertions(+), 248 deletions(-) diff --git a/compiler/erg_common/error.rs b/compiler/erg_common/error.rs index c0cdf1e1..ee0aa033 100644 --- a/compiler/erg_common/error.rs +++ b/compiler/erg_common/error.rs @@ -14,6 +14,7 @@ use crate::style::StyledStr; use crate::style::StyledString; use crate::style::StyledStrings; use crate::style::Theme; +use crate::style::THEME; use crate::traits::{Locational, Stream}; use crate::{impl_display_from_debug, switch_lang}; @@ -313,70 +314,6 @@ impl Location { } } -/// In Erg, common parts used by error. -/// Must be wrap when to use. -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct ErrorCore { - pub errno: usize, - pub kind: ErrorKind, - pub loc: Location, - pub desc: AtomicStr, - pub hint: Option, -} - -impl ErrorCore { - pub fn new>( - errno: usize, - kind: ErrorKind, - loc: Location, - desc: S, - hint: Option, - ) -> Self { - Self { - errno, - kind, - loc, - desc: desc.into(), - hint, - } - } - - pub fn dummy(errno: usize) -> Self { - Self::new( - errno, - DummyError, - Location::Line(errno as usize), - "", - None, - ) - } - - pub fn unreachable(fn_name: &str, line: u32) -> Self { - Self::bug(line as usize, Location::Line(line as usize), fn_name, line) - } - - pub fn bug(errno: usize, loc: Location, fn_name: &str, line: u32) -> Self { - const URL: StyledStr = StyledStr::new( - "https://github.com/erg-lang/erg", - Some(Color::White), - Some(Attribute::Underline), - ); - - Self::new( - errno, - CompilerSystemError, - loc, - switch_lang!( - "japanese" => format!("これはErgのバグです、開発者に報告して下さい({URL})\n{fn_name}:{line}より発生"), - "simplified_chinese" => format!("这是Erg的bug,请报告给{URL}\n原因来自: {fn_name}:{line}"), - "traditional_chinese" => format!("这是Erg的bug,请报告给{URL}\n原因来自: {fn_name}:{line}"), - "english" => format!("this is a bug of Erg, please report it to {URL}\ncaused from: {fn_name}:{line}"), - ), - None, - ) - } -} - #[allow(clippy::too_many_arguments)] fn format_context( e: &E, @@ -390,6 +327,8 @@ fn format_context( chars: &Characters, // kinds of error for specify the color mark: char, + sub_msg: Option<&AtomicStr>, + hint: Option<&AtomicStr>, ) -> String { let mark = mark.to_string(); let codes = if e.input().is_repl() { @@ -429,12 +368,201 @@ fn format_context( } context.push_str("\n"); } - context.push_str_with_color(&offset, gutter_color); - context.push_str(&" ".repeat(col_end - 1)); - context.push_str_with_color(&chars.left_bottom_line(), err_color); + if let Some(msg) = sub_msg { + context.push_str_with_color(&offset, gutter_color); + context.push_str(&" ".repeat(col_end - 1)); + context.push_str_with_color(&chars.left_bottom_line(), err_color); + context.push_str(msg); + } + if let Some(hint) = hint { + context.push_str_with_color(&offset, gutter_color); + context.push_str(&" ".repeat(col_end - 1)); + context.push_str_with_color(&chars.left_bottom_line(), err_color); + context.push_str(hint); + } context.to_string() } +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct SubMessage { + pub loc: Location, + msg: Option, + hint: Option, +} + +impl SubMessage { + pub fn new>(loc: Location, msg: S, hint: S) -> Self { + Self { + loc, + msg: Some(msg.into()), + hint: Some(hint.into()), + } + } + + pub fn ambiguous_new(loc: Location, msg: Option, hint: Option) -> Self { + Self { loc, msg, hint } + } + + pub fn only_loc(loc: Location) -> Self { + Self { + loc, + msg: None, + hint: None, + } + } + + pub fn set_hint>(&mut self, hint: S) { + self.hint = Some(hint.into()); + } + + pub fn get_hint(self) -> Option { + self.hint + } + + fn format_code_and_pointer( + &self, + e: &E, + err_color: Color, + gutter_color: Color, + mark: char, + chars: &Characters, + ) -> String { + match self.loc { + Location::Range { + ln_begin, + col_begin, + ln_end, + col_end, + } => format_context( + e, + ln_begin, + ln_end, + col_begin, + col_end, + err_color, + gutter_color, + chars, + mark, + self.msg.as_ref(), + self.hint.as_ref(), + ), + Location::LineRange(ln_begin, ln_end) => { + let input = e.input(); + let (_, vbar) = chars.gutters(); + let mut cxt = StyledStrings::default(); + let codes = if input.is_repl() { + vec![input.reread()] + } else { + input.reread_lines(ln_begin, ln_end) + }; + let mark = mark.to_string(); + for (i, lineno) in (ln_begin..=ln_end).enumerate() { + cxt.push_str_with_color(&format!("{lineno} {}", vbar), err_color); + cxt.push_str(&codes[i]); + cxt.push_str(&" ".repeat(lineno.to_string().len() + 3)); // +3 means ` | ` + cxt.push_str_with_color(&mark.repeat(cmp::max(1, codes[i].len())), gutter_color) + } + cxt.to_string() + } + Location::Line(lineno) => { + let input = e.input(); + let (_, vbar) = chars.gutters(); + let code = if input.is_repl() { + input.reread() + } else { + input.reread_lines(lineno, lineno).remove(0) + }; + let mut cxt = StyledStrings::default(); + cxt.push_str_with_color(&format!(" {lineno} {} ", vbar), gutter_color); + cxt.push_str(&code); + cxt.push_str("\n"); + cxt.to_string() + } + Location::Unknown => match e.input() { + Input::File(_) => "\n".to_string(), + + other => { + let (_, vbar) = chars.gutters(); + let mut cxt = StyledStrings::default(); + cxt.push_str_with_color(&format!(" ? {}", vbar), gutter_color); + cxt.push_str(&other.reread()); + cxt.to_string() + } + }, + } + } +} + +/// In Erg, common parts used by error. +/// Must be wrap when to use. +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct ErrorCore { + pub sub_messages: Vec, + pub main_message: AtomicStr, + pub errno: usize, + pub kind: ErrorKind, + theme: Theme, +} + +impl ErrorCore { + pub fn new>( + sub_messages: Vec, + main_message: S, + errno: usize, + kind: ErrorKind, + ) -> Self { + Self { + sub_messages, + main_message: main_message.into(), + errno, + kind, + theme: THEME, + } + } + + pub fn sub_messages(&self) -> &Vec { + &self.sub_messages + } + + pub fn dummy(errno: usize) -> Self { + Self::new( + vec![SubMessage::only_loc(Location::Line(errno as usize))], + "", + errno, + DummyError, + ) + } + + pub fn unreachable(fn_name: &str, line: u32) -> Self { + Self::bug(line as usize, Location::Line(line as usize), fn_name, line) + } + + pub fn bug(errno: usize, loc: Location, fn_name: &str, line: u32) -> Self { + const URL: StyledStr = StyledStr::new( + "https://github.com/erg-lang/erg", + Some(Color::White), + Some(Attribute::Underline), + ); + + let m_msg = switch_lang!( + "japanese" => format!("これはErgのバグです、開発者に報告して下さい({URL})\n{fn_name}:{line}より発生"), + "simplified_chinese" => format!("这是Erg的bug,请报告给{URL}\n原因来自: {fn_name}:{line}"), + "traditional_chinese" => format!("这是Erg的bug,请报告给{URL}\n原因来自: {fn_name}:{line}"), + "english" => format!("this is a bug of Erg, please report it to {URL}\ncaused from: {fn_name}:{line}"), + ); + Self::new( + vec![SubMessage::only_loc(loc)], + &m_msg, + errno, + CompilerSystemError, + ) + } + + pub fn fmt_main_message(&self, kind: StyledString) -> String { + format!("{}\n{}\n\n", kind, self.main_message) + } +} + /// format: /// ```txt /// Error[#{.errno}]: File {file}, line {.loc (as line)}, in {.caused_by} @@ -460,11 +588,8 @@ fn format_context( pub trait ErrorDisplay { fn core(&self) -> &ErrorCore; fn input(&self) -> &Input; - /// Colors and indication char for each type(error, warning, exception) - fn theme(&self) -> &Theme; /// The block name the error caused. /// This will be None if the error occurred before semantic analysis. - /// As for the internal error, do not put the fn name here. fn caused_by(&self) -> &str; /// the previous error that caused this error. fn ref_inner(&self) -> Option<&Self>; @@ -484,107 +609,53 @@ pub trait ErrorDisplay { } fn show(&self) -> String { - let theme = self.theme(); - let ((color, mark), kind) = if self.core().kind.is_error() { - (theme.error(), "Error") - } else if self.core().kind.is_warning() { - (theme.warning(), "Warning") + let core = self.core(); + let ((color, mark), kind) = if core.kind.is_error() { + (core.theme.error(), "Error") + } else if core.kind.is_warning() { + (core.theme.warning(), "Warning") } else { - (theme.exception(), "Exception") + (core.theme.exception(), "Exception") }; - - let (gutter_color, chars) = theme.characters(); + let (gutter_color, chars) = core.theme.characters(); let kind = StyledString::new( - &chars.error_kind_format(kind, self.core().errno), + &chars.error_kind_format(kind, core.errno), Some(color), Some(Attribute::Bold), ); - - // When hint is None, hint desc is "" and empty line is displayed, but hint is Some(...), hint desc is "..." and filled by text - if let Some(hint) = self.core().hint.as_ref() { - let (hint_color, _) = theme.hint(); - let mut hints = StyledStrings::default(); - hints.push_str_with_color_and_attribute("hint: ", hint_color, Attribute::Bold); - hints.push_str(hint); - format!( - "\ -{} -{}{}: {} - -{} - -", - self.format_header(kind), - self.format_code_and_pointer(color, gutter_color, mark, chars), - self.core().kind, - self.core().desc, - hints, - ) - } else { - format!( - "\ -{} -{}{}: {} - -", - self.format_header(kind), - self.format_code_and_pointer(color, gutter_color, mark, chars), - self.core().kind, - self.core().desc, - ) + let sub_messages = self.core().sub_messages(); + let mut msg = String::new(); + msg += &core.fmt_main_message(kind); + for sub_msg in sub_messages { + msg += &sub_msg.format_code_and_pointer(self, color, gutter_color, mark, chars) } + msg += "\n"; + msg } /// for fmt::Display fn format(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let theme = self.theme(); - let ((color, mark), kind) = if self.core().kind.is_error() { - (theme.error(), "Error") - } else if self.core().kind.is_warning() { - (theme.warning(), "Warning") + let core = self.core(); + let ((color, mark), kind) = if core.kind.is_error() { + (core.theme.error(), "Error") + } else if core.kind.is_warning() { + (core.theme.warning(), "Warning") } else { - (theme.exception(), "Exception") + (core.theme.exception(), "Exception") }; - let (gutter_color, chars) = theme.characters(); + let (gutter_color, chars) = core.theme.characters(); let kind = StyledString::new( - &chars.error_kind_format(kind, self.core().errno), + &chars.error_kind_format(kind, core.errno), Some(color), Some(Attribute::Bold), ); - - // When hint is None, hint desc is "" and empty line is displayed, but hint is Some(...), hint desc is "..." and filled by text - if let Some(hint) = self.core().hint.as_ref() { - let (hint_color, _) = theme.hint(); - let mut hints = StyledStrings::default(); - hints.push_str_with_color_and_attribute("hint: ", hint_color, Attribute::Bold); - hints.push_str(hint); + writeln!(f, "{}", core.fmt_main_message(kind))?; + let sub_messages = self.core().sub_messages(); + for sub_msg in sub_messages { writeln!( f, - "\ -{} -{}{}: {} - -{} - -", - self.format_header(kind), - self.format_code_and_pointer(color, gutter_color, mark, chars), - self.core().kind, - self.core().desc, - hints, - )?; - } else { - writeln!( - f, - "\ -{} -{}{}: {} - -", - self.format_header(kind), - self.format_code_and_pointer(color, gutter_color, mark, chars), - self.core().kind, - self.core().desc, + "{}", + &sub_msg.format_code_and_pointer(self, color, gutter_color, mark, chars) )?; } if let Some(inner) = self.ref_inner() { @@ -593,102 +664,6 @@ pub trait ErrorDisplay { Ok(()) } } - - fn format_header(&self, kind: StyledString) -> String { - let loc = match self.core().loc { - Location::Range { - ln_begin, ln_end, .. - } if ln_begin == ln_end => format!(", line {ln_begin}"), - Location::Range { - ln_begin, ln_end, .. - } - | Location::LineRange(ln_begin, ln_end) => format!(", line {ln_begin}..{ln_end}"), - Location::Line(lineno) => format!(", line {lineno}"), - Location::Unknown => "".to_string(), - }; - let caused_by = if self.caused_by() != "" { - format!(", in {}", self.caused_by()) - } else { - "".to_string() - }; - format!( - "{kind}: File {input}{loc}{caused_by}\n", - input = self.input().enclosed_name(), - ) - } - - fn format_code_and_pointer( - &self, - err_color: Color, - gutter_color: Color, - mark: char, - chars: &Characters, - ) -> String { - match self.core().loc { - Location::Range { - ln_begin, - col_begin, - ln_end, - col_end, - } => format_context( - self, - ln_begin, - ln_end, - col_begin, - col_end, - err_color, - gutter_color, - chars, - mark, - ), - Location::LineRange(ln_begin, ln_end) => { - let (_, vbar) = chars.gutters(); - let mut cxt = StyledStrings::default(); - let codes = if self.input().is_repl() { - vec![self.input().reread()] - } else { - self.input().reread_lines(ln_begin, ln_end) - }; - let mark = mark.to_string(); - for (i, lineno) in (ln_begin..=ln_end).enumerate() { - cxt.push_str_with_color(&format!("{lineno} {}", vbar), err_color); - cxt.push_str(&codes[i]); - cxt.push_str("\n"); - cxt.push_str(&" ".repeat(lineno.to_string().len() + 3)); // +3 means ` | ` - cxt.push_str_with_color( - &mark.repeat(cmp::max(1, codes[i].len())), - gutter_color, - ); - cxt.push_str("\n"); - } - cxt.to_string() - } - Location::Line(lineno) => { - let (_, vbar) = chars.gutters(); - let code = if self.input().is_repl() { - self.input().reread() - } else { - self.input().reread_lines(lineno, lineno).remove(0) - }; - let mut cxt = StyledStrings::default(); - cxt.push_str_with_color(&format!(" {lineno} {} ", vbar), gutter_color); - cxt.push_str(&code); - cxt.push_str("\n"); - cxt.to_string() - } - Location::Unknown => match self.input() { - Input::File(_) => "\n".to_string(), - - other => { - let (_, vbar) = chars.gutters(); - let mut cxt = StyledStrings::default(); - cxt.push_str_with_color(&format!(" ? {}", vbar), gutter_color); - cxt.push_str(&other.reread()); - cxt.to_string() - } - }, - } - } } #[macro_export] From bba66f7696300a2c79601b889c9bde7158710e4a Mon Sep 17 00:00:00 2001 From: GreasySlug <9619abgoni@gmail.com> Date: Thu, 17 Nov 2022 23:25:47 +0900 Subject: [PATCH 03/23] Change: move `THEME` to `ErrorCore` --- compiler/erg_common/style.rs | 11 +++++++---- compiler/erg_compiler/ty/deserialize.rs | 7 +++---- compiler/erg_parser/lex.rs | 7 +++---- compiler/erg_parser/parse.rs | 7 +++---- compiler/erg_parser/tests/parse_test.rs | 3 +-- 5 files changed, 17 insertions(+), 18 deletions(-) diff --git a/compiler/erg_common/style.rs b/compiler/erg_common/style.rs index d4feb738..81c5882d 100644 --- a/compiler/erg_common/style.rs +++ b/compiler/erg_common/style.rs @@ -23,7 +23,7 @@ pub const CUSTOM_MAGENTA: &str = "\x1b[38;2;103;65;150m"; pub const CUSTOM_GREEN: &str = "\x1b[38;2;170;209;71m"; pub const CUSTOM_YELLOW: &str = "\x1b[38;2;230;180;34m"; -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Hash)] pub enum Color { Reset, Black, @@ -87,13 +87,14 @@ impl Attribute { } } -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct ThemeColors { pub error: Color, pub warning: Color, pub exception: Color, pub gutter: Color, pub hint: Color, + pub accent: Color, } #[cfg(not(feature = "pretty"))] @@ -103,6 +104,7 @@ pub const COLORS: ThemeColors = ThemeColors { exception: Color::Magenta, gutter: Color::Cyan, hint: Color::Green, + accent: Color::White, }; #[cfg(feature = "pretty")] @@ -112,9 +114,10 @@ pub const COLORS: ThemeColors = ThemeColors { exception: Color::CustomMagenta, gutter: Color::CustomCyan, hint: Color::CustomGreen, + accent: Color::CustomGray, }; -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct Characters { hat: char, // error wave: char, // exception @@ -177,7 +180,7 @@ impl Characters { } } -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct Theme { pub colors: ThemeColors, pub characters: Characters, diff --git a/compiler/erg_compiler/ty/deserialize.rs b/compiler/erg_compiler/ty/deserialize.rs index 7bfa8bdc..679a7bff 100644 --- a/compiler/erg_compiler/ty/deserialize.rs +++ b/compiler/erg_compiler/ty/deserialize.rs @@ -6,7 +6,7 @@ use erg_common::astr::AtomicStr; use erg_common::cache::CacheSet; use erg_common::config::{ErgConfig, Input}; use erg_common::dict::Dict; -use erg_common::error::{ErrorCore, ErrorKind, Location}; +use erg_common::error::{ErrorCore, ErrorKind, Location, SubMessage}; use erg_common::python_util::PythonVersion; use erg_common::serialize::DataTypePrefix; use erg_common::{fn_name, switch_lang}; @@ -40,11 +40,10 @@ impl From for DeserializeError { impl From for ErrorCore { fn from(err: DeserializeError) -> Self { ErrorCore::new( + vec![SubMessage::only_loc(Location::Unknown)], + err.desc, err.errno, ErrorKind::ImportError, - Location::Unknown, - err.desc, - Option::::None, ) } } diff --git a/compiler/erg_parser/lex.rs b/compiler/erg_parser/lex.rs index 1d13ae91..dde1c872 100644 --- a/compiler/erg_parser/lex.rs +++ b/compiler/erg_parser/lex.rs @@ -4,7 +4,6 @@ use std::cmp::Ordering; use erg_common::cache::CacheSet; use erg_common::config::ErgConfig; use erg_common::config::Input; -use erg_common::style::THEME; use erg_common::traits::{Locational, Runnable, Stream}; use erg_common::{debug_power_assert, fn_name_full, normalize_newline, switch_lang}; @@ -42,7 +41,7 @@ impl Runnable for LexerRunner { let lexer = Lexer::from_str(self.input().read()); let ts = lexer .lex() - .map_err(|errs| LexerRunnerErrors::convert(self.input(), errs, THEME))?; + .map_err(|errs| LexerRunnerErrors::convert(self.input(), errs))?; println!("{ts}"); Ok(0) } @@ -52,13 +51,13 @@ impl Runnable for LexerRunner { if cfg!(feature = "debug") { let ts = lexer .lex() - .map_err(|errs| LexerRunnerErrors::convert(self.input(), errs, THEME))?; + .map_err(|errs| LexerRunnerErrors::convert(self.input(), errs))?; println!("{ts}"); Ok(ts.to_string()) } else { Ok(lexer .lex() - .map_err(|errs| LexerRunnerErrors::convert(self.input(), errs, THEME))? + .map_err(|errs| LexerRunnerErrors::convert(self.input(), errs))? .to_string()) } } diff --git a/compiler/erg_parser/parse.rs b/compiler/erg_parser/parse.rs index 1ef447ca..a7704834 100644 --- a/compiler/erg_parser/parse.rs +++ b/compiler/erg_parser/parse.rs @@ -11,7 +11,6 @@ use erg_common::error::Location; use erg_common::option_enum_unwrap; use erg_common::set::Set as HashSet; use erg_common::str::Str; -use erg_common::style::THEME; use erg_common::traits::Runnable; use erg_common::traits::{Locational, Stream}; use erg_common::{ @@ -207,16 +206,16 @@ impl ParserRunner { pub fn parse_token_stream(&mut self, ts: TokenStream) -> Result { Parser::new(ts) .parse() - .map_err(|errs| ParserRunnerErrors::convert(self.input(), errs, THEME)) + .map_err(|errs| ParserRunnerErrors::convert(self.input(), errs)) } pub fn parse(&mut self, src: String) -> Result { let ts = Lexer::new(Input::Str(src)) .lex() - .map_err(|errs| ParserRunnerErrors::convert(self.input(), errs, THEME))?; + .map_err(|errs| ParserRunnerErrors::convert(self.input(), errs))?; Parser::new(ts) .parse() - .map_err(|errs| ParserRunnerErrors::convert(self.input(), errs, THEME)) + .map_err(|errs| ParserRunnerErrors::convert(self.input(), errs)) } } diff --git a/compiler/erg_parser/tests/parse_test.rs b/compiler/erg_parser/tests/parse_test.rs index 62590f91..15734391 100644 --- a/compiler/erg_parser/tests/parse_test.rs +++ b/compiler/erg_parser/tests/parse_test.rs @@ -1,6 +1,5 @@ use erg_common::config::{ErgConfig, Input}; use erg_common::error::MultiErrorDisplay; -use erg_common::style::THEME; use erg_common::traits::Runnable; use erg_parser::error::ParserRunnerErrors; @@ -64,7 +63,7 @@ fn parse_test_from_code(file_path: &'static str) -> Result<(), ParserRunnerError match parser.parse_token_stream( lexer .lex() - .map_err(|errs| ParserRunnerErrors::convert(&input, errs, THEME))?, + .map_err(|errs| ParserRunnerErrors::convert(&input, errs))?, ) { Ok(module) => { println!("{module}"); From 000124fea83d4ce437188f2b9c0beb6b3f9299e2 Mon Sep 17 00:00:00 2001 From: GreasySlug <9619abgoni@gmail.com> Date: Thu, 17 Nov 2022 23:27:31 +0900 Subject: [PATCH 04/23] Update: changed in support of `SubMessage` --- compiler/erg_compiler/context/eval.rs | 3 +- .../context/initialize/const_func.rs | 96 ++-- compiler/erg_compiler/context/inquire.rs | 39 +- compiler/erg_compiler/context/register.rs | 3 +- compiler/erg_compiler/error.rs | 436 ++++++++---------- compiler/erg_parser/error.rs | 70 +-- 6 files changed, 318 insertions(+), 329 deletions(-) diff --git a/compiler/erg_compiler/context/eval.rs b/compiler/erg_compiler/context/eval.rs index fa506edf..3bc46b74 100644 --- a/compiler/erg_compiler/context/eval.rs +++ b/compiler/erg_compiler/context/eval.rs @@ -241,7 +241,8 @@ impl Context { match subr { ConstSubr::User(_user) => todo!(), ConstSubr::Builtin(builtin) => builtin.call(args, self).map_err(|mut e| { - e.0.loc = loc; + // TODO: Is it possible to get 0? + e.0.sub_messages.get_mut(0).unwrap().loc = loc; EvalErrors::from(EvalError::new( *e.0, self.cfg.input.clone(), diff --git a/compiler/erg_compiler/context/initialize/const_func.rs b/compiler/erg_compiler/context/initialize/const_func.rs index 4313f863..b0eb198a 100644 --- a/compiler/erg_compiler/context/initialize/const_func.rs +++ b/compiler/erg_compiler/context/initialize/const_func.rs @@ -7,29 +7,37 @@ use crate::ty::constructors::{and, mono}; use crate::ty::value::{EvalValueResult, GenTypeObj, TypeObj, ValueObj}; use crate::ty::ValueArgs; use erg_common::astr::AtomicStr; -use erg_common::error::{ErrorCore, ErrorKind, Location}; -use erg_common::style::{RED, RESET, YELLOW}; +use erg_common::error::{ErrorCore, ErrorKind, Location, SubMessage}; +use erg_common::style::{Color, StyledStr, StyledString, THEME}; + +const ERR: Color = THEME.colors.error; +const WARN: Color = THEME.colors.warning; + +const SUP_ERR: StyledStr = StyledStr::new("Super", Some(ERR), None); +const SUP_WARN: StyledStr = StyledStr::new("Super", Some(WARN), None); +const CLASS_ERR: StyledStr = StyledStr::new("Class", Some(ERR), None); +const REQ_ERR: StyledStr = StyledStr::new("Requirement", Some(ERR), None); +const REQ_WARN: StyledStr = StyledStr::new("Requirement", Some(WARN), None); /// Requirement: Type, Impl := Type -> ClassType pub fn class_func(mut args: ValueArgs, ctx: &Context) -> EvalValueResult { let require = args.remove_left_or_key("Requirement").ok_or_else(|| { ErrorCore::new( + vec![SubMessage::only_loc(Location::Unknown)], + AtomicStr::from(format!("{REQ_ERR} is not passed")), line!() as usize, ErrorKind::TypeError, - Location::Unknown, - AtomicStr::from(format!("{RED}Requirement{RESET} is not passed")), - None, ) })?; let Some(require) = require.as_type() else { + let require = StyledString::new(&format!("{}", require), Some(ERR), None); return Err(ErrorCore::new( + vec![SubMessage::only_loc(Location::Unknown)], + AtomicStr::from(format!( + "non-type object {require} is passed to {REQ_WARN}", + )), line!() as usize, ErrorKind::TypeError, - Location::Unknown, - AtomicStr::from(format!( - "non-type object {RED}{require}{RESET} is passed to {YELLOW}Requirement{RESET}", - )), - None, ).into()); }; let impls = args.remove_left_or_key("Impl"); @@ -41,23 +49,23 @@ pub fn class_func(mut args: ValueArgs, ctx: &Context) -> EvalValueResult ClassType pub fn inherit_func(mut args: ValueArgs, ctx: &Context) -> EvalValueResult { let sup = args.remove_left_or_key("Super").ok_or_else(|| { + let sup = StyledStr::new("Super", Some(ERR), None); ErrorCore::new( + vec![SubMessage::only_loc(Location::Unknown)], + AtomicStr::from(format!("{sup} is not passed")), line!() as usize, ErrorKind::KeyError, - Location::Unknown, - AtomicStr::from(format!("{RED}Super{RESET} is not passed")), - None, ) })?; let Some(sup) = sup.as_type() else { + let sup_ty = StyledString::new(&format!("{}", sup), Some(ERR), None); return Err(ErrorCore::new( + vec![SubMessage::only_loc(Location::Unknown)], + AtomicStr::from(format!( + "non-class object {sup_ty} is passed to {SUP_WARN}", + )), line!() as usize, ErrorKind::TypeError, - Location::Unknown, - AtomicStr::from(format!( - "non-class object {RED}{sup}{RESET} is passed to {YELLOW}Super{RESET}", - )), - None, ).into()); }; let impls = args.remove_left_or_key("Impl"); @@ -75,11 +83,10 @@ pub fn inherit_func(mut args: ValueArgs, ctx: &Context) -> EvalValueResult EvalValueResult { let class = args.remove_left_or_key("Class").ok_or_else(|| { ErrorCore::new( + vec![SubMessage::only_loc(Location::Unknown)], + AtomicStr::from(format!("{CLASS_ERR} is not passed")), line!() as usize, ErrorKind::KeyError, - Location::Unknown, - AtomicStr::from(format!("{RED}Class{RESET} is not passed")), - None, ) })?; match class { @@ -107,22 +114,21 @@ pub fn inheritable_func(mut args: ValueArgs, _ctx: &Context) -> EvalValueResult< pub fn trait_func(mut args: ValueArgs, ctx: &Context) -> EvalValueResult { let require = args.remove_left_or_key("Requirement").ok_or_else(|| { ErrorCore::new( + vec![SubMessage::only_loc(Location::Unknown)], + AtomicStr::from(format!("{REQ_ERR} is not passed")), line!() as usize, ErrorKind::KeyError, - Location::Unknown, - AtomicStr::from(format!("{RED}Requirement{RESET} is not passed")), - None, ) })?; let Some(require) = require.as_type() else { + let require = StyledString::new(&format!("{}", require), Some(ERR), None); return Err(ErrorCore::new( + vec![SubMessage::only_loc(Location::Unknown)], + AtomicStr::from(format!( + "non-type object {require} is passed to {REQ_WARN}", + )), line!() as usize, ErrorKind::TypeError, - Location::Unknown, - AtomicStr::from(format!( - "non-type object {RED}{require}{RESET} is passed to {YELLOW}Requirement{RESET}", - )), - None, ).into()); }; let impls = args.remove_left_or_key("Impl"); @@ -135,22 +141,21 @@ pub fn trait_func(mut args: ValueArgs, ctx: &Context) -> EvalValueResult EvalValueResult { let sup = args.remove_left_or_key("Super").ok_or_else(|| { ErrorCore::new( + vec![SubMessage::only_loc(Location::Unknown)], + AtomicStr::from(format!("{SUP_ERR} is not passed")), line!() as usize, ErrorKind::KeyError, - Location::Unknown, - AtomicStr::from(format!("{RED}Super{RESET} is not passed")), - None, ) })?; let Some(sup) = sup.as_type() else { + let sup = StyledString::new(&format!("{}", sup), Some(ERR), None); return Err(ErrorCore::new( + vec![SubMessage::only_loc(Location::Unknown)], + AtomicStr::from(format!( + "non-trait object {sup} is passed to {SUP_WARN}", + )), line!() as usize, ErrorKind::TypeError, - Location::Unknown, - AtomicStr::from(format!( - "non-trait object {RED}{sup}{RESET} is passed to {YELLOW}Super{RESET}", - )), - None, ).into()); }; let impls = args.remove_left_or_key("Impl"); @@ -172,16 +177,15 @@ pub fn __array_getitem__(mut args: ValueArgs, ctx: &Context) -> EvalValueResult< Ok(v.clone()) } else { Err(ErrorCore::new( - line!() as usize, - ErrorKind::IndexError, - Location::Unknown, + vec![SubMessage::only_loc(Location::Unknown)], AtomicStr::from(format!( "[{}] has {} elements, but accessed {}th element", erg_common::fmt_vec(&slf), slf.len(), index )), - None, + line!() as usize, + ErrorKind::IndexError, ) .into()) } @@ -211,11 +215,10 @@ pub fn __dict_getitem__(mut args: ValueArgs, ctx: &Context) -> EvalValueResult EvalValueResult Ok(ValueObj::Nat(start + index)) } else { Err(ErrorCore::new( + vec![SubMessage::only_loc(Location::Unknown)], + AtomicStr::from(format!("Index out of range: {}", index)), line!() as usize, ErrorKind::IndexError, - Location::Unknown, - AtomicStr::from(format!("Index out of range: {}", index)), - None, ) .into()) } diff --git a/compiler/erg_compiler/context/inquire.rs b/compiler/erg_compiler/context/inquire.rs index d08598f4..4d5b24ed 100644 --- a/compiler/erg_compiler/context/inquire.rs +++ b/compiler/erg_compiler/context/inquire.rs @@ -4,7 +4,7 @@ use std::path::{Path, PathBuf}; use erg_common::config::Input; use erg_common::env::erg_pystd_path; -use erg_common::error::{ErrorCore, ErrorKind, Location}; +use erg_common::error::{ErrorCore, ErrorKind, Location, SubMessage}; use erg_common::levenshtein::get_similar_name; use erg_common::set::Set; use erg_common::traits::{Locational, Stream}; @@ -757,13 +757,20 @@ impl Context { TyCheckErrors::new( errs.into_iter() .map(|e| { - // HACK: dname.loc()はダミーLocationしか返さないので、エラーならop.loc()で上書きする + let mut sub_msges = Vec::new(); + for sub_msg in e.core.sub_messages { + sub_msges.push(SubMessage::ambiguous_new( + // HACK: dname.loc()はダミーLocationしか返さないので、エラーならop.loc()で上書きする + bin.loc(), + None, + sub_msg.get_hint(), + )); + } let core = ErrorCore::new( + sub_msges, + e.core.main_message, e.core.errno, e.core.kind, - bin.loc(), - e.core.desc, - e.core.hint, ); TyCheckError::new(core, self.cfg.input.clone(), e.caused_by) }) @@ -798,12 +805,19 @@ impl Context { TyCheckErrors::new( errs.into_iter() .map(|e| { + let mut sub_msges = Vec::new(); + for sub_msg in e.core.sub_messages { + sub_msges.push(SubMessage::ambiguous_new( + unary.loc(), + None, + sub_msg.get_hint(), + )); + } let core = ErrorCore::new( + sub_msges, + e.core.main_message, e.core.errno, e.core.kind, - unary.loc(), - e.core.desc, - e.core.hint, ); TyCheckError::new(core, self.cfg.input.clone(), e.caused_by) }) @@ -1053,7 +1067,8 @@ impl Context { TyCheckError::type_mismatch_error( self.cfg.input.clone(), line!() as usize, - e.core.loc, + // TODO: Is it possible to get 0? + e.core.sub_messages.get(0).unwrap().loc, e.caused_by, &name[..], Some(nth), @@ -1108,7 +1123,8 @@ impl Context { TyCheckError::type_mismatch_error( self.cfg.input.clone(), line!() as usize, - e.core.loc, + // TODO: Is it possible to get 0? + e.core.sub_messages.get(0).unwrap().loc, e.caused_by, &name[..], Some(nth), @@ -1165,7 +1181,8 @@ impl Context { TyCheckError::type_mismatch_error( self.cfg.input.clone(), line!() as usize, - e.core.loc, + // TODO: Is it possible to get 0? + e.core.sub_messages.get(0).unwrap().loc, e.caused_by, &name[..], Some(nth), diff --git a/compiler/erg_compiler/context/register.rs b/compiler/erg_compiler/context/register.rs index 3560240e..6841f7b4 100644 --- a/compiler/erg_compiler/context/register.rs +++ b/compiler/erg_compiler/context/register.rs @@ -416,7 +416,8 @@ impl Context { TyCheckError::return_type_error( self.cfg.input.clone(), line!() as usize, - e.core.loc, + // TODO: is it possible to get 0? + e.core.sub_messages.get(0).unwrap().loc, e.caused_by, readable_name(name.inspect()), spec_ret_t, diff --git a/compiler/erg_compiler/error.rs b/compiler/erg_compiler/error.rs index 4fa0c717..bba20121 100644 --- a/compiler/erg_compiler/error.rs +++ b/compiler/erg_compiler/error.rs @@ -2,9 +2,11 @@ use std::fmt::Display; use erg_common::astr::AtomicStr; use erg_common::config::Input; -use erg_common::error::{ErrorCore, ErrorDisplay, ErrorKind::*, Location, MultiErrorDisplay}; +use erg_common::error::{ + ErrorCore, ErrorDisplay, ErrorKind::*, Location, MultiErrorDisplay, SubMessage, +}; use erg_common::set::Set; -use erg_common::style::{Attribute, Color, StyledStr, StyledString, Theme, THEME}; +use erg_common::style::{Attribute, Color, StyledStr, StyledString, THEME}; use erg_common::traits::{Locational, Stream}; use erg_common::vis::Visibility; use erg_common::{ @@ -112,7 +114,6 @@ pub struct CompileError { pub core: Box, // ErrorCore is large, so box it pub input: Input, pub caused_by: AtomicStr, - pub theme: Theme, } impl_display_and_error!(CompileError); @@ -123,7 +124,6 @@ impl From for CompileError { core: Box::new(err.core), input: err.input, caused_by: "".into(), - theme: THEME, } } } @@ -135,9 +135,6 @@ impl ErrorDisplay for CompileError { fn input(&self) -> &Input { &self.input } - fn theme(&self) -> &Theme { - &self.theme - } fn caused_by(&self) -> &str { &self.caused_by } @@ -146,9 +143,10 @@ impl ErrorDisplay for CompileError { } } +const ACCENT: Color = THEME.colors.accent; const URL: StyledStr = StyledStr::new( "https://github.com/erg-lang/erg", - Some(Color::White), + Some(ACCENT), Some(Attribute::Underline), ); @@ -158,7 +156,6 @@ impl CompileError { core: Box::new(core), input, caused_by, - theme: THEME, } } @@ -171,16 +168,15 @@ impl CompileError { ) -> Self { Self::new( ErrorCore::new( - errno, - CompilerSystemError, - loc, + vec![SubMessage::only_loc(loc)], switch_lang!( "japanese" => format!("これはErg compilerのバグです、開発者に報告して下さい ({URL})\n\n{fn_name}:{line}より発生"), "simplified_chinese" => format!("这是Erg编译器的错误,请报告给{URL}\n\n原因来自: {fn_name}:{line}"), "traditional_chinese" => format!("這是Erg編譯器的錯誤,請報告給{URL}\n\n原因來自: {fn_name}:{line}"), "english" => format!("this is a bug of the Erg compiler, please report it to {URL}\n\ncaused from: {fn_name}:{line}"), ), - None, + errno, + CompilerSystemError, ), input, "".into(), @@ -196,9 +192,7 @@ impl CompileError { ) -> Self { Self::new( ErrorCore::new( - 0, - CompilerSystemError, - loc, + vec![SubMessage::only_loc(loc)], switch_lang!( "japanese" => format!("スタックの要素数が異常です (要素数: {stack_len}, ブロックID: {block_id})\n\ これはコンパイラのバグです、開発者に報告して下さい ({URL})\n\ @@ -213,7 +207,8 @@ impl CompileError { this is a bug of the Erg compiler, please report it ({URL})\n\ caused from: {fn_name}"), ), - None, + 0, + CompilerSystemError, ), input, "".into(), @@ -223,16 +218,15 @@ impl CompileError { pub fn feature_error(input: Input, loc: Location, name: &str, caused_by: AtomicStr) -> Self { Self::new( ErrorCore::new( - 0, - FeatureError, - loc, + vec![SubMessage::only_loc(loc)], switch_lang!( "japanese" => format!("この機能({name})はまだ正式に提供されていません"), "simplified_chinese" => format!("此功能({name})尚未实现"), "traditional_chinese" => format!("此功能({name})尚未實現"), "english" => format!("this feature({name}) is not implemented yet"), ), - None, + 0, + FeatureError, ), input, caused_by, @@ -242,16 +236,15 @@ impl CompileError { pub fn system_exit() -> Self { Self::new( ErrorCore::new( - 0, - SystemExit, - Location::Unknown, + vec![SubMessage::only_loc(Location::Unknown)], switch_lang!( "japanese" => "システムを終了します", "simplified_chinese" => "系统正在退出", "traditional_chinese" => "系統正在退出", "english" => "system is exiting", ), - None, + 0, + SystemExit, ), Input::Dummy, "".into(), @@ -283,16 +276,15 @@ impl TyCheckError { ) -> Self { Self::new( ErrorCore::new( - errno, - CompilerSystemError, - loc, + vec![SubMessage::only_loc(loc)], switch_lang!( "japanese" => format!("これはErg compilerのバグです、開発者に報告して下さい ({URL})\n\n{fn_name}:{line}より発生"), "simplified_chinese" => format!("这是Erg编译器的错误,请报告给{URL}\n\n原因来自: {fn_name}:{line}"), "traditional_chinese" => format!("這是Erg編譯器的錯誤,請報告給{URL}\n\n原因來自: {fn_name}:{line}"), "english" => format!("this is a bug of the Erg compiler, please report it to {URL}\n\ncaused from: {fn_name}:{line}"), ), - None, + errno, + CompilerSystemError, ), input, "".into(), @@ -309,16 +301,15 @@ impl TyCheckError { let name = readable_name(name); Self::new( ErrorCore::new( - errno, - TypeError, - loc, + vec![SubMessage::only_loc(loc)], switch_lang!( "japanese" => format!("{name}の型が指定されていません"), "simplified_chinese" => format!("{name}的类型未指定"), "traditional_chinese" => format!("{name}的類型未指定"), "english" => format!("the type of {name} is not specified"), ), - None, + errno, + TypeError, ), input, caused_by, @@ -335,9 +326,7 @@ impl TyCheckError { let param_ts = fmt_iter(param_ts); Self::new( ErrorCore::new( - errno, - NotImplementedError, - callee.loc(), + vec![SubMessage::only_loc(callee.loc())], switch_lang!( "japanese" => format!( "{callee}は{param_ts}を引数に取る呼び出し可能オブジェクトではありません" @@ -348,7 +337,8 @@ impl TyCheckError { "{callee} is not a Callable object that takes {param_ts} as an argument" ), ), - None, + errno, + NotImplementedError, ), input, caused_by, @@ -386,16 +376,15 @@ impl TyCheckError { let found = StyledString::new(&format!("{}", found), Some(ERR), Some(Attribute::Bold)); Self::new( ErrorCore::new( - errno, - TypeError, - loc, + vec![SubMessage::ambiguous_new(loc, None, hint)], switch_lang!( "japanese" => format!("{name}の型が違います\n\n予期した型: {expect}\n与えられた型: {found}{}", fmt_option_map!(pre "\n与えられた型の単一化候補: ", candidates, |x: &Set| x.folded_display())), "simplified_chinese" => format!("{name}的类型不匹配\n\n预期: {expect}\n但找到: {found}{}", fmt_option_map!(pre "\n某一类型的统一候选: ", candidates, |x: &Set| x.folded_display())), "traditional_chinese" => format!("{name}的類型不匹配\n\n預期: {expect}\n但找到: {found}{}", fmt_option_map!(pre "\n某一類型的統一候選: ", candidates, |x: &Set| x.folded_display())), "english" => format!("the type of {name} is mismatched\n\nexpected: {expect}\nbut found: {found}{}", fmt_option_map!(pre "\nunification candidates of a given type: ", candidates, |x: &Set| x.folded_display())), ), - hint, + errno, + TypeError, ), input, caused_by, @@ -415,16 +404,15 @@ impl TyCheckError { let found = StyledString::new(&format!("{}", found), Some(ERR), Some(Attribute::Bold)); Self::new( ErrorCore::new( - errno, - TypeError, - loc, + vec![SubMessage::only_loc(loc)], switch_lang!( "japanese" => format!("{name}の戻り値の型が違います\n\n予期した型: {expect}\n与えられた型: {found}"), "simplified_chinese" => format!("{name}的返回类型不匹配\n\n预期: {expect}\n但找到: {found}"), "traditional_chinese" => format!("{name}的返回類型不匹配\n\n預期: {expect}\n但找到: {found}"), "english" => format!("the return type of {name} is mismatched\n\nexpected: {expect}\nbut found: {found}"), ), - None, + errno, + TypeError, ), input, caused_by, @@ -441,16 +429,15 @@ impl TyCheckError { ) -> Self { Self::new( ErrorCore::new( - errno, - NameError, - loc, + vec![SubMessage::only_loc(loc)], switch_lang!( "japanese" => format!("{name}: {t}は宣言されましたが初期化されていません"), "simplified_chinese" => format!("{name}: {t}已声明但未初始化"), "traditional_chinese" => format!("{name}: {t}已宣告但未初始化"), "english" => format!("{name}: {t} is declared but not initialized"), ), - None, + errno, + NameError, ), input, caused_by, @@ -469,16 +456,15 @@ impl TyCheckError { let found = StyledString::new(&format!("{}", found), Some(ERR), Some(Attribute::Bold)); Self::new( ErrorCore::new( - errno, - TypeError, - loc, + vec![SubMessage::only_loc(loc)], switch_lang!( "japanese" => format!("ポジショナル引数の数が違います\n\n予期した個数: {expect}\n与えられた個数: {found}"), "simplified_chinese" => format!("正则参数的数量不匹配\n\n预期: {expect}\n但找到: {found}"), "traditional_chinese" => format!("正則參數的數量不匹配\n\n預期: {expect}\n但找到: {found}"), "english" => format!("the number of positional arguments is mismatched\n\nexpected: {expect}\nbut found: {found}"), ), - None, + errno, + TypeError, ), input, caused_by, @@ -494,16 +480,15 @@ impl TyCheckError { ) -> Self { Self::new( ErrorCore::new( - errno, - TypeError, - loc, + vec![SubMessage::only_loc(loc)], switch_lang!( "japanese" => format!("{expr_t}型の全パターンを網羅していません"), "simplified_chinese" => format!("并非所有{expr_t}类型的模式都被涵盖"), "traditional_chinese" => format!("並非所有{expr_t}類型的模式都被涵蓋"), "english" => format!("not all patterns of type {expr_t} are covered"), ), - None, + errno, + TypeError, ), input, caused_by, @@ -519,16 +504,15 @@ impl TyCheckError { ) -> Self { Self::new( ErrorCore::new( - errno, - TypeError, - loc, + vec![SubMessage::only_loc(loc)], switch_lang!( "japanese" => format!("{expr}の型が推論できません"), "simplified_chinese" => format!("无法推断{expr}的类型"), "traditional_chinese" => format!("無法推斷{expr}的類型"), "english" => format!("failed to infer the type of {expr}"), ), - None, + errno, + TypeError, ), input, caused_by, @@ -572,9 +556,7 @@ impl TyCheckError { ); Self::new( ErrorCore::new( - errno, - TypeError, - loc, + vec![SubMessage::only_loc(loc)], switch_lang!( "japanese" => format!( "{name}に渡された引数の数が多すぎます @@ -603,7 +585,8 @@ passed positional args: {pos_args_len} passed keyword args: {kw_args_len}" ), ), - None, + errno, + TypeError, ), input, caused_by, @@ -627,16 +610,15 @@ passed keyword args: {kw_args_len}" ); Self::new( ErrorCore::new( - errno, - TypeError, - loc, + vec![SubMessage::only_loc(loc)], switch_lang!( "japanese" => format!("{name}に渡された引数が{missing_len}個足りません({vec_cxt})" ), "simplified_chinese" => format!("{name}的{missing_len}个位置参数不被传递({vec_cxt})"), "traditional_chinese" => format!("{name}的{missing_len}個位置參數不被傳遞({vec_cxt})"), "english" => format!("missing {missing_len} positional argument(s) for {name}: {vec_cxt}"), ), - None, + errno, + TypeError, ), input, caused_by, @@ -655,16 +637,15 @@ passed keyword args: {kw_args_len}" let found = StyledString::new(arg_name, Some(ERR), Some(Attribute::Bold)); Self::new( ErrorCore::new( - errno, - TypeError, - loc, + vec![SubMessage::only_loc(loc)], switch_lang!( "japanese" => format!("{name}の引数{found}が複数回渡されています"), "simplified_chinese" => format!("{name}的参数{found}被多次传递"), "traditional_chinese" => format!("{name}的參數{found}被多次傳遞"), "english" => format!("{name}'s argument {found} is passed multiple times"), ), - None, + errno, + TypeError, ), input, caused_by, @@ -683,16 +664,15 @@ passed keyword args: {kw_args_len}" let found = StyledString::new(param_name, Some(ERR), Some(Attribute::Bold)); Self::new( ErrorCore::new( - errno, - TypeError, - loc, + vec![SubMessage::only_loc(loc)], switch_lang!( "japanese" => format!("{name}には予期しないキーワード引数{found}が渡されています"), "simplified_chinese" => format!("{name}得到了意外的关键字参数{found}"), "traditional_chinese" => format!("{name}得到了意外的關鍵字參數{found}"), "english" => format!("{name} got unexpected keyword argument {found}"), ), - None, + errno, + TypeError, ), input, caused_by, @@ -711,16 +691,15 @@ passed keyword args: {kw_args_len}" let rhs_t = StyledString::new(&format!("{}", rhs_t), Some(WARNING), Some(Attribute::Bold)); Self::new( ErrorCore::new( - errno, - TypeError, - loc, + vec![SubMessage::only_loc(loc)], switch_lang!( "japanese" => format!("型の単一化に失敗しました\n\n左辺: {lhs_t}\n右辺: {rhs_t}"), "simplified_chinese" => format!("类型统一失败\n\n左边: {lhs_t}\n右边: {rhs_t}"), "traditional_chinese" => format!("類型統一失敗\n\n左邊: {lhs_t}\n右邊: {rhs_t}"), "english" => format!("unification failed\n\nlhs: {lhs_t}\nrhs: {rhs_t}"), ), - None, + errno, + TypeError, ), input, caused_by, @@ -739,16 +718,15 @@ passed keyword args: {kw_args_len}" let rhs_t = StyledString::new(&format!("{}", rhs_t), Some(WARNING), Some(Attribute::Bold)); Self::new( ErrorCore::new( - errno, - TypeError, - loc, + vec![SubMessage::only_loc(loc)], switch_lang!( "japanese" => format!("型の再単一化に失敗しました\n\n左辺: {lhs_t}\n右辺: {rhs_t}"), "simplified_chinese" => format!("重新统一类型失败\n\n左边: {lhs_t}\n右边: {rhs_t}"), "traditional_chinese" => format!("重新統一類型失敗\n\n左邊: {lhs_t}\n右邊: {rhs_t}"), "english" => format!("re-unification failed\n\nlhs: {lhs_t}\nrhs: {rhs_t}"), ), - None, + errno, + TypeError, ), input, caused_by, @@ -767,16 +745,15 @@ passed keyword args: {kw_args_len}" let sup_t = StyledString::new(&format!("{}", sup_t), Some(WARNING), Some(Attribute::Bold)); Self::new( ErrorCore::new( - errno, - TypeError, - loc, + vec![SubMessage::only_loc(loc)], switch_lang!( "japanese" => format!("この式の部分型制約を満たせません\n\nサブタイプ: {sub_t}\nスーパータイプ: {sup_t}"), "simplified_chinese" => format!("无法满足此表达式中的子类型约束\n\n子类型: {sub_t}\n超类型: {sup_t}"), "traditional_chinese" => format!("無法滿足此表達式中的子類型約束\n\n子類型: {sub_t}\n超類型: {sup_t}"), "english" => format!("the subtype constraint in this expression cannot be satisfied:\nsubtype: {sub_t}\nsupertype: {sup_t}"), ), - None, + errno, + TypeError, ), input, caused_by, @@ -794,16 +771,15 @@ passed keyword args: {kw_args_len}" let rhs = StyledString::new(&format!("{}", rhs), Some(WARNING), Some(Attribute::Bold)); Self::new( ErrorCore::new( - errno, - TypeError, - Location::Unknown, + vec![SubMessage::only_loc(Location::Unknown)], switch_lang!( "japanese" => format!("述語式の単一化に失敗しました\n\n左辺: {lhs}\n右辺: {rhs}"), "simplified_chinese" => format!("无法统一谓词表达式\n\n左边: {lhs}\n左边: {rhs}"), "traditional_chinese" => format!("無法統一謂詞表達式\n\n左邊: {lhs}\n左邊: {rhs}"), "english" => format!("predicate unification failed\n\nlhs: {lhs}\nrhs: {rhs}"), ), - None, + errno, + TypeError, ), input, caused_by, @@ -820,16 +796,15 @@ passed keyword args: {kw_args_len}" ) -> Self { Self::new( ErrorCore::new( - errno, - TypeError, - loc, + vec![SubMessage::ambiguous_new(loc, None, hint)], switch_lang!( "japanese" => format!("{proj}の候補がありません"), "simplified_chinese" => format!("{proj}没有候选项"), "traditional_chinese" => format!("{proj}沒有候選項"), "english" => format!("no candidate for {proj}"), ), - hint, + errno, + TypeError, ), input, caused_by, @@ -847,16 +822,15 @@ passed keyword args: {kw_args_len}" ) -> Self { Self::new( ErrorCore::new( - errno, - TypeError, - loc, + vec![SubMessage::ambiguous_new(loc, None, hint)], switch_lang!( "japanese" => format!("{class}は{trait_}を実装していません"), "simplified_chinese" => format!("{class}没有实现{trait_}"), "traditional_chinese" => format!("{class}沒有實現{trait_}"), "english" => format!("{class} does not implement {trait_}"), ), - hint, + errno, + TypeError, ), input, caused_by, @@ -874,9 +848,7 @@ passed keyword args: {kw_args_len}" let found = StyledString::new(name, Some(ERR), Some(Attribute::Bold)); Self::new( ErrorCore::new( - errno, - MethodError, - loc, + vec![SubMessage::ambiguous_new(loc, None, hint)], switch_lang!( "japanese" => format!( "{found}にメソッドを定義することはできません", @@ -891,7 +863,8 @@ passed keyword args: {kw_args_len}" "cannot define methods for {found}", ), ), - hint, + errno, + MethodError, ), input, caused_by, @@ -915,16 +888,15 @@ passed keyword args: {kw_args_len}" let found = StyledString::new(&format!("{}", found), Some(ERR), Some(Attribute::Bold)); Self::new( ErrorCore::new( - errno, - TypeError, - loc, + vec![SubMessage::ambiguous_new(loc, None, hint)], switch_lang!( "japanese" => format!("{member_name}の型が違います\n\n{trait_type}で宣言された型: {expect}\n与えられた型: {found}"), "simplified_chinese" => format!("{member_name}的类型不匹配\n\n在{trait_type}中声明的类型: {expect}\n但找到: {found}"), "traditional_chinese" => format!("{member_name}的類型不匹配\n\n在{trait_type}中聲明的類型: {expect}\n但找到: {found}"), "english" => format!("the type of {member_name} is mismatched\n\ndeclared in {trait_type}: {expect}\nbut found: {found}"), ), - hint, + errno, + TypeError, ), input, caused_by, @@ -944,16 +916,15 @@ passed keyword args: {kw_args_len}" let member_name = StyledString::new(member_name, Some(WARNING), Some(Attribute::Bold)); Self::new( ErrorCore::new( - errno, - TypeError, - Location::Unknown, + vec![SubMessage::ambiguous_new(Location::Unknown, None, hint)], switch_lang!( "japanese" => format!("{trait_type}の{member_name}が{class_type}で実装されていません"), "simplified_chinese" => format!("{trait_type}中的{member_name}没有在{class_type}中实现"), "traditional_chinese" => format!("{trait_type}中的{member_name}沒有在{class_type}中實現"), "english" => format!("{member_name} of {trait_type} is not implemented in {class_type}"), ), - hint, + errno, + TypeError, ), input, caused_by, @@ -973,16 +944,15 @@ passed keyword args: {kw_args_len}" let member_name = StyledString::new(member_name, Some(WARNING), Some(Attribute::Bold)); Self::new( ErrorCore::new( - errno, - TypeError, - Location::Unknown, + vec![SubMessage::ambiguous_new(Location::Unknown, None, hint)], switch_lang!( "japanese" => format!("{class_type}の{member_name}は{trait_type}で宣言されていません"), "simplified_chinese" => format!("{class_type}中的{member_name}没有在{trait_type}中声明"), "traditional_chinese" => format!("{class_type}中的{member_name}沒有在{trait_type}中聲明"), "english" => format!("{member_name} of {class_type} is not declared in {trait_type}"), ), - hint, + errno, + TypeError, ), input, caused_by, @@ -999,16 +969,15 @@ passed keyword args: {kw_args_len}" let found = StyledString::new(name, Some(ERR), Some(Attribute::Bold)); Self::new( ErrorCore::new( - errno, - TypeError, - loc, + vec![SubMessage::only_loc(loc)], switch_lang!( "japanese" => format!("型変数{found}が定義されていません"), "simplified_chinese" => format!("类型变量{found}没有定义"), "traditional_chinese" => format!("類型變量{found}沒有定義"), "english" => format!("type variable {found} is not defined"), ), - None, + errno, + TypeError, ), input, caused_by, @@ -1022,25 +991,25 @@ passed keyword args: {kw_args_len}" candidates: &[Type], caused_by: AtomicStr, ) -> Self { - Self::new( - ErrorCore::new( - errno, - TypeError, - expr.loc(), - switch_lang!( - "japanese" => format!("{expr}の型を一意に決定できませんでした\n\n候補: {}", fmt_vec(candidates)), - "simplified_chinese" => format!("无法确定{expr}的类型\n\n候选: {}", fmt_vec(candidates)), - "traditional_chinese" => format!("無法確定{expr}的類型\n\n候選: {}", fmt_vec(candidates)), - "english" => format!("cannot determine the type of {expr}\n\ncandidates: {}", fmt_vec(candidates)), - ), - Some( + let hint = Some( switch_lang!( "japanese" => "多相関数の場合は`f|T := Int|`, 型属性の場合は`T|T <: Trait|.X`などのようにして型を指定してください", "simplified_chinese" => "如果是多态函数,请使用`f|T := Int|`,如果是类型属性,请使用`T|T <: Trait|.X`等方式指定类型", "traditional_chinese" => "如果是多型函數,請使用`f|T := Int|`,如果是類型屬性,請使用`T|T <: Trait|.X`等方式指定類型", "english" => "if it is a polymorphic function, use `f|T := Int|`, or if it is a type attribute, use `T|T <: Trait|.X` etc. to specify the type", ).into(), + ); + Self::new( + ErrorCore::new( + vec![SubMessage::ambiguous_new(expr.loc(), None, hint)], + switch_lang!( + "japanese" => format!("{expr}の型を一意に決定できませんでした\n\n候補: {}", fmt_vec(candidates)), + "simplified_chinese" => format!("无法确定{expr}的类型\n\n候选: {}", fmt_vec(candidates)), + "traditional_chinese" => format!("無法確定{expr}的類型\n\n候選: {}", fmt_vec(candidates)), + "english" => format!("cannot determine the type of {expr}\n\ncandidates: {}", fmt_vec(candidates)), ), + errno, + TypeError, ), input, caused_by, @@ -1063,16 +1032,15 @@ impl EvalError { pub fn not_const_expr(input: Input, errno: usize, loc: Location, caused_by: AtomicStr) -> Self { Self::new( ErrorCore::new( - errno, - NotConstExpr, - loc, + vec![SubMessage::only_loc(loc)], switch_lang!( "japanese" => "定数式ではありません", "simplified_chinese" => "不是常量表达式", "traditional_chinese" => "不是常量表達式", "english" => "not a constant expression", ), - None, + errno, + NotConstExpr, ), input, caused_by, @@ -1087,16 +1055,15 @@ impl EvalError { ) -> Self { Self::new( ErrorCore::new( - errno, - SyntaxError, - loc, + vec![SubMessage::only_loc(loc)], switch_lang!( "japanese" => "リテラルが不正です", "simplified_chinese" => "字面量不合法", "traditional_chinese" => "字面量不合法", "english" => "invalid literal", ), - None, + errno, + SyntaxError, ), input, caused_by, @@ -1116,16 +1083,15 @@ impl EffectError { ) -> Self { Self::new( ErrorCore::new( - errno, - HasEffect, - expr.loc(), + vec![SubMessage::only_loc(expr.loc())], switch_lang!( "japanese" => "この式には副作用があります", "simplified_chinese" => "此表达式会产生副作用", "traditional_chinese" => "此表達式會產生副作用", "english" => "this expression causes a side-effect", ), - None, + errno, + HasEffect, ), input, caused_by.into(), @@ -1138,26 +1104,26 @@ impl EffectError { sig: &Signature, caused_by: S, ) -> Self { + let hint = Some( + switch_lang!( + "japanese" => "変数の末尾に`!`をつけてください", + "simplified_chinese" => "请在变量名后加上`!`", + "traditional_chinese" => "請在變量名後加上`!`", + "english" => "add `!` to the end of the variable name", + ) + .into(), + ); Self::new( ErrorCore::new( - errno, - HasEffect, - sig.loc(), + vec![SubMessage::ambiguous_new(sig.loc(), None, hint)], switch_lang!( "japanese" => "プロシージャを通常の変数に代入することはできません", "simplified_chinese" => "不能将过程赋值给普通变量", "traditional_chinese" => "不能將過程賦值給普通變量", "english" => "cannot assign a procedure to a normal variable", ), - Some( - switch_lang!( - "japanese" => "変数の末尾に`!`をつけてください", - "simplified_chinese" => "请在变量名后加上`!`", - "traditional_chinese" => "請在變量名後加上`!`", - "english" => "add `!` to the end of the variable name", - ) - .into(), - ), + errno, + HasEffect, ), input, caused_by.into(), @@ -1180,9 +1146,7 @@ impl OwnershipError { let found = StyledString::new(name, Some(ERR), Some(Attribute::Bold)); Self::new( ErrorCore::new( - errno, - MoveError, - name_loc, + vec![SubMessage::only_loc(name_loc)], switch_lang!( "japanese" => format!( "{found}は{}行目ですでに移動されています", @@ -1201,7 +1165,8 @@ impl OwnershipError { moved_loc.ln_begin().unwrap_or(0) ), ), - None, + errno, + MoveError, ), input, caused_by.into(), @@ -1226,7 +1191,12 @@ impl LowerError { hint: Option, ) -> Self { Self::new( - ErrorCore::new(errno, SyntaxError, loc, desc, hint), + ErrorCore::new( + vec![SubMessage::ambiguous_new(loc, None, hint)], + desc.into(), + errno, + SyntaxError, + ), input, caused_by, ) @@ -1242,16 +1212,15 @@ impl LowerError { let name = readable_name(name); Self::new( ErrorCore::new( - errno, - NameError, - loc, + vec![SubMessage::only_loc(loc)], switch_lang!( "japanese" => format!("{name}は既に宣言されています"), "simplified_chinese" => format!("{name}已声明"), "traditional_chinese" => format!("{name}已聲明"), "english" => format!("{name} is already declared"), ), - Option::::None, + errno, + NameError, ), input, caused_by, @@ -1268,16 +1237,15 @@ impl LowerError { let name = readable_name(name); Self::new( ErrorCore::new( - errno, - NameError, - loc, + vec![SubMessage::only_loc(loc)], switch_lang!( "japanese" => format!("{name}は既に定義されています"), "simplified_chinese" => format!("{name}已定义"), "traditional_chinese" => format!("{name}已定義"), "english" => format!("{name} is already defined"), ), - Option::::None, + errno, + NameError, ), input, caused_by, @@ -1298,16 +1266,15 @@ impl LowerError { let found = StyledString::new(&format!("{}", found_t), Some(ERR), Some(Attribute::Bold)); Self::new( ErrorCore::new( - errno, - TypeError, - loc, + vec![SubMessage::only_loc(loc)], switch_lang!( "japanese" => format!("{name}は{expect}型として宣言されましたが、{found}型のオブジェクトが代入されています"), "simplified_chinese" => format!("{name}被声明为{expect},但分配了一个{found}对象"), "traditional_chinese" => format!("{name}被聲明為{expect},但分配了一個{found}對象"), "english" => format!("{name} was declared as {expect}, but an {found} object is assigned"), ), - Option::::None, + errno, + TypeError, ), input, caused_by, @@ -1324,6 +1291,7 @@ impl LowerError { ) -> Self { let name = readable_name(name); let hint = similar_name.map(|n| { + let n = StyledStr::new(n, Some(HINT), Some(Attribute::Bold)); switch_lang!( "japanese" => format!("似た名前の変数があります: {n}"), "simplified_chinese" => format!("存在相同名称变量: {n}"), @@ -1335,16 +1303,15 @@ impl LowerError { let found = StyledString::new(name, Some(ERR), Some(Attribute::Bold)); Self::new( ErrorCore::new( - errno, - NameError, - loc, + vec![SubMessage::ambiguous_new(loc, None, hint)], switch_lang!( "japanese" => format!("{found}という変数は定義されていません"), "simplified_chinese" => format!("{found}未定义"), "traditional_chinese" => format!("{found}未定義"), "english" => format!("{found} is not defined"), ), - hint, + errno, + NameError, ), input, caused_by, @@ -1359,25 +1326,24 @@ impl LowerError { typ: &Type, ) -> Self { let typ = StyledString::new(&typ.to_string(), Some(ERR), Some(Attribute::Bold)); + let hint = Some(switch_lang!( + "japanese" => format!("恐らくこれはErgコンパイラのバグです、{URL}へ報告してください"), + "simplified_chinese" => format!("这可能是Erg编译器的错误,请报告给{URL}"), + "traditional_chinese" => format!("這可能是Erg編譯器的錯誤,請報告給{URL}"), + "english" => format!("This may be a bug of Erg compiler, please report to {URL}"), + ).into(), + ); Self::new( ErrorCore::new( - errno, - NameError, - loc, + vec![SubMessage::ambiguous_new(loc, None, hint)], switch_lang!( "japanese" => format!("{typ}という型は定義されていません"), "simplified_chinese" => format!("{typ}未定义"), "traditional_chinese" => format!("{typ}未定義"), "english" => format!("Type {typ} is not defined"), ), - Some( - switch_lang!( - "japanese" => format!("恐らくこれはErgコンパイラのバグです、{URL}へ報告してください"), - "simplified_chinese" => format!("这可能是Erg编译器的错误,请报告给{URL}"), - "traditional_chinese" => format!("這可能是Erg編譯器的錯誤,請報告給{URL}"), - "english" => format!("This may be a bug of Erg compiler, please report to {URL}"), - ).into(), - ), + errno, + NameError, ), input, caused_by, @@ -1405,16 +1371,15 @@ impl LowerError { let found = StyledString::new(name, Some(ERR), Some(Attribute::Bold)); Self::new( ErrorCore::new( - errno, - AttributeError, - loc, + vec![SubMessage::ambiguous_new(loc, None, hint)], switch_lang!( "japanese" => format!("{obj_t}型オブジェクトに{found}という属性はありません"), "simplified_chinese" => format!("{obj_t}对象没有属性{found}"), "traditional_chinese" => format!("{obj_t}對像沒有屬性{found}"), "english" => format!("{obj_t} object has no attribute {found}"), ), - hint, + errno, + AttributeError, ), input, caused_by, @@ -1433,6 +1398,7 @@ impl LowerError { similar_name: Option<&str>, ) -> Self { let hint = similar_name.map(|n| { + let n = StyledStr::new(n, Some(HINT), Some(Attribute::Bold)); switch_lang!( "japanese" => format!("似た名前の属性があります: {n}"), "simplified_chinese" => format!("具有相同名称的属性: {n}"), @@ -1444,16 +1410,15 @@ impl LowerError { let found = StyledString::new(name, Some(ERR), Some(Attribute::Bold)); Self::new( ErrorCore::new( - errno, - AttributeError, - loc, + vec![SubMessage::ambiguous_new(loc, None, hint)], switch_lang!( "japanese" => format!("{obj_name}(: {obj_t})に{found}という属性はありません"), "simplified_chinese" => format!("{obj_name}(: {obj_t})没有属性{found}"), "traditional_chinese" => format!("{obj_name}(: {obj_t})沒有屬性{found}"), "english" => format!("{obj_name}(: {obj_t}) has no attribute {found}"), ), - hint, + errno, + AttributeError, ), input, caused_by, @@ -1470,16 +1435,15 @@ impl LowerError { let name = StyledString::new(readable_name(name), Some(WARNING), Some(Attribute::Bold)); Self::new( ErrorCore::new( - errno, - AssignError, - loc, + vec![SubMessage::only_loc(loc)], switch_lang!( "japanese" => format!("変数{name}に複数回代入することはできません"), "simplified_chinese" => format!("不能为变量{name}分配多次"), "traditional_chinese" => format!("不能為變量{name}分配多次"), "english" => format!("variable {name} cannot be assigned more than once"), ), - None, + errno, + AssignError, ), input, caused_by, @@ -1496,16 +1460,15 @@ impl LowerError { let name = StyledString::new(readable_name(name), Some(WARNING), Some(Attribute::Bold)); Self::new( ErrorCore::new( - errno, - UnusedWarning, - loc, + vec![SubMessage::only_loc(loc)], switch_lang!( "japanese" => format!("{name}は使用されていません"), "simplified_chinese" => format!("{name}未使用"), "traditional_chinese" => format!("{name}未使用"), "english" => format!("{name} is not used"), ), - None, + errno, + UnusedWarning, ), input, caused_by, @@ -1520,16 +1483,15 @@ impl LowerError { ); Self::new( ErrorCore::new( - errno, - NameError, - ident.loc(), + vec![SubMessage::only_loc(ident.loc())], switch_lang!( "japanese" => format!("{name}は削除できません"), "simplified_chinese" => format!("{name}不能删除"), "traditional_chinese" => format!("{name}不能刪除"), "english" => format!("{name} cannot be deleted"), ), - None, + errno, + NameError, ), input, caused_by, @@ -1563,16 +1525,15 @@ impl LowerError { let found = StyledString::new(name, Some(ERR), Some(Attribute::Bold)); Self::new( ErrorCore::new( - errno, - VisibilityError, - loc, + vec![SubMessage::only_loc(loc)], switch_lang!( "japanese" => format!("{found}は{visibility}変数です"), "simplified_chinese" => format!("{found}是{visibility}变量",), "traditional_chinese" => format!("{found}是{visibility}變量",), "english" => format!("{found} is {visibility} variable",), ), - None, + errno, + VisibilityError, ), input, caused_by, @@ -1593,11 +1554,16 @@ impl LowerError { Some(WARNING), Some(Attribute::Bold), ); + let hint = + Some(switch_lang!( + "japanese" => "デフォルトでオーバーライドはできません(`Override`デコレータを使用してください)", + "simplified_chinese" => "默认不可重写(请使用`Override`装饰器)", + "traditional_chinese" => "默認不可重寫(請使用`Override`裝飾器)", + "english" => "cannot override by default (use `Override` decorator)", + ).into()); Self::new( ErrorCore::new( - errno, - NameError, - name_loc, + vec![SubMessage::ambiguous_new(name_loc, None, hint)], switch_lang!( "japanese" => format!( "{name}は{superclass}で既に定義されています", @@ -1612,12 +1578,8 @@ impl LowerError { "{name} is already defined in {superclass}", ), ), - Some(switch_lang!( - "japanese" => "デフォルトでオーバーライドはできません(`Override`デコレータを使用してください)", - "simplified_chinese" => "默认不可重写(请使用`Override`装饰器)", - "traditional_chinese" => "默認不可重寫(請使用`Override`裝飾器)", - "english" => "cannot override by default (use `Override` decorator)", - ).into()), + errno, + NameError, ), input, caused_by.into(), @@ -1633,16 +1595,15 @@ impl LowerError { ) -> Self { Self::new( ErrorCore::new( - errno, - InheritanceError, - loc, + vec![SubMessage::only_loc(loc)], switch_lang!( "japanese" => format!("{class}は継承できません"), "simplified_chinese" => format!("{class}不可继承"), "traditional_chinese" => format!("{class}不可繼承"), "english" => format!("{class} is not inheritable"), ), - None, + errno, + InheritanceError, ), input, caused_by, @@ -1658,7 +1619,7 @@ impl LowerError { hint: Option, ) -> Self { Self::new( - ErrorCore::new(errno, IoError, loc, desc, hint), + ErrorCore::new( vec![SubMessage::ambiguous_new(loc, None, hint)], desc, errno, IoError), input, caused_by, ) @@ -1719,16 +1680,15 @@ impl LowerError { ) -> Self { Self::new( ErrorCore::new( - errno, - TypeError, - loc, + vec![SubMessage::only_loc(loc)], switch_lang!( "japanese" => format!("型はトップレベルで定義されなければなりません"), "simplified_chinese" => format!("类型必须在顶层定义"), "traditional_chinese" => format!("類型必須在頂層定義"), "english" => format!("types must be defined at the top level"), ), - None, + errno, + TypeError, ), input, caused_by, @@ -1738,16 +1698,15 @@ impl LowerError { pub fn declare_error(input: Input, errno: usize, loc: Location, caused_by: AtomicStr) -> Self { Self::new( ErrorCore::new( - errno, - SyntaxError, - loc, + vec![SubMessage::only_loc(loc)], switch_lang!( "japanese" => format!("d.erファイル内では宣言、別名定義のみが許可されています"), "simplified_chinese" => format!("在d.er文件中只允许声明和别名定义"), "traditional_chinese" => format!("在d.er文件中只允許聲明和別名定義"), "english" => format!("declarations and alias definitions are only allowed in d.er files"), ), - None, + errno, + SyntaxError, ), input, caused_by, @@ -1772,16 +1731,15 @@ impl LowerError { ); Self::new( ErrorCore::new( - errno, - TypeError, - loc, + vec![SubMessage::ambiguous_new(loc, None, hint)], switch_lang!( "japanese" => format!("{name}の型を{found}にキャストすることはできません"), "simplified_chinese" => format!("{name}的类型无法转换为{found}"), "traditional_chinese" => format!("{name}的類型無法轉換為{found}"), "english" => format!("the type of {name} cannot be cast to {found}"), ), - hint, + errno, + TypeError, ), input, caused_by, diff --git a/compiler/erg_parser/error.rs b/compiler/erg_parser/error.rs index 95d63f01..42048d50 100644 --- a/compiler/erg_parser/error.rs +++ b/compiler/erg_parser/error.rs @@ -3,8 +3,10 @@ //! パーサーが出すエラーを定義 use erg_common::astr::AtomicStr; use erg_common::config::Input; -use erg_common::error::{ErrorCore, ErrorDisplay, ErrorKind::*, Location, MultiErrorDisplay}; -use erg_common::style::{Attribute, Color, StyledStr, StyledString, Theme}; +use erg_common::error::{ + ErrorCore, ErrorDisplay, ErrorKind::*, Location, MultiErrorDisplay, SubMessage, +}; +use erg_common::style::{Attribute, Color, StyledStr, StyledString, THEME}; use erg_common::traits::Stream; use erg_common::{impl_display_and_error, impl_stream_for_wrapper, switch_lang}; @@ -28,62 +30,64 @@ pub struct LexErrors(Vec); impl_stream_for_wrapper!(LexErrors, LexError); +const HINT: Color = THEME.colors.hint; +const ACCENT: Color = THEME.colors.accent; + impl LexError { pub fn new(core: ErrorCore) -> Self { Self(Box::new(core)) } pub fn set_hint>(&mut self, hint: S) { - self.0.hint = Some(hint.into()); + if let Some(sub_msg) = self.0.sub_messages.get_mut(0) { + sub_msg.set_hint(hint) + } } pub fn compiler_bug(errno: usize, loc: Location, fn_name: &str, line: u32) -> Self { const URL: StyledStr = StyledStr::new( "https://github.com/erg-lang/erg", - Some(Color::White), + Some(ACCENT), Some(Attribute::Underline), ); Self::new(ErrorCore::new( - errno, - CompilerSystemError, - loc, + vec![SubMessage::only_loc(loc)], switch_lang!( "japanese" => format!("これはErg compilerのバグです、開発者に報告して下さい ({URL})\n{fn_name}:{line}より発生"), "simplified_chinese" => format!("这是Erg编译器的一个错误,请报告给{URL}\n原因来自: {fn_name}:{line}"), "traditional_chinese" => format!("這是Erg編譯器的一個錯誤,請報告給{URL}\n原因來自: {fn_name}:{line}"), "english" => format!("this is a bug of the Erg compiler, please report it to {URL}\ncaused from: {fn_name}:{line}"), ), - None, + errno, + CompilerSystemError, )) } pub fn feature_error(errno: usize, loc: Location, name: &str) -> Self { Self::new(ErrorCore::new( - errno, - FeatureError, - loc, + vec![SubMessage::only_loc(loc)], switch_lang!( "japanese" => format!("この機能({name})はまだ正式に提供されていません"), "simplified_chinese" => format!("此功能({name})尚未实现"), "traditional_chinese" => format!("此功能({name})尚未實現"), "english" => format!("this feature({name}) is not implemented yet"), ), - None, + errno, + FeatureError, )) } pub fn simple_syntax_error(errno: usize, loc: Location) -> Self { Self::new(ErrorCore::new( - errno, - SyntaxError, - loc, + vec![SubMessage::only_loc(loc)], switch_lang!( "japanese" => "不正な構文です", "simplified_chinese" => "无效的语法", "traditional_chinese" => "無效的語法", "english" => "invalid syntax", ), - None, + errno, + SyntaxError, )) } @@ -93,7 +97,12 @@ impl LexError { desc: S, hint: Option, ) -> Self { - Self::new(ErrorCore::new(errno, SyntaxError, loc, desc, hint)) + Self::new(ErrorCore::new( + vec![SubMessage::ambiguous_new(loc, None, hint)], + desc, + errno, + SyntaxError, + )) } pub fn syntax_warning>( @@ -102,7 +111,12 @@ impl LexError { desc: S, hint: Option, ) -> Self { - Self::new(ErrorCore::new(errno, SyntaxWarning, loc, desc, hint)) + Self::new(ErrorCore::new( + vec![SubMessage::ambiguous_new(loc, None, hint)], + desc, + errno, + SyntaxWarning, + )) } pub fn no_var_error( @@ -112,6 +126,7 @@ impl LexError { similar_name: Option, ) -> Self { let hint = similar_name.map(|n| { + let n = StyledString::new(&n, Some(HINT), Some(Attribute::Bold)); switch_lang!( "japanese" => format!("似た名前の変数があります: {n}"), "simplified_chinese" => format!("存在相同名称变量: {n}"), @@ -122,16 +137,15 @@ impl LexError { }); let name = StyledString::new(name, Some(Color::Red), Some(Attribute::Underline)); Self::new(ErrorCore::new( - errno, - NameError, - loc, + vec![SubMessage::ambiguous_new(loc, None, hint)], switch_lang!( "japanese" => format!("{name}という変数は定義されていません"), "simplified_chinese" => format!("{name}未定义"), "traditional_chinese" => format!("{name}未定義"), "english" => format!("{name} is not defined"), ), - hint, + errno, + NameError, )) } } @@ -164,7 +178,6 @@ pub type DesugaringResult = Result; pub struct ParserRunnerError { pub core: ErrorCore, pub input: Input, - pub theme: Theme, } impl_display_and_error!(ParserRunnerError); @@ -176,9 +189,6 @@ impl ErrorDisplay for ParserRunnerError { fn input(&self) -> &Input { &self.input } - fn theme(&self) -> &Theme { - &self.theme - } fn caused_by(&self) -> &str { "" } @@ -188,8 +198,8 @@ impl ErrorDisplay for ParserRunnerError { } impl ParserRunnerError { - pub const fn new(core: ErrorCore, input: Input, theme: Theme) -> Self { - Self { core, input, theme } + pub const fn new(core: ErrorCore, input: Input) -> Self { + Self { core, input } } } @@ -201,10 +211,10 @@ impl_stream_for_wrapper!(ParserRunnerErrors, ParserRunnerError); impl MultiErrorDisplay for ParserRunnerErrors {} impl ParserRunnerErrors { - pub fn convert(input: &Input, errs: ParseErrors, theme: Theme) -> Self { + pub fn convert(input: &Input, errs: ParseErrors) -> Self { Self( errs.into_iter() - .map(|err| ParserRunnerError::new(*err.0, input.clone(), theme)) + .map(|err| ParserRunnerError::new(*err.0, input.clone())) .collect(), ) } From 4ae81aa05ea6c1aae6f401eab0cec98e46c835b6 Mon Sep 17 00:00:00 2001 From: GreasySlug <9619abgoni@gmail.com> Date: Fri, 18 Nov 2022 12:31:44 +0900 Subject: [PATCH 05/23] Add: `Location` moved to `ErrorCore` --- compiler/erg_common/error.rs | 9 ++-- .../context/initialize/const_func.rs | 12 +++++ compiler/erg_compiler/context/inquire.rs | 2 + compiler/erg_compiler/error.rs | 53 ++++++++++++++++++- compiler/erg_compiler/ty/deserialize.rs | 1 + compiler/erg_parser/error.rs | 9 +++- 6 files changed, 80 insertions(+), 6 deletions(-) diff --git a/compiler/erg_common/error.rs b/compiler/erg_common/error.rs index ee0aa033..9946385f 100644 --- a/compiler/erg_common/error.rs +++ b/compiler/erg_common/error.rs @@ -501,6 +501,7 @@ pub struct ErrorCore { pub main_message: AtomicStr, pub errno: usize, pub kind: ErrorKind, + pub loc: Location, theme: Theme, } @@ -510,26 +511,25 @@ impl ErrorCore { main_message: S, errno: usize, kind: ErrorKind, + loc: Location, ) -> Self { Self { sub_messages, main_message: main_message.into(), errno, kind, + loc, theme: THEME, } } - pub fn sub_messages(&self) -> &Vec { - &self.sub_messages - } - pub fn dummy(errno: usize) -> Self { Self::new( vec![SubMessage::only_loc(Location::Line(errno as usize))], "", errno, DummyError, + Location::Line(errno as usize), ) } @@ -555,6 +555,7 @@ impl ErrorCore { &m_msg, errno, CompilerSystemError, + loc, ) } diff --git a/compiler/erg_compiler/context/initialize/const_func.rs b/compiler/erg_compiler/context/initialize/const_func.rs index b0eb198a..cd814e20 100644 --- a/compiler/erg_compiler/context/initialize/const_func.rs +++ b/compiler/erg_compiler/context/initialize/const_func.rs @@ -27,6 +27,7 @@ pub fn class_func(mut args: ValueArgs, ctx: &Context) -> EvalValueResult EvalValueResult EvalValueResult EvalValueResult EvalValueResult< AtomicStr::from(format!("{CLASS_ERR} is not passed")), line!() as usize, ErrorKind::KeyError, + Location::Unknown, ) })?; match class { @@ -118,6 +123,7 @@ pub fn trait_func(mut args: ValueArgs, ctx: &Context) -> EvalValueResult EvalValueResult EvalValueResult EvalValueResult EvalValueResult< )), line!() as usize, ErrorKind::IndexError, + Location::Unknown, ) .into()) } @@ -219,6 +229,7 @@ pub fn __dict_getitem__(mut args: ValueArgs, ctx: &Context) -> EvalValueResult EvalValueResult AtomicStr::from(format!("Index out of range: {}", index)), line!() as usize, ErrorKind::IndexError, + Location::Unknown, ) .into()) } diff --git a/compiler/erg_compiler/context/inquire.rs b/compiler/erg_compiler/context/inquire.rs index 4d5b24ed..eb998803 100644 --- a/compiler/erg_compiler/context/inquire.rs +++ b/compiler/erg_compiler/context/inquire.rs @@ -771,6 +771,7 @@ impl Context { e.core.main_message, e.core.errno, e.core.kind, + e.core.loc, ); TyCheckError::new(core, self.cfg.input.clone(), e.caused_by) }) @@ -818,6 +819,7 @@ impl Context { e.core.main_message, e.core.errno, e.core.kind, + e.core.loc, ); TyCheckError::new(core, self.cfg.input.clone(), e.caused_by) }) diff --git a/compiler/erg_compiler/error.rs b/compiler/erg_compiler/error.rs index bba20121..1b45e30e 100644 --- a/compiler/erg_compiler/error.rs +++ b/compiler/erg_compiler/error.rs @@ -177,6 +177,7 @@ impl CompileError { ), errno, CompilerSystemError, + loc, ), input, "".into(), @@ -209,6 +210,7 @@ impl CompileError { ), 0, CompilerSystemError, + loc, ), input, "".into(), @@ -227,6 +229,7 @@ impl CompileError { ), 0, FeatureError, + loc, ), input, caused_by, @@ -245,6 +248,7 @@ impl CompileError { ), 0, SystemExit, + Location::Unknown, ), Input::Dummy, "".into(), @@ -285,6 +289,7 @@ impl TyCheckError { ), errno, CompilerSystemError, + loc, ), input, "".into(), @@ -310,6 +315,7 @@ impl TyCheckError { ), errno, TypeError, + loc, ), input, caused_by, @@ -339,6 +345,7 @@ impl TyCheckError { ), errno, NotImplementedError, + callee.loc(), ), input, caused_by, @@ -385,6 +392,7 @@ impl TyCheckError { ), errno, TypeError, + loc, ), input, caused_by, @@ -413,6 +421,7 @@ impl TyCheckError { ), errno, TypeError, + loc, ), input, caused_by, @@ -438,6 +447,7 @@ impl TyCheckError { ), errno, NameError, + loc, ), input, caused_by, @@ -465,6 +475,7 @@ impl TyCheckError { ), errno, TypeError, + loc, ), input, caused_by, @@ -489,6 +500,7 @@ impl TyCheckError { ), errno, TypeError, + loc, ), input, caused_by, @@ -513,6 +525,7 @@ impl TyCheckError { ), errno, TypeError, + loc, ), input, caused_by, @@ -587,6 +600,7 @@ passed keyword args: {kw_args_len}" ), errno, TypeError, + loc, ), input, caused_by, @@ -619,6 +633,7 @@ passed keyword args: {kw_args_len}" ), errno, TypeError, + loc, ), input, caused_by, @@ -646,6 +661,7 @@ passed keyword args: {kw_args_len}" ), errno, TypeError, + loc, ), input, caused_by, @@ -673,6 +689,7 @@ passed keyword args: {kw_args_len}" ), errno, TypeError, + loc, ), input, caused_by, @@ -700,6 +717,7 @@ passed keyword args: {kw_args_len}" ), errno, TypeError, + loc, ), input, caused_by, @@ -727,6 +745,7 @@ passed keyword args: {kw_args_len}" ), errno, TypeError, + loc, ), input, caused_by, @@ -754,6 +773,7 @@ passed keyword args: {kw_args_len}" ), errno, TypeError, + loc, ), input, caused_by, @@ -780,6 +800,7 @@ passed keyword args: {kw_args_len}" ), errno, TypeError, + Location::Unknown, ), input, caused_by, @@ -805,6 +826,7 @@ passed keyword args: {kw_args_len}" ), errno, TypeError, + loc, ), input, caused_by, @@ -831,6 +853,7 @@ passed keyword args: {kw_args_len}" ), errno, TypeError, + loc, ), input, caused_by, @@ -865,6 +888,7 @@ passed keyword args: {kw_args_len}" ), errno, MethodError, + loc, ), input, caused_by, @@ -897,6 +921,7 @@ passed keyword args: {kw_args_len}" ), errno, TypeError, + loc, ), input, caused_by, @@ -925,6 +950,7 @@ passed keyword args: {kw_args_len}" ), errno, TypeError, + Location::Unknown, ), input, caused_by, @@ -953,6 +979,7 @@ passed keyword args: {kw_args_len}" ), errno, TypeError, + Location::Unknown, ), input, caused_by, @@ -978,6 +1005,7 @@ passed keyword args: {kw_args_len}" ), errno, TypeError, + loc, ), input, caused_by, @@ -1010,6 +1038,7 @@ passed keyword args: {kw_args_len}" ), errno, TypeError, + expr.loc(), ), input, caused_by, @@ -1041,6 +1070,7 @@ impl EvalError { ), errno, NotConstExpr, + loc, ), input, caused_by, @@ -1064,6 +1094,7 @@ impl EvalError { ), errno, SyntaxError, + loc, ), input, caused_by, @@ -1092,6 +1123,7 @@ impl EffectError { ), errno, HasEffect, + expr.loc(), ), input, caused_by.into(), @@ -1124,6 +1156,7 @@ impl EffectError { ), errno, HasEffect, + sig.loc(), ), input, caused_by.into(), @@ -1167,6 +1200,7 @@ impl OwnershipError { ), errno, MoveError, + name_loc, ), input, caused_by.into(), @@ -1196,6 +1230,7 @@ impl LowerError { desc.into(), errno, SyntaxError, + loc, ), input, caused_by, @@ -1221,6 +1256,7 @@ impl LowerError { ), errno, NameError, + loc, ), input, caused_by, @@ -1246,6 +1282,7 @@ impl LowerError { ), errno, NameError, + loc, ), input, caused_by, @@ -1275,6 +1312,7 @@ impl LowerError { ), errno, TypeError, + loc, ), input, caused_by, @@ -1312,6 +1350,7 @@ impl LowerError { ), errno, NameError, + loc, ), input, caused_by, @@ -1344,6 +1383,7 @@ impl LowerError { ), errno, NameError, + loc, ), input, caused_by, @@ -1380,6 +1420,7 @@ impl LowerError { ), errno, AttributeError, + loc, ), input, caused_by, @@ -1419,6 +1460,7 @@ impl LowerError { ), errno, AttributeError, + loc, ), input, caused_by, @@ -1444,6 +1486,7 @@ impl LowerError { ), errno, AssignError, + loc, ), input, caused_by, @@ -1469,6 +1512,7 @@ impl LowerError { ), errno, UnusedWarning, + loc, ), input, caused_by, @@ -1492,6 +1536,7 @@ impl LowerError { ), errno, NameError, + ident.loc(), ), input, caused_by, @@ -1534,6 +1579,7 @@ impl LowerError { ), errno, VisibilityError, + loc, ), input, caused_by, @@ -1580,6 +1626,7 @@ impl LowerError { ), errno, NameError, + name_loc, ), input, caused_by.into(), @@ -1604,6 +1651,7 @@ impl LowerError { ), errno, InheritanceError, + loc, ), input, caused_by, @@ -1619,7 +1667,7 @@ impl LowerError { hint: Option, ) -> Self { Self::new( - ErrorCore::new( vec![SubMessage::ambiguous_new(loc, None, hint)], desc, errno, IoError), + ErrorCore::new( vec![SubMessage::ambiguous_new(loc, None, hint)], desc, errno, IoError, loc), input, caused_by, ) @@ -1689,6 +1737,7 @@ impl LowerError { ), errno, TypeError, + loc, ), input, caused_by, @@ -1707,6 +1756,7 @@ impl LowerError { ), errno, SyntaxError, + loc, ), input, caused_by, @@ -1740,6 +1790,7 @@ impl LowerError { ), errno, TypeError, + loc, ), input, caused_by, diff --git a/compiler/erg_compiler/ty/deserialize.rs b/compiler/erg_compiler/ty/deserialize.rs index 679a7bff..7820205a 100644 --- a/compiler/erg_compiler/ty/deserialize.rs +++ b/compiler/erg_compiler/ty/deserialize.rs @@ -44,6 +44,7 @@ impl From for ErrorCore { err.desc, err.errno, ErrorKind::ImportError, + Location::Unknown, ) } } diff --git a/compiler/erg_parser/error.rs b/compiler/erg_parser/error.rs index 42048d50..75810f79 100644 --- a/compiler/erg_parser/error.rs +++ b/compiler/erg_parser/error.rs @@ -30,6 +30,7 @@ pub struct LexErrors(Vec); impl_stream_for_wrapper!(LexErrors, LexError); +const ERR: Color = THEME.colors.error; const HINT: Color = THEME.colors.hint; const ACCENT: Color = THEME.colors.accent; @@ -60,6 +61,7 @@ impl LexError { ), errno, CompilerSystemError, + loc, )) } @@ -74,6 +76,7 @@ impl LexError { ), errno, FeatureError, + loc, )) } @@ -88,6 +91,7 @@ impl LexError { ), errno, SyntaxError, + loc, )) } @@ -102,6 +106,7 @@ impl LexError { desc, errno, SyntaxError, + loc, )) } @@ -116,6 +121,7 @@ impl LexError { desc, errno, SyntaxWarning, + loc, )) } @@ -135,7 +141,7 @@ impl LexError { ) .into() }); - let name = StyledString::new(name, Some(Color::Red), Some(Attribute::Underline)); + let name = StyledString::new(name, Some(ERR), Some(Attribute::Underline)); Self::new(ErrorCore::new( vec![SubMessage::ambiguous_new(loc, None, hint)], switch_lang!( @@ -146,6 +152,7 @@ impl LexError { ), errno, NameError, + loc, )) } } From 899e8ead033e3b66c6df2e871349ee8f30ae731b Mon Sep 17 00:00:00 2001 From: GreasySlug <9619abgoni@gmail.com> Date: Fri, 18 Nov 2022 12:41:19 +0900 Subject: [PATCH 06/23] Add: `fmt_header` --- compiler/erg_common/error.rs | 53 ++++++++++++++++++++++++------------ 1 file changed, 35 insertions(+), 18 deletions(-) diff --git a/compiler/erg_common/error.rs b/compiler/erg_common/error.rs index 9946385f..57398b0a 100644 --- a/compiler/erg_common/error.rs +++ b/compiler/erg_common/error.rs @@ -373,14 +373,16 @@ fn format_context( context.push_str(&" ".repeat(col_end - 1)); context.push_str_with_color(&chars.left_bottom_line(), err_color); context.push_str(msg); + context.push_str("\n") } if let Some(hint) = hint { context.push_str_with_color(&offset, gutter_color); context.push_str(&" ".repeat(col_end - 1)); context.push_str_with_color(&chars.left_bottom_line(), err_color); context.push_str(hint); + context.push_str("\n") } - context.to_string() + context.to_string() + "\n" } #[derive(Debug, Clone, PartialEq, Eq, Hash)] @@ -475,7 +477,6 @@ impl SubMessage { let mut cxt = StyledStrings::default(); cxt.push_str_with_color(&format!(" {lineno} {} ", vbar), gutter_color); cxt.push_str(&code); - cxt.push_str("\n"); cxt.to_string() } Location::Unknown => match e.input() { @@ -559,8 +560,27 @@ impl ErrorCore { ) } - pub fn fmt_main_message(&self, kind: StyledString) -> String { - format!("{}\n{}\n\n", kind, self.main_message) + pub fn fmt_header(&self, kind: StyledString, caused_by: &str, input: &str) -> String { + let loc = match self.loc { + Location::Range { + ln_begin, ln_end, .. + } if ln_begin == ln_end => format!(", line {ln_begin}"), + Location::Range { + ln_begin, ln_end, .. + } + | Location::LineRange(ln_begin, ln_end) => format!(", line {ln_begin}..{ln_end}"), + Location::Line(lineno) => format!(", line {lineno}"), + Location::Unknown => "".to_string(), + }; + format!("{kind}: File {input}{loc}{caused_by}\n",) + } + + pub fn fmt_main_message(&self, kind: StyledString, caused_by: &str, input: &str) -> String { + format!( + "{}{}\n\n", + self.fmt_header(kind, caused_by, input), + self.main_message + ) } } @@ -570,21 +590,17 @@ impl ErrorCore { /// {.loc (as line)}| {src} /// {pointer} /// {.kind}: {.desc} -/// /// {.hint} -/// /// ``` /// /// example: /// ```txt /// Error[#2223]: File , line 1, in +/// SyntaxError: cannot assign to 100 /// /// 1 | 100 = i /// --- -/// ╰─ SyntaxError: cannot assign to 100 -/// -/// hint: hint message here -/// +/// ╰─ hint: hint message here /// ``` pub trait ErrorDisplay { fn core(&self) -> &ErrorCore; @@ -624,13 +640,11 @@ pub trait ErrorDisplay { Some(color), Some(Attribute::Bold), ); - let sub_messages = self.core().sub_messages(); let mut msg = String::new(); - msg += &core.fmt_main_message(kind); - for sub_msg in sub_messages { - msg += &sub_msg.format_code_and_pointer(self, color, gutter_color, mark, chars) + msg += &core.fmt_main_message(kind, self.caused_by(), self.input().enclosed_name()); + for sub_msg in &self.core().sub_messages { + msg += &sub_msg.format_code_and_pointer(self, color, gutter_color, mark, chars); } - msg += "\n"; msg } @@ -650,9 +664,12 @@ pub trait ErrorDisplay { Some(color), Some(Attribute::Bold), ); - writeln!(f, "{}", core.fmt_main_message(kind))?; - let sub_messages = self.core().sub_messages(); - for sub_msg in sub_messages { + writeln!( + f, + "{}\n", + core.fmt_main_message(kind, self.caused_by(), self.input().enclosed_name()) + )?; + for sub_msg in &self.core().sub_messages { writeln!( f, "{}", From 12ccd6ac2710e724c936555a381e11ab9de29b4f Mon Sep 17 00:00:00 2001 From: GreasySlug <9619abgoni@gmail.com> Date: Fri, 18 Nov 2022 21:56:09 +0900 Subject: [PATCH 07/23] Clean: display format --- compiler/erg_common/error.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler/erg_common/error.rs b/compiler/erg_common/error.rs index 57398b0a..fb70e589 100644 --- a/compiler/erg_common/error.rs +++ b/compiler/erg_common/error.rs @@ -572,12 +572,12 @@ impl ErrorCore { Location::Line(lineno) => format!(", line {lineno}"), Location::Unknown => "".to_string(), }; - format!("{kind}: File {input}{loc}{caused_by}\n",) + format!("{kind}: File {input}{loc}{caused_by}",) } pub fn fmt_main_message(&self, kind: StyledString, caused_by: &str, input: &str) -> String { format!( - "{}{}\n\n", + "{}\n{}\n\n", self.fmt_header(kind, caused_by, input), self.main_message ) @@ -666,11 +666,11 @@ pub trait ErrorDisplay { ); writeln!( f, - "{}\n", + "{}", core.fmt_main_message(kind, self.caused_by(), self.input().enclosed_name()) )?; for sub_msg in &self.core().sub_messages { - writeln!( + write!( f, "{}", &sub_msg.format_code_and_pointer(self, color, gutter_color, mark, chars) From 088f985ee3642c1851c6dd4a09c946856d5acaab Mon Sep 17 00:00:00 2001 From: GreasySlug <9619abgoni@gmail.com> Date: Sat, 19 Nov 2022 15:44:19 +0900 Subject: [PATCH 08/23] Change: header divided into kind and main_msg --- compiler/erg_common/error.rs | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/compiler/erg_common/error.rs b/compiler/erg_common/error.rs index fb70e589..b614cbea 100644 --- a/compiler/erg_common/error.rs +++ b/compiler/erg_common/error.rs @@ -464,6 +464,7 @@ impl SubMessage { cxt.push_str(&" ".repeat(lineno.to_string().len() + 3)); // +3 means ` | ` cxt.push_str_with_color(&mark.repeat(cmp::max(1, codes[i].len())), gutter_color) } + cxt.push_str("\n\n"); cxt.to_string() } Location::Line(lineno) => { @@ -477,6 +478,7 @@ impl SubMessage { let mut cxt = StyledStrings::default(); cxt.push_str_with_color(&format!(" {lineno} {} ", vbar), gutter_color); cxt.push_str(&code); + cxt.push_str("\n\n"); cxt.to_string() } Location::Unknown => match e.input() { @@ -487,6 +489,7 @@ impl SubMessage { let mut cxt = StyledStrings::default(); cxt.push_str_with_color(&format!(" ? {}", vbar), gutter_color); cxt.push_str(&other.reread()); + cxt.push_str("\n\n"); cxt.to_string() } }, @@ -641,10 +644,13 @@ pub trait ErrorDisplay { Some(Attribute::Bold), ); let mut msg = String::new(); - msg += &core.fmt_main_message(kind, self.caused_by(), self.input().enclosed_name()); - for sub_msg in &self.core().sub_messages { + msg += &core.fmt_header(kind, self.caused_by(), self.input().enclosed_name()); + msg += "\n\n"; + for sub_msg in &core.sub_messages { msg += &sub_msg.format_code_and_pointer(self, color, gutter_color, mark, chars); } + msg += &core.main_message; + msg += "\n\n"; msg } @@ -664,18 +670,19 @@ pub trait ErrorDisplay { Some(color), Some(Attribute::Bold), ); - writeln!( + write!( f, - "{}", - core.fmt_main_message(kind, self.caused_by(), self.input().enclosed_name()) + "{}\n\n", + core.fmt_header(kind, self.caused_by(), self.input().enclosed_name()) )?; - for sub_msg in &self.core().sub_messages { + for sub_msg in &core.sub_messages { write!( f, "{}", &sub_msg.format_code_and_pointer(self, color, gutter_color, mark, chars) )?; } + write!(f, "{}\n\n", core.main_message)?; if let Some(inner) = self.ref_inner() { inner.format(f) } else { From d64712c7a710d731f4b7671f327f685e4fe82405 Mon Sep 17 00:00:00 2001 From: GreasySlug <9619abgoni@gmail.com> Date: Sun, 20 Nov 2022 09:34:26 +0900 Subject: [PATCH 09/23] Change: Option to Vec --- compiler/erg_common/error.rs | 20 +- compiler/erg_compiler/context/inquire.rs | 4 +- compiler/erg_compiler/error.rs | 564 ++++++++++++++++------- compiler/erg_parser/error.rs | 6 +- 4 files changed, 402 insertions(+), 192 deletions(-) diff --git a/compiler/erg_common/error.rs b/compiler/erg_common/error.rs index b614cbea..9f59732c 100644 --- a/compiler/erg_common/error.rs +++ b/compiler/erg_common/error.rs @@ -327,7 +327,7 @@ fn format_context( chars: &Characters, // kinds of error for specify the color mark: char, - sub_msg: Option<&AtomicStr>, + sub_msg: &[AtomicStr], hint: Option<&AtomicStr>, ) -> String { let mark = mark.to_string(); @@ -368,7 +368,7 @@ fn format_context( } context.push_str("\n"); } - if let Some(msg) = sub_msg { + for msg in sub_msg { context.push_str_with_color(&offset, gutter_color); context.push_str(&" ".repeat(col_end - 1)); context.push_str_with_color(&chars.left_bottom_line(), err_color); @@ -388,27 +388,19 @@ fn format_context( #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct SubMessage { pub loc: Location, - msg: Option, + msg: Vec, hint: Option, } impl SubMessage { - pub fn new>(loc: Location, msg: S, hint: S) -> Self { - Self { - loc, - msg: Some(msg.into()), - hint: Some(hint.into()), - } - } - - pub fn ambiguous_new(loc: Location, msg: Option, hint: Option) -> Self { + pub fn ambiguous_new(loc: Location, msg: Vec, hint: Option) -> Self { Self { loc, msg, hint } } pub fn only_loc(loc: Location) -> Self { Self { loc, - msg: None, + msg: Vec::new(), hint: None, } } @@ -445,7 +437,7 @@ impl SubMessage { gutter_color, chars, mark, - self.msg.as_ref(), + &self.msg, self.hint.as_ref(), ), Location::LineRange(ln_begin, ln_end) => { diff --git a/compiler/erg_compiler/context/inquire.rs b/compiler/erg_compiler/context/inquire.rs index eb998803..4e9fc4db 100644 --- a/compiler/erg_compiler/context/inquire.rs +++ b/compiler/erg_compiler/context/inquire.rs @@ -762,7 +762,7 @@ impl Context { sub_msges.push(SubMessage::ambiguous_new( // HACK: dname.loc()はダミーLocationしか返さないので、エラーならop.loc()で上書きする bin.loc(), - None, + vec![], sub_msg.get_hint(), )); } @@ -810,7 +810,7 @@ impl Context { for sub_msg in e.core.sub_messages { sub_msges.push(SubMessage::ambiguous_new( unary.loc(), - None, + vec![], sub_msg.get_hint(), )); } diff --git a/compiler/erg_compiler/error.rs b/compiler/erg_compiler/error.rs index 1b45e30e..2f34dcda 100644 --- a/compiler/erg_compiler/error.rs +++ b/compiler/erg_compiler/error.rs @@ -6,7 +6,7 @@ use erg_common::error::{ ErrorCore, ErrorDisplay, ErrorKind::*, Location, MultiErrorDisplay, SubMessage, }; use erg_common::set::Set; -use erg_common::style::{Attribute, Color, StyledStr, StyledString, THEME}; +use erg_common::style::{Attribute, Color, StyledStr, StyledString, StyledStrings, THEME}; use erg_common::traits::{Locational, Stream}; use erg_common::vis::Visibility; use erg_common::{ @@ -259,7 +259,7 @@ impl CompileError { pub type TyCheckError = CompileError; const ERR: Color = THEME.colors.error; -const WARNING: Color = THEME.colors.warning; +const WARN: Color = THEME.colors.warning; const HINT: Color = THEME.colors.hint; impl TyCheckError { @@ -376,19 +376,38 @@ impl TyCheckError { }; let name = StyledString::new( &format!("{}{}", name, ord), - Some(WARNING), + Some(WARN), Some(Attribute::Bold), ); - let expect = StyledString::new(&format!("{}", expect), Some(HINT), Some(Attribute::Bold)); - let found = StyledString::new(&format!("{}", found), Some(ERR), Some(Attribute::Bold)); + let mut expct = StyledStrings::default(); + switch_lang!( + "japanese" => expct.push_str("予期した型: "), + "simplified_chinese" =>expct.push_str("预期: "), + "traditional_chinese" => expct.push_str("預期: "), + "english" => expct.push_str("expected: "), + ); + expct.push_str_with_color_and_attribute(&format!("{}", expect), HINT, Attribute::Bold); + + let mut fnd = StyledStrings::default(); + switch_lang!( + "japanese" => fnd.push_str("与えられた型: "), + "simplified_chinese" => fnd.push_str("但找到: "), + "traditional_chinese" => fnd.push_str("但找到: "), + "english" =>fnd.push_str("but found: "), + ); + fnd.push_str_with_color_and_attribute(&format!("{}", found), ERR, Attribute::Bold); Self::new( ErrorCore::new( - vec![SubMessage::ambiguous_new(loc, None, hint)], + vec![SubMessage::ambiguous_new( + loc, + vec![expct.into(), fnd.into()], + hint, + )], switch_lang!( - "japanese" => format!("{name}の型が違います\n\n予期した型: {expect}\n与えられた型: {found}{}", fmt_option_map!(pre "\n与えられた型の単一化候補: ", candidates, |x: &Set| x.folded_display())), - "simplified_chinese" => format!("{name}的类型不匹配\n\n预期: {expect}\n但找到: {found}{}", fmt_option_map!(pre "\n某一类型的统一候选: ", candidates, |x: &Set| x.folded_display())), - "traditional_chinese" => format!("{name}的類型不匹配\n\n預期: {expect}\n但找到: {found}{}", fmt_option_map!(pre "\n某一類型的統一候選: ", candidates, |x: &Set| x.folded_display())), - "english" => format!("the type of {name} is mismatched\n\nexpected: {expect}\nbut found: {found}{}", fmt_option_map!(pre "\nunification candidates of a given type: ", candidates, |x: &Set| x.folded_display())), + "japanese" => format!("{name}の型が違います{}", fmt_option_map!(pre "\n与えられた型の単一化候補: ", candidates, |x: &Set| x.folded_display())), + "simplified_chinese" => format!("{name}的类型不匹配{}", fmt_option_map!(pre "\n某一类型的统一候选: ", candidates, |x: &Set| x.folded_display())), + "traditional_chinese" => format!("{name}的類型不匹配{}", fmt_option_map!(pre "\n某一類型的統一候選: ", candidates, |x: &Set| x.folded_display())), + "english" => format!("the type of {name} is mismatched{}", fmt_option_map!(pre "\nunification candidates of a given type: ", candidates, |x: &Set| x.folded_display())), ), errno, TypeError, @@ -408,16 +427,36 @@ impl TyCheckError { expect: &Type, found: &Type, ) -> Self { - let expect = StyledString::new(&format!("{}", expect), Some(HINT), Some(Attribute::Bold)); - let found = StyledString::new(&format!("{}", found), Some(ERR), Some(Attribute::Bold)); + let mut expct = StyledStrings::default(); + switch_lang!( + "japanese" => expct.push_str("予期した型: "), + "simplified_chinese" =>expct.push_str("预期: "), + "traditional_chinese" => expct.push_str("預期: "), + "english" => expct.push_str("expected: "), + ); + expct.push_str_with_color_and_attribute(&format!("{}", expect), HINT, Attribute::Bold); + + let mut fnd = StyledStrings::default(); + switch_lang!( + "japanese" => fnd.push_str("与えられた型: "), + "simplified_chinese" => fnd.push_str("但找到: "), + "traditional_chinese" => fnd.push_str("但找到: "), + "english" =>fnd.push_str("but found: "), + ); + fnd.push_str_with_color_and_attribute(&format!("{}", found), ERR, Attribute::Bold); + Self::new( ErrorCore::new( - vec![SubMessage::only_loc(loc)], + vec![SubMessage::ambiguous_new( + loc, + vec![expct.into(), fnd.into()], + None, + )], switch_lang!( - "japanese" => format!("{name}の戻り値の型が違います\n\n予期した型: {expect}\n与えられた型: {found}"), - "simplified_chinese" => format!("{name}的返回类型不匹配\n\n预期: {expect}\n但找到: {found}"), - "traditional_chinese" => format!("{name}的返回類型不匹配\n\n預期: {expect}\n但找到: {found}"), - "english" => format!("the return type of {name} is mismatched\n\nexpected: {expect}\nbut found: {found}"), + "japanese" => format!("{name}の戻り値の型が違います"), + "simplified_chinese" => format!("{name}的返回类型不匹配"), + "traditional_chinese" => format!("{name}的返回類型不匹配"), + "english" => format!("the return type of {name} is mismatched"), ), errno, TypeError, @@ -462,16 +501,32 @@ impl TyCheckError { expect: usize, found: usize, ) -> Self { - let expect = StyledString::new(&format!("{}", expect), Some(HINT), Some(Attribute::Bold)); - let found = StyledString::new(&format!("{}", found), Some(ERR), Some(Attribute::Bold)); + let mut expct = StyledStrings::default(); + switch_lang!( + "japanese" => expct.push_str("予期した個数: "), + "simplified_chinese" =>expct.push_str("预期: "), + "traditional_chinese" => expct.push_str("預期: "), + "english" => expct.push_str("expected: "), + ); + expct.push_str_with_color_and_attribute(&format!("{}", expect), HINT, Attribute::Bold); + + let mut fnd = StyledStrings::default(); + switch_lang!( + "japanese" => fnd.push_str("与えられた個数: "), + "simplified_chinese" => fnd.push_str("但找到: "), + "traditional_chinese" => fnd.push_str("但找到: "), + "english" =>fnd.push_str("but found: "), + ); + fnd.push_str_with_color_and_attribute(&format!("{}", found), ERR, Attribute::Bold); + Self::new( ErrorCore::new( vec![SubMessage::only_loc(loc)], switch_lang!( - "japanese" => format!("ポジショナル引数の数が違います\n\n予期した個数: {expect}\n与えられた個数: {found}"), - "simplified_chinese" => format!("正则参数的数量不匹配\n\n预期: {expect}\n但找到: {found}"), - "traditional_chinese" => format!("正則參數的數量不匹配\n\n預期: {expect}\n但找到: {found}"), - "english" => format!("the number of positional arguments is mismatched\n\nexpected: {expect}\nbut found: {found}"), + "japanese" => format!("ポジショナル引数の数が違います"), + "simplified_chinese" => format!("正则参数的数量不匹配"), + "traditional_chinese" => format!("正則參數的數量不匹配"), + "english" => format!("the number of positional arguments is mismatched"), ), errno, TypeError, @@ -580,9 +635,9 @@ impl TyCheckError { ), "simplified_chinese" => format!("传递给{name}的参数过多 -: {expect} -: {pos_args_len} -: {kw_args_len}" +总的预期参数: {expect} +通过的位置参数: {pos_args_len} +通过了关键字参数: {kw_args_len}" ), "traditional_chinese" => format!("傳遞給{name}的參數過多 @@ -617,11 +672,8 @@ passed keyword args: {kw_args_len}" missing_params: Vec, ) -> Self { let name = readable_name(callee_name); - let vec_cxt = StyledString::new( - &fmt_vec(&missing_params), - Some(WARNING), - Some(Attribute::Bold), - ); + let vec_cxt = + StyledString::new(&fmt_vec(&missing_params), Some(WARN), Some(Attribute::Bold)); Self::new( ErrorCore::new( vec![SubMessage::only_loc(loc)], @@ -704,16 +756,34 @@ passed keyword args: {kw_args_len}" loc: Location, caused_by: AtomicStr, ) -> Self { - let lhs_t = StyledString::new(&format!("{}", lhs_t), Some(WARNING), Some(Attribute::Bold)); - let rhs_t = StyledString::new(&format!("{}", rhs_t), Some(WARNING), Some(Attribute::Bold)); + let mut lhs_typ = StyledStrings::default(); + switch_lang!( + "japanese" => lhs_typ.push_str("左辺: "), + "simplified_chinese" => lhs_typ.push_str("左边: "), + "traditional_chinese" => lhs_typ.push_str("左邊: "), + "english" => lhs_typ.push_str("lhs: "), + ); + lhs_typ.push_str_with_color_and_attribute(&format!("{}", lhs_t), WARN, Attribute::Bold); + let mut rhs_typ = StyledStrings::default(); + switch_lang!( + "japanese" => rhs_typ.push_str("右辺: "), + "simplified_chinese" => rhs_typ.push_str("右边: "), + "traditional_chinese" => rhs_typ.push_str("右邊: "), + "english" => rhs_typ.push_str("rhs: "), + ); + rhs_typ.push_str_with_color_and_attribute(&format!("{}", rhs_t), WARN, Attribute::Bold); Self::new( ErrorCore::new( - vec![SubMessage::only_loc(loc)], + vec![SubMessage::ambiguous_new( + loc, + vec![lhs_typ.into(), rhs_typ.into()], + None, + )], switch_lang!( - "japanese" => format!("型の単一化に失敗しました\n\n左辺: {lhs_t}\n右辺: {rhs_t}"), - "simplified_chinese" => format!("类型统一失败\n\n左边: {lhs_t}\n右边: {rhs_t}"), - "traditional_chinese" => format!("類型統一失敗\n\n左邊: {lhs_t}\n右邊: {rhs_t}"), - "english" => format!("unification failed\n\nlhs: {lhs_t}\nrhs: {rhs_t}"), + "japanese" => format!("型の単一化に失敗しました"), + "simplified_chinese" => format!("类型统一失败"), + "traditional_chinese" => format!("類型統一失敗"), + "english" => format!("unification failed"), ), errno, TypeError, @@ -732,8 +802,8 @@ passed keyword args: {kw_args_len}" loc: Location, caused_by: AtomicStr, ) -> Self { - let lhs_t = StyledString::new(&format!("{}", lhs_t), Some(WARNING), Some(Attribute::Bold)); - let rhs_t = StyledString::new(&format!("{}", rhs_t), Some(WARNING), Some(Attribute::Bold)); + let lhs_t = StyledString::new(&format!("{}", lhs_t), Some(WARN), Some(Attribute::Bold)); + let rhs_t = StyledString::new(&format!("{}", rhs_t), Some(WARN), Some(Attribute::Bold)); Self::new( ErrorCore::new( vec![SubMessage::only_loc(loc)], @@ -760,16 +830,36 @@ passed keyword args: {kw_args_len}" loc: Location, caused_by: AtomicStr, ) -> Self { - let sub_t = StyledString::new(&format!("{}", sub_t), Some(WARNING), Some(Attribute::Bold)); - let sup_t = StyledString::new(&format!("{}", sup_t), Some(WARNING), Some(Attribute::Bold)); + let mut sub_type = StyledStrings::default(); + switch_lang!( + "japanese" => sub_type.push_str("部分型: "), + "simplified_chinese" => sub_type.push_str("超类型: "), + "simplified_chinese" =>sub_type.push_str("超類型: "), + "english" => sub_type.push_str("super type: "), + ); + sub_type.push_str_with_color(&format!("{}", sub_t), WARN); + + let mut sup_type = StyledStrings::default(); + switch_lang!( + "japanese" => sup_type.push_str("汎化型: "), + "simplified_chinese" => sup_type.push_str("超类型: "), + "simplified_chinese" => sup_type.push_str("超類型: "), + "english" =>sup_type.push_str("super type: "), + ); + sup_type.push_str_with_color(&format!("{}", sup_t), WARN); + Self::new( ErrorCore::new( - vec![SubMessage::only_loc(loc)], + vec![SubMessage::ambiguous_new( + loc, + vec![sub_type.into(), sup_type.into()], + None, + )], switch_lang!( - "japanese" => format!("この式の部分型制約を満たせません\n\nサブタイプ: {sub_t}\nスーパータイプ: {sup_t}"), - "simplified_chinese" => format!("无法满足此表达式中的子类型约束\n\n子类型: {sub_t}\n超类型: {sup_t}"), - "traditional_chinese" => format!("無法滿足此表達式中的子類型約束\n\n子類型: {sub_t}\n超類型: {sup_t}"), - "english" => format!("the subtype constraint in this expression cannot be satisfied:\nsubtype: {sub_t}\nsupertype: {sup_t}"), + "japanese" => format!("この式の部分型制約を満たせません"), + "simplified_chinese" => format!("无法满足此表达式中的子类型约束"), + "traditional_chinese" => format!("無法滿足此表達式中的子類型約束"), + "english" => format!("the subtype constraint in this expression cannot be satisfied:"), ), errno, TypeError, @@ -787,16 +877,34 @@ passed keyword args: {kw_args_len}" rhs: &Predicate, caused_by: AtomicStr, ) -> Self { - let lhs = StyledString::new(&format!("{}", lhs), Some(WARNING), Some(Attribute::Bold)); - let rhs = StyledString::new(&format!("{}", rhs), Some(WARNING), Some(Attribute::Bold)); + let mut lhs_uni = StyledStrings::default(); + switch_lang!( + "japanese" => lhs_uni.push_str("左辺: "), + "simplified_chinese" => lhs_uni.push_str("左边: "), + "traditional_chinese" => lhs_uni.push_str("左邊: "), + "english" => lhs_uni.push_str("lhs: "), + ); + lhs_uni.push_str_with_color_and_attribute(&format!("{}", lhs), WARN, Attribute::Bold); + let mut rhs_uni = StyledStrings::default(); + switch_lang!( + "japanese" => rhs_uni.push_str("右辺: "), + "simplified_chinese" => rhs_uni.push_str("右边: "), + "traditional_chinese" => rhs_uni.push_str("右邊: "), + "english" => rhs_uni.push_str("rhs: "), + ); + rhs_uni.push_str_with_color_and_attribute(&format!("{}", rhs), WARN, Attribute::Bold); Self::new( ErrorCore::new( - vec![SubMessage::only_loc(Location::Unknown)], + vec![SubMessage::ambiguous_new( + Location::Unknown, + vec![lhs_uni.into(), rhs_uni.into()], + None, + )], switch_lang!( - "japanese" => format!("述語式の単一化に失敗しました\n\n左辺: {lhs}\n右辺: {rhs}"), - "simplified_chinese" => format!("无法统一谓词表达式\n\n左边: {lhs}\n左边: {rhs}"), - "traditional_chinese" => format!("無法統一謂詞表達式\n\n左邊: {lhs}\n左邊: {rhs}"), - "english" => format!("predicate unification failed\n\nlhs: {lhs}\nrhs: {rhs}"), + "japanese" => format!("述語式の単一化に失敗しました"), + "simplified_chinese" => format!("无法统一谓词表达式"), + "traditional_chinese" => format!("無法統一謂詞表達式"), + "english" => format!("predicate unification failed"), ), errno, TypeError, @@ -817,7 +925,7 @@ passed keyword args: {kw_args_len}" ) -> Self { Self::new( ErrorCore::new( - vec![SubMessage::ambiguous_new(loc, None, hint)], + vec![SubMessage::ambiguous_new(loc, vec![], hint)], switch_lang!( "japanese" => format!("{proj}の候補がありません"), "simplified_chinese" => format!("{proj}没有候选项"), @@ -844,7 +952,7 @@ passed keyword args: {kw_args_len}" ) -> Self { Self::new( ErrorCore::new( - vec![SubMessage::ambiguous_new(loc, None, hint)], + vec![SubMessage::ambiguous_new(loc, vec![], hint)], switch_lang!( "japanese" => format!("{class}は{trait_}を実装していません"), "simplified_chinese" => format!("{class}没有实现{trait_}"), @@ -871,7 +979,7 @@ passed keyword args: {kw_args_len}" let found = StyledString::new(name, Some(ERR), Some(Attribute::Bold)); Self::new( ErrorCore::new( - vec![SubMessage::ambiguous_new(loc, None, hint)], + vec![SubMessage::ambiguous_new(loc, vec![], hint)], switch_lang!( "japanese" => format!( "{found}にメソッドを定義することはできません", @@ -907,17 +1015,36 @@ passed keyword args: {kw_args_len}" found: &Type, hint: Option, ) -> Self { - let member_name = StyledString::new(member_name, Some(WARNING), Some(Attribute::Bold)); - let expect = StyledString::new(&format!("{}", expect), Some(HINT), Some(Attribute::Bold)); - let found = StyledString::new(&format!("{}", found), Some(ERR), Some(Attribute::Bold)); + let mut expct = StyledStrings::default(); + expct.push_str_with_color_and_attribute(&format!("{}", trait_type), WARN, Attribute::Bold); + switch_lang!( + "japanese" => expct.push_str("で宣言された型: "), + "simplified_chinese" => expct.push_str("中声明的类型: "), + "traditional_chinese" => expct.push_str("中聲明的類型: "), + "english" => expct.push_str("declared in: "), + ); + expct.push_str_with_color(&format!("{}", expect), HINT); + let mut fnd = StyledStrings::default(); + fnd.push_str_with_color_and_attribute(member_name, WARN, Attribute::Bold); + switch_lang!( + "japanese" => expct.push_str("与えられた型: "), + "simplified_chinese" => expct.push_str("但找到: "), + "traditional_chinese" => expct.push_str("但找到: "), + "english" => expct.push_str("but found: "), + ); + fnd.push_str_with_color(&format!("{}", found), ERR); Self::new( ErrorCore::new( - vec![SubMessage::ambiguous_new(loc, None, hint)], + vec![SubMessage::ambiguous_new( + loc, + vec![expct.into(), fnd.into()], + hint, + )], switch_lang!( - "japanese" => format!("{member_name}の型が違います\n\n{trait_type}で宣言された型: {expect}\n与えられた型: {found}"), - "simplified_chinese" => format!("{member_name}的类型不匹配\n\n在{trait_type}中声明的类型: {expect}\n但找到: {found}"), - "traditional_chinese" => format!("{member_name}的類型不匹配\n\n在{trait_type}中聲明的類型: {expect}\n但找到: {found}"), - "english" => format!("the type of {member_name} is mismatched\n\ndeclared in {trait_type}: {expect}\nbut found: {found}"), + "japanese" => format!("{member_name}の型が違います"), + "simplified_chinese" => format!("{member_name}的类型不匹配"), + "traditional_chinese" => format!("{member_name}的類型不匹配"), + "english" => format!("the type of {member_name} is mismatched"), ), errno, TypeError, @@ -938,10 +1065,10 @@ passed keyword args: {kw_args_len}" class_type: &Type, hint: Option, ) -> Self { - let member_name = StyledString::new(member_name, Some(WARNING), Some(Attribute::Bold)); + let member_name = StyledString::new(member_name, Some(WARN), Some(Attribute::Bold)); Self::new( ErrorCore::new( - vec![SubMessage::ambiguous_new(Location::Unknown, None, hint)], + vec![SubMessage::ambiguous_new(Location::Unknown, vec![], hint)], switch_lang!( "japanese" => format!("{trait_type}の{member_name}が{class_type}で実装されていません"), "simplified_chinese" => format!("{trait_type}中的{member_name}没有在{class_type}中实现"), @@ -967,10 +1094,10 @@ passed keyword args: {kw_args_len}" class_type: &Type, hint: Option, ) -> Self { - let member_name = StyledString::new(member_name, Some(WARNING), Some(Attribute::Bold)); + let member_name = StyledString::new(member_name, Some(WARN), Some(Attribute::Bold)); Self::new( ErrorCore::new( - vec![SubMessage::ambiguous_new(Location::Unknown, None, hint)], + vec![SubMessage::ambiguous_new(Location::Unknown, vec![], hint)], switch_lang!( "japanese" => format!("{class_type}の{member_name}は{trait_type}で宣言されていません"), "simplified_chinese" => format!("{class_type}中的{member_name}没有在{trait_type}中声明"), @@ -1027,14 +1154,26 @@ passed keyword args: {kw_args_len}" "english" => "if it is a polymorphic function, use `f|T := Int|`, or if it is a type attribute, use `T|T <: Trait|.X` etc. to specify the type", ).into(), ); + let mut candi = StyledStrings::default(); + switch_lang!( + "japanese" => candi.push_str("候補: "), + "simplified_chinese" => candi.push_str("候选: "), + "traditional_chinese" => candi.push_str("候選: "), + "english" => candi.push_str("candidates: "), + ); + candi.push_str_with_color_and_attribute(&fmt_vec(candidates), WARN, Attribute::Bold); Self::new( ErrorCore::new( - vec![SubMessage::ambiguous_new(expr.loc(), None, hint)], + vec![SubMessage::ambiguous_new( + expr.loc(), + vec![candi.into()], + hint, + )], switch_lang!( - "japanese" => format!("{expr}の型を一意に決定できませんでした\n\n候補: {}", fmt_vec(candidates)), - "simplified_chinese" => format!("无法确定{expr}的类型\n\n候选: {}", fmt_vec(candidates)), - "traditional_chinese" => format!("無法確定{expr}的類型\n\n候選: {}", fmt_vec(candidates)), - "english" => format!("cannot determine the type of {expr}\n\ncandidates: {}", fmt_vec(candidates)), + "japanese" => format!("{expr}の型を一意に決定できませんでした"), + "simplified_chinese" => format!("无法确定{expr}的类型"), + "traditional_chinese" => format!("無法確定{expr}的類型"), + "english" => format!("cannot determine the type of {expr}"), ), errno, TypeError, @@ -1147,7 +1286,7 @@ impl EffectError { ); Self::new( ErrorCore::new( - vec![SubMessage::ambiguous_new(sig.loc(), None, hint)], + vec![SubMessage::ambiguous_new(sig.loc(), vec![], hint)], switch_lang!( "japanese" => "プロシージャを通常の変数に代入することはできません", "simplified_chinese" => "不能将过程赋值给普通变量", @@ -1226,7 +1365,7 @@ impl LowerError { ) -> Self { Self::new( ErrorCore::new( - vec![SubMessage::ambiguous_new(loc, None, hint)], + vec![SubMessage::ambiguous_new(loc, vec![], hint)], desc.into(), errno, SyntaxError, @@ -1341,7 +1480,7 @@ impl LowerError { let found = StyledString::new(name, Some(ERR), Some(Attribute::Bold)); Self::new( ErrorCore::new( - vec![SubMessage::ambiguous_new(loc, None, hint)], + vec![SubMessage::ambiguous_new(loc, vec![], hint)], switch_lang!( "japanese" => format!("{found}という変数は定義されていません"), "simplified_chinese" => format!("{found}未定义"), @@ -1374,7 +1513,7 @@ impl LowerError { ); Self::new( ErrorCore::new( - vec![SubMessage::ambiguous_new(loc, None, hint)], + vec![SubMessage::ambiguous_new(loc, vec![], hint)], switch_lang!( "japanese" => format!("{typ}という型は定義されていません"), "simplified_chinese" => format!("{typ}未定义"), @@ -1411,7 +1550,7 @@ impl LowerError { let found = StyledString::new(name, Some(ERR), Some(Attribute::Bold)); Self::new( ErrorCore::new( - vec![SubMessage::ambiguous_new(loc, None, hint)], + vec![SubMessage::ambiguous_new(loc, vec![], hint)], switch_lang!( "japanese" => format!("{obj_t}型オブジェクトに{found}という属性はありません"), "simplified_chinese" => format!("{obj_t}对象没有属性{found}"), @@ -1451,7 +1590,7 @@ impl LowerError { let found = StyledString::new(name, Some(ERR), Some(Attribute::Bold)); Self::new( ErrorCore::new( - vec![SubMessage::ambiguous_new(loc, None, hint)], + vec![SubMessage::ambiguous_new(loc, vec![], hint)], switch_lang!( "japanese" => format!("{obj_name}(: {obj_t})に{found}という属性はありません"), "simplified_chinese" => format!("{obj_name}(: {obj_t})没有属性{found}"), @@ -1474,7 +1613,7 @@ impl LowerError { caused_by: AtomicStr, name: &str, ) -> Self { - let name = StyledString::new(readable_name(name), Some(WARNING), Some(Attribute::Bold)); + let name = StyledString::new(readable_name(name), Some(WARN), Some(Attribute::Bold)); Self::new( ErrorCore::new( vec![SubMessage::only_loc(loc)], @@ -1500,7 +1639,7 @@ impl LowerError { name: &str, caused_by: AtomicStr, ) -> Self { - let name = StyledString::new(readable_name(name), Some(WARNING), Some(Attribute::Bold)); + let name = StyledString::new(readable_name(name), Some(WARN), Some(Attribute::Bold)); Self::new( ErrorCore::new( vec![SubMessage::only_loc(loc)], @@ -1522,7 +1661,7 @@ impl LowerError { pub fn del_error(input: Input, errno: usize, ident: &Identifier, caused_by: AtomicStr) -> Self { let name = StyledString::new( readable_name(ident.inspect()), - Some(WARNING), + Some(WARN), Some(Attribute::Bold), ); Self::new( @@ -1597,19 +1736,31 @@ impl LowerError { let name = StyledString::new(name, Some(ERR), Some(Attribute::Bold)); let superclass = StyledString::new( &format!("{}", superclass), - Some(WARNING), + Some(WARN), Some(Attribute::Bold), ); - let hint = - Some(switch_lang!( - "japanese" => "デフォルトでオーバーライドはできません(`Override`デコレータを使用してください)", - "simplified_chinese" => "默认不可重写(请使用`Override`装饰器)", - "traditional_chinese" => "默認不可重寫(請使用`Override`裝飾器)", - "english" => "cannot override by default (use `Override` decorator)", - ).into()); + let hint = Some( + switch_lang!( + "japanese" => "`Override`デコレータを使用してください", + "simplified_chinese" => "请使用`Override`装饰器", + "traditional_chinese" => "請使用`Override`裝飾器", + "english" => "use `Override` decorator", + ) + .into(), + ); + let sub_msg = switch_lang!( + "japanese" => "デフォルトでオーバーライドはできません", + "simplified_chinese" => "默认不可重写", + "simplified_chinese" => "默認不可重寫", + "english" => "cannot override by default", + ); Self::new( ErrorCore::new( - vec![SubMessage::ambiguous_new(name_loc, None, hint)], + vec![SubMessage::ambiguous_new( + name_loc, + vec![sub_msg.into()], + hint, + )], switch_lang!( "japanese" => format!( "{name}は{superclass}で既に定義されています", @@ -1667,7 +1818,13 @@ impl LowerError { hint: Option, ) -> Self { Self::new( - ErrorCore::new( vec![SubMessage::ambiguous_new(loc, None, hint)], desc, errno, IoError, loc), + ErrorCore::new( + vec![SubMessage::ambiguous_new(loc, vec![], hint)], + desc, + errno, + IoError, + loc, + ), input, caused_by, ) @@ -1698,26 +1855,115 @@ impl LowerError { similar_erg_mod: Option, similar_py_mod: Option, ) -> Self { - let hint = match (similar_erg_mod, similar_py_mod) { - (Some(erg), Some(py)) => { - let erg = StyledString::new(&erg, Some(WARNING), Some(Attribute::Bold)); - let py = StyledString::new(&py, Some(WARNING), Some(Attribute::Bold)); - Some(format!( - "similar name erg module {erg} and python module {py} exists (to import python modules, use `pyimport`)", - )) + let mut erg_str = StyledStrings::default(); + let mut py_str = StyledStrings::default(); + let hint = switch_lang!( + + "japanese" => { + match (similar_erg_mod, similar_py_mod) { + (Some(erg), Some(py)) => { + erg_str.push_str("似た名前のergモジュールが存在します: "); + erg_str.push_str_with_color_and_attribute(&erg, WARN, Attribute::Bold); + py_str.push_str("似た名前のpythonモジュールが存在します: "); + py_str.push_str_with_color_and_attribute(&py, WARN, Attribute::Bold); + Some("pythonのモジュールをインポートするためには`pyimport`を使用してください".to_string()) + } + (Some(erg), None) => { + erg_str.push_str("似た名前のergモジュールが存在します"); + erg_str.push_str_with_color_and_attribute(&erg, WARN, Attribute::Bold); + None + } + (None, Some(py)) => { + py_str.push_str("似た名前のpythonモジュールが存在します"); + py_str.push_str_with_color_and_attribute(&py, WARN, Attribute::Bold); + Some("pythonのモジュールをインポートするためには`pyimport`を使用してください".to_string()) + } + (None, None) => None, } - (Some(erg), None) => { - let erg = StyledString::new(&erg, Some(WARNING), Some(Attribute::Bold)); - Some(format!("similar name erg module exists: {erg}")) + }, + "simplified_chinese" => { + match (similar_erg_mod, similar_py_mod) { + (Some(erg), Some(py)) => { + erg_str.push_str("存在相似名称的erg模块: "); + erg_str.push_str_with_color_and_attribute(&erg, WARN, Attribute::Bold); + py_str.push_str("存在相似名称的python模块: "); + py_str.push_str_with_color_and_attribute(&py, WARN, Attribute::Bold); + Some("要导入python模块,请使用`pyimport`".to_string()) + } + (Some(erg), None) => { + erg_str.push_str("存在相似名称的erg模块: "); + erg_str.push_str_with_color_and_attribute(&erg, WARN, Attribute::Bold); + None + } + (None, Some(py)) => { + py_str.push_str("存在相似名称的python模块: "); + py_str.push_str_with_color_and_attribute(&py, WARN, Attribute::Bold); + Some("要导入python模块,请使用`pyimport`".to_string()) + } + (None, None) => None, } - (None, Some(py)) => { - let py = StyledString::new(&py, Some(WARNING), Some(Attribute::Bold)); - Some(format!("similar name python module exists: {py} (to import python modules, use `pyimport`)")) + }, + "traditional_chinese" => { + match (similar_erg_mod, similar_py_mod) { + (Some(erg), Some(py)) => { + erg_str.push_str("存在類似名稱的erg模塊: "); + erg_str.push_str_with_color_and_attribute(&erg, WARN, Attribute::Bold); + py_str.push_str("存在類似名稱的python模塊: "); + py_str.push_str_with_color_and_attribute(&py, WARN, Attribute::Bold); + Some("要導入python模塊, 請使用`pyimport`".to_string()) + } + (Some(erg), None) => { + erg_str.push_str("存在類似名稱的erg模塊: "); + erg_str.push_str_with_color_and_attribute(&erg, WARN, Attribute::Bold); + None + } + (None, Some(py)) => { + py_str.push_str("存在類似名稱的python模塊: "); + py_str.push_str_with_color_and_attribute(&py, WARN, Attribute::Bold); + Some("要導入python模塊, 請使用`pyimport`".to_string()) + } + (None, None) => None, } - (None, None) => None, - }; + }, + "english" => { + match (similar_erg_mod, similar_py_mod) { + (Some(erg), Some(py)) => { + erg_str.push_str("similar name erg module exists: "); + erg_str.push_str_with_color_and_attribute(&erg, WARN, Attribute::Bold); + py_str.push_str("similar name python module exists: "); + py_str.push_str_with_color_and_attribute(&py, WARN, Attribute::Bold); + Some("to import python modules, use `pyimport`".to_string()) + } + (Some(erg), None) => { + erg_str.push_str("similar name erg module exists: "); + erg_str.push_str_with_color_and_attribute(&erg, WARN, Attribute::Bold); + None + } + (None, Some(py)) => { + py_str.push_str("similar name python module: "); + py_str.push_str_with_color_and_attribute(&py, WARN, Attribute::Bold); + Some("to import python modules, use `pyimport`".to_string()) + } + (None, None) => None, + } + }, + ); let hint = hint.map(AtomicStr::from); - Self::file_error(input, errno, desc, loc, caused_by, hint) + Self::new( + ErrorCore::new( + vec![SubMessage::ambiguous_new( + loc, + vec![erg_str.into(), py_str.into()], + hint, + )], + desc, + errno, + ImportError, + loc, + ), + input, + caused_by, + ) } pub fn inner_typedef_error( @@ -1773,15 +2019,11 @@ impl LowerError { cast_to: &Type, hint: Option, ) -> Self { - let name = StyledString::new(name, Some(WARNING), Some(Attribute::Bold)); - let found = StyledString::new( - &format!("{}", cast_to), - Some(WARNING), - Some(Attribute::Bold), - ); + let name = StyledString::new(name, Some(WARN), Some(Attribute::Bold)); + let found = StyledString::new(&format!("{}", cast_to), Some(WARN), Some(Attribute::Bold)); Self::new( ErrorCore::new( - vec![SubMessage::ambiguous_new(loc, None, hint)], + vec![SubMessage::ambiguous_new(loc, vec![], hint)], switch_lang!( "japanese" => format!("{name}の型を{found}にキャストすることはできません"), "simplified_chinese" => format!("{name}的类型无法转换为{found}"), @@ -1836,60 +2078,26 @@ pub type CompileWarnings = CompileErrors; #[cfg(test)] mod test { - - use erg_common::{config::Input, error::Location}; - - use crate::ty::Type; - use super::TyCheckError; + use crate::{error::CompileError, ty::Type}; + use erg_common::{config::Input, error::Location}; #[test] fn default_arg_error_test() { - let loc = Location::Range { - ln_begin: 1, - col_begin: 0, - ln_end: 1, - col_end: 5, - }; - let input = Input::Pipe("a = 1".to_string()); - let caused_by = "File name here basically"; - let desc = "Some kinds of error description here"; - let hint = Some("Some hint massage here\n".into()); - - let err = TyCheckError::syntax_error(input, 0, loc, caused_by.into(), desc, hint); + let input = Input::Pipe("line error".into()); + let loc = Location::Line(1); + let err = CompileError::stack_bug(input, loc, 0, 0, "FileName"); print!("{}", err); - let loc = Location::Range { - ln_begin: 1, - col_begin: 24, - ln_end: 1, - col_end: 27, - }; - let input = Input::Pipe("Person = Class { name = Str }".to_string()); - let caused_by = "File name here basically"; - let err = TyCheckError::args_missing_error( - input, - 0, - loc, - "\"Callee name here\"", - caused_by.into(), - 0, - vec!["sample".into(), "args".into(), "here".into()], - ); + let input = Input::Pipe("a: Nat = -1".into()); + let err = TyCheckError::checker_bug(input, 0, Location::Unknown, "name", 1); print!("{}", err); - let loc = Location::Range { - ln_begin: 1, - col_begin: 0, - ln_end: 3, - col_end: 5, - }; + let loc = Location::LineRange(1, 3); let input = Input::Pipe( - "\ -if True: + "if True: sample - end -" + end" .to_string(), ); let caused_by = "File name here basically"; @@ -1904,16 +2112,6 @@ if True: ); print!("{}", err); - let loc = Location::Range { - ln_begin: 1, - col_begin: 0, - ln_end: 1, - col_end: 3, - }; - let input = Input::Pipe("add(x, y):Nat = x - y".to_string()); - let err = TyCheckError::checker_bug(input, 0, loc, "file_name", 0); - print!("{}", err); - let loc = Location::Range { ln_begin: 1, col_begin: 11, @@ -1921,7 +2119,7 @@ if True: col_end: 14, }; let expect = Type::Nat; - let found = Type::Obj; + let found = Type::Int; let input = Input::Pipe("add(x, y): Nat = x - y".to_string()); let caused_by = "File name here basically"; let err = TyCheckError::return_type_error( @@ -1935,8 +2133,28 @@ if True: ); print!("{}", err); - let input = Input::Pipe("Dummy code here".to_string()); - let err = TyCheckError::unreachable(input, "file name here", 1); + let loc = Location::Range { + ln_begin: 1, + col_begin: 0, + ln_end: 1, + col_end: 1, + }; + let expect = Type::Nat; + let found = Type::Int; + let input = Input::Pipe("a: Nat = -1".to_string()); + let caused_by = "File name here basically"; + let err = TyCheckError::type_mismatch_error( + input, + 0, + loc, + caused_by.into(), + "name", + Some(1), + &expect, + &found, + None, + Some("hint message here".into()), + ); print!("{}", err); } } diff --git a/compiler/erg_parser/error.rs b/compiler/erg_parser/error.rs index 75810f79..2d29857b 100644 --- a/compiler/erg_parser/error.rs +++ b/compiler/erg_parser/error.rs @@ -102,7 +102,7 @@ impl LexError { hint: Option, ) -> Self { Self::new(ErrorCore::new( - vec![SubMessage::ambiguous_new(loc, None, hint)], + vec![SubMessage::ambiguous_new(loc, vec![], hint)], desc, errno, SyntaxError, @@ -117,7 +117,7 @@ impl LexError { hint: Option, ) -> Self { Self::new(ErrorCore::new( - vec![SubMessage::ambiguous_new(loc, None, hint)], + vec![SubMessage::ambiguous_new(loc, vec![], hint)], desc, errno, SyntaxWarning, @@ -143,7 +143,7 @@ impl LexError { }); let name = StyledString::new(name, Some(ERR), Some(Attribute::Underline)); Self::new(ErrorCore::new( - vec![SubMessage::ambiguous_new(loc, None, hint)], + vec![SubMessage::ambiguous_new(loc, vec![], hint)], switch_lang!( "japanese" => format!("{name}という変数は定義されていません"), "simplified_chinese" => format!("{name}未定义"), From b739554050c55550fc80f10bef27773822e6c9a6 Mon Sep 17 00:00:00 2001 From: GreasySlug <9619abgoni@gmail.com> Date: Sun, 20 Nov 2022 09:36:12 +0900 Subject: [PATCH 10/23] Fix: format --- compiler/erg_common/astr.rs | 15 +++++++++++++++ compiler/erg_common/error.rs | 24 +++++++++++------------- 2 files changed, 26 insertions(+), 13 deletions(-) diff --git a/compiler/erg_common/astr.rs b/compiler/erg_common/astr.rs index 1c45b313..df65cbbe 100644 --- a/compiler/erg_common/astr.rs +++ b/compiler/erg_common/astr.rs @@ -3,6 +3,7 @@ use std::fmt; use std::hash::{Hash, Hasher}; use std::ops::{Add, Deref}; +use crate::style::{StyledString, StyledStrings}; use crate::Str; pub type ArcStr = std::sync::Arc; @@ -118,6 +119,20 @@ impl From<&Str> for AtomicStr { } } +impl From for AtomicStr { + #[inline] + fn from(s: StyledString) -> Self { + AtomicStr::Arc(s.to_string().into()) + } +} + +impl From for AtomicStr { + #[inline] + fn from(s: StyledStrings) -> Self { + AtomicStr::Arc(s.to_string().into()) + } +} + impl Deref for AtomicStr { type Target = str; fn deref(&self) -> &Self::Target { diff --git a/compiler/erg_common/error.rs b/compiler/erg_common/error.rs index 9f59732c..8d56de81 100644 --- a/compiler/erg_common/error.rs +++ b/compiler/erg_common/error.rs @@ -442,7 +442,7 @@ impl SubMessage { ), Location::LineRange(ln_begin, ln_end) => { let input = e.input(); - let (_, vbar) = chars.gutters(); + let (vbreak, vbar) = chars.gutters(); let mut cxt = StyledStrings::default(); let codes = if input.is_repl() { vec![input.reread()] @@ -451,12 +451,18 @@ impl SubMessage { }; let mark = mark.to_string(); for (i, lineno) in (ln_begin..=ln_end).enumerate() { - cxt.push_str_with_color(&format!("{lineno} {}", vbar), err_color); + cxt.push_str_with_color(&format!("{lineno} {vbar} "), gutter_color); cxt.push_str(&codes[i]); - cxt.push_str(&" ".repeat(lineno.to_string().len() + 3)); // +3 means ` | ` - cxt.push_str_with_color(&mark.repeat(cmp::max(1, codes[i].len())), gutter_color) + cxt.push_str("\n"); + cxt.push_str_with_color( + &format!("{} {}", &" ".repeat(lineno.to_string().len()), vbreak), + gutter_color, + ); + cxt.push_str(&" ".repeat(lineno.to_string().len())); + cxt.push_str_with_color(&mark.repeat(cmp::max(1, codes[i].len())), err_color); + cxt.push_str("\n"); } - cxt.push_str("\n\n"); + cxt.push_str("\n"); cxt.to_string() } Location::Line(lineno) => { @@ -569,14 +575,6 @@ impl ErrorCore { }; format!("{kind}: File {input}{loc}{caused_by}",) } - - pub fn fmt_main_message(&self, kind: StyledString, caused_by: &str, input: &str) -> String { - format!( - "{}\n{}\n\n", - self.fmt_header(kind, caused_by, input), - self.main_message - ) - } } /// format: From 645c3e4a547eca5e3c4a0464f1e2f3e6a1cbdd6f Mon Sep 17 00:00:00 2001 From: GreasySlug <9619abgoni@gmail.com> Date: Sun, 20 Nov 2022 09:36:35 +0900 Subject: [PATCH 11/23] Change: update doc current format --- compiler/erg_common/error.rs | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/compiler/erg_common/error.rs b/compiler/erg_common/error.rs index 8d56de81..f60189cf 100644 --- a/compiler/erg_common/error.rs +++ b/compiler/erg_common/error.rs @@ -580,20 +580,27 @@ impl ErrorCore { /// format: /// ```txt /// Error[#{.errno}]: File {file}, line {.loc (as line)}, in {.caused_by} +/// /// {.loc (as line)}| {src} -/// {pointer} +/// {offset} : {pointer} +/// {offset} : {sub_msgs} +/// {offset} : {.hint} +/// /// {.kind}: {.desc} -/// {.hint} +/// /// ``` /// /// example: /// ```txt /// Error[#2223]: File , line 1, in +/// +/// 1 │ 100 = i +/// · --- +/// · ╰─ sub_msg: sub messages here +/// · ╰─ hint: hint message here +/// /// SyntaxError: cannot assign to 100 /// -/// 1 | 100 = i -/// --- -/// ╰─ hint: hint message here /// ``` pub trait ErrorDisplay { fn core(&self) -> &ErrorCore; From 92ad941676ded1a1941b233c7a1bdb82f92b3cfd Mon Sep 17 00:00:00 2001 From: GreasySlug <9619abgoni@gmail.com> Date: Sun, 20 Nov 2022 09:37:19 +0900 Subject: [PATCH 12/23] Test: reverse --- compiler/erg_common/style.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/compiler/erg_common/style.rs b/compiler/erg_common/style.rs index 81c5882d..52c556a4 100644 --- a/compiler/erg_common/style.rs +++ b/compiler/erg_common/style.rs @@ -516,10 +516,15 @@ mod tests { Attribute::Bold, ); texts.push_str_with_color_and_attribute( - "White and underlined text", - Color::White, + "White and underlined text\n", + Color::Blue, Attribute::Underline, ); + texts.push_str_with_color_and_attribute( + "White and underlined text", + Color::Red, + Attribute::Reversed, + ); println!("{}", texts); } } From 9611322533b271ab1c04a2f07e024217a370a460 Mon Sep 17 00:00:00 2001 From: GreasySlug <9619abgoni@gmail.com> Date: Sun, 20 Nov 2022 11:32:30 +0900 Subject: [PATCH 13/23] Add: left cross for sub-msg --- compiler/erg_common/error.rs | 13 ++++++++++--- compiler/erg_common/style.rs | 16 ++++++++++++++-- 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/compiler/erg_common/error.rs b/compiler/erg_common/error.rs index bee93dd0..4d827d5b 100644 --- a/compiler/erg_common/error.rs +++ b/compiler/erg_common/error.rs @@ -367,10 +367,16 @@ fn format_context( } context.push_str("\n"); } - for msg in sub_msg { + + let msg_num = sub_msg.len().saturating_sub(1); + for (i, msg) in sub_msg.iter().enumerate() { context.push_str_with_color(&offset, gutter_color); context.push_str(&" ".repeat(col_end - 1)); - context.push_str_with_color(&chars.left_bottom_line(), err_color); + if i == msg_num && hint.is_none() { + context.push_str_with_color(&chars.left_bottom_line(), err_color); + } else { + context.push_str_with_color(&chars.left_cross(), err_color); + } context.push_str(msg); context.push_str("\n") } @@ -595,7 +601,8 @@ impl ErrorCore { /// /// 1 │ 100 = i /// · --- -/// · ╰─ sub_msg: sub messages here +/// · │─ sub_msg1: first sub message here +/// · │─ sub_msg2: second sub message here /// · ╰─ hint: hint message here /// /// SyntaxError: cannot assign to 100 diff --git a/compiler/erg_common/style.rs b/compiler/erg_common/style.rs index 63fff6bb..c7e537a1 100644 --- a/compiler/erg_common/style.rs +++ b/compiler/erg_common/style.rs @@ -144,10 +144,10 @@ impl Characters { (self.vbreak, self.vbar) } - // " `- " + // "`- " #[cfg(not(feature = "unicode"))] pub fn left_bottom_line(&self) -> String { - format!(" {}{} ", self.lbot, self.line) + format!("{}{} ", self.lbot, self.line) } // `╰─ ` @@ -156,6 +156,18 @@ impl Characters { format!("{}{} ", self.lbot, self.line) } + // "|- " + #[cfg(not(feature = "unicode"))] + pub fn left_cross(&self) -> String { + format!("{}{} ", self.vbar, self.line) + } + + // "│─ " + #[cfg(feature = "unicode")] + pub fn left_cross(&self) -> String { + format!("{}{} ", self.vbar, self.line) + } + // kind[padded error number] #[cfg(not(feature = "pretty"))] pub fn error_kind_format(&self, kind: &str, err_num: usize) -> String { From cc9fa5a12ea8e4ad0db795286cdd25911c3cead1 Mon Sep 17 00:00:00 2001 From: GreasySlug <9619abgoni@gmail.com> Date: Mon, 21 Nov 2022 14:21:03 +0900 Subject: [PATCH 14/23] Change: `String` to `Cow<'a, str>` --- compiler/erg_common/str.rs | 11 +- compiler/erg_common/style.rs | 26 ++- compiler/erg_compiler/error.rs | 381 ++++++++++++++++++++------------- 3 files changed, 258 insertions(+), 160 deletions(-) diff --git a/compiler/erg_common/str.rs b/compiler/erg_common/str.rs index 425a0441..04a2bc94 100644 --- a/compiler/erg_common/str.rs +++ b/compiler/erg_common/str.rs @@ -1,4 +1,4 @@ -use std::borrow::Borrow; +use std::borrow::{Borrow, Cow}; use std::fmt; use std::hash::{Hash, Hasher}; use std::ops::{Add, Deref}; @@ -61,6 +61,15 @@ impl From for String { } } +impl<'a> From for Cow<'a, str> { + fn from(s: Str) -> Self { + match s { + Str::Static(s) => Cow::Owned(s.to_owned()), + _ => unreachable!(), + } + } +} + // &'static str -> &strになってしまわないように // あえて`impl> From for Str { ... }`はしない impl From<&'static str> for Str { diff --git a/compiler/erg_common/style.rs b/compiler/erg_common/style.rs index c7e537a1..2aa890e8 100644 --- a/compiler/erg_common/style.rs +++ b/compiler/erg_common/style.rs @@ -1,3 +1,5 @@ +use std::borrow::Cow; + pub const ATTR_RESET: &str = "\x1b[0m"; pub const BOLD: &str = "\x1b[1m"; pub const UNDERLINE: &str = "\x1b[4m"; @@ -315,9 +317,14 @@ pub struct StyledString { } impl StyledString { - pub fn new(s: &str, color: Option, attribute: Option) -> Self { + pub fn new<'a, S: Into>>( + s: S, + color: Option, + attribute: Option, + ) -> Self { + let text: Cow<'a, str> = s.into(); Self { - text: String::from(s), + text: text.into_owned(), color, attribute, } @@ -420,9 +427,10 @@ impl StyledStrings { /// texts.push_str_with_color("\n If you want to add break lines, you should add `\n`.", Color::Magenta); /// println!("{}", texts); /// ``` - pub fn push_str_with_color(&mut self, s: &str, color: Color) { + pub fn push_str_with_color<'a, S: Into>>(&mut self, s: S, color: Color) { if self.is_same_color(color) { - self.texts.last_mut().unwrap().text.push_str(s); + let text = s.into(); + self.texts.last_mut().unwrap().text.push_str(&text); } else { self.texts.push(StyledString::new(s, Some(color), None)); } @@ -441,9 +449,15 @@ impl StyledStrings { /// // texts.push_str_with_color_and_attribute("Must be specify the color and attribute", None, Attribute::Underline); /// println!("{}", texts); /// ``` - pub fn push_str_with_color_and_attribute(&mut self, s: &str, color: Color, attr: Attribute) { + pub fn push_str_with_color_and_attribute<'a, S: Into>>( + &mut self, + s: S, + color: Color, + attr: Attribute, + ) { if self.is_same_color(color) && self.is_same_attribute(attr) { - self.texts.last_mut().unwrap().text.push_str(s); + let text = s.into(); + self.texts.last_mut().unwrap().text.push_str(&text); } else { self.texts .push(StyledString::new(s, Some(color), Some(attr))); diff --git a/compiler/erg_compiler/error.rs b/compiler/erg_compiler/error.rs index 2c02f260..ea8868fb 100644 --- a/compiler/erg_compiler/error.rs +++ b/compiler/erg_compiler/error.rs @@ -145,11 +145,25 @@ impl ErrorDisplay for CompileError { } } +// found, error +const ERR: Color = THEME.colors.error; +// name +const WARN: Color = THEME.colors.warning; +// expect, hint +const HINT: Color = THEME.colors.hint; +// url and var name const ACCENT: Color = THEME.colors.accent; +// url and feature = pretty +const UNDERLINE: Attribute = Attribute::Underline; +#[cfg(not(feature = "pretty"))] +const ATTR: Attribute = Attribute::Bold; +#[cfg(feature = "pretty")] +const ATTR: Attribute = Attribute::Underline; + const URL: StyledStr = StyledStr::new( "https://github.com/erg-lang/erg", Some(ACCENT), - Some(Attribute::Underline), + Some(UNDERLINE), ); impl CompileError { @@ -208,7 +222,7 @@ impl CompileError { 這是 Erg 編譯器的一個錯誤,請報告它 ({URL})\n\ 起因於: {fn_name}"), "english" => format!("the number of elements in the stack is invalid (num of elems: {stack_len}, block id: {block_id})\n\ - this is a bug of the Erg compiler, please report it ({URL})\n\ + this is a bug of the Erg compiler, please report it to {URL}\n\ caused from: {fn_name}"), ), 0, @@ -261,10 +275,6 @@ impl CompileError { pub type TyCheckError = CompileError; -const ERR: Color = THEME.colors.error; -const WARN: Color = THEME.colors.warning; -const HINT: Color = THEME.colors.hint; - impl TyCheckError { pub fn dummy(input: Input, errno: usize) -> Self { Self::new(ErrorCore::dummy(errno), input, "".into()) @@ -377,11 +387,7 @@ impl TyCheckError { ), None => "".into(), }; - let name = StyledString::new( - &format!("{}{}", name, ord), - Some(WARN), - Some(Attribute::Bold), - ); + let name = StyledString::new(format!("{}{}", name, ord), Some(WARN), Some(ATTR)); let mut expct = StyledStrings::default(); switch_lang!( "japanese" => expct.push_str("予期した型: "), @@ -389,7 +395,7 @@ impl TyCheckError { "traditional_chinese" => expct.push_str("預期: "), "english" => expct.push_str("expected: "), ); - expct.push_str_with_color_and_attribute(&format!("{}", expect), HINT, Attribute::Bold); + expct.push_str_with_color_and_attribute(format!("{}", expect), HINT, ATTR); let mut fnd = StyledStrings::default(); switch_lang!( @@ -398,12 +404,12 @@ impl TyCheckError { "traditional_chinese" => fnd.push_str("但找到: "), "english" =>fnd.push_str("but found: "), ); - fnd.push_str_with_color_and_attribute(&format!("{}", found), ERR, Attribute::Bold); + fnd.push_str_with_color_and_attribute(format!("{}", found), ERR, ATTR); Self::new( ErrorCore::new( vec![SubMessage::ambiguous_new( loc, - vec![expct.into(), fnd.into()], + vec![expct.to_string(), fnd.to_string()], hint, )], switch_lang!( @@ -437,7 +443,7 @@ impl TyCheckError { "traditional_chinese" => expct.push_str("預期: "), "english" => expct.push_str("expected: "), ); - expct.push_str_with_color_and_attribute(&format!("{}", expect), HINT, Attribute::Bold); + expct.push_str_with_color_and_attribute(format!("{}", expect), HINT, ATTR); let mut fnd = StyledStrings::default(); switch_lang!( @@ -446,13 +452,13 @@ impl TyCheckError { "traditional_chinese" => fnd.push_str("但找到: "), "english" =>fnd.push_str("but found: "), ); - fnd.push_str_with_color_and_attribute(&format!("{}", found), ERR, Attribute::Bold); + fnd.push_str_with_color_and_attribute(format!("{}", found), ERR, ATTR); Self::new( ErrorCore::new( vec![SubMessage::ambiguous_new( loc, - vec![expct.into(), fnd.into()], + vec![expct.to_string(), fnd.to_string()], None, )], switch_lang!( @@ -511,7 +517,7 @@ impl TyCheckError { "traditional_chinese" => expct.push_str("預期: "), "english" => expct.push_str("expected: "), ); - expct.push_str_with_color_and_attribute(&format!("{}", expect), HINT, Attribute::Bold); + expct.push_str_with_color_and_attribute(format!("{}", expect), HINT, ATTR); let mut fnd = StyledStrings::default(); switch_lang!( @@ -520,11 +526,15 @@ impl TyCheckError { "traditional_chinese" => fnd.push_str("但找到: "), "english" =>fnd.push_str("but found: "), ); - fnd.push_str_with_color_and_attribute(&format!("{}", found), ERR, Attribute::Bold); + fnd.push_str_with_color_and_attribute(format!("{}", found), ERR, ATTR); Self::new( ErrorCore::new( - vec![SubMessage::only_loc(loc)], + vec![SubMessage::ambiguous_new( + loc, + vec![expct.to_string(), fnd.to_string()], + None, + )], switch_lang!( "japanese" => format!("ポジショナル引数の数が違います"), "simplified_chinese" => format!("正则参数的数量不匹配"), @@ -610,21 +620,9 @@ impl TyCheckError { kw_args_len: usize, ) -> Self { let name = readable_name(callee_name); - let expect = StyledString::new( - &format!("{}", params_len), - Some(HINT), - Some(Attribute::Bold), - ); - let pos_args_len = StyledString::new( - &format!("{}", pos_args_len), - Some(ERR), - Some(Attribute::Bold), - ); - let kw_args_len = StyledString::new( - &format!("{}", kw_args_len), - Some(ERR), - Some(Attribute::Bold), - ); + let expect = StyledString::new(format!("{}", params_len), Some(HINT), Some(ATTR)); + let pos_args_len = StyledString::new(format!("{}", pos_args_len), Some(ERR), Some(ATTR)); + let kw_args_len = StyledString::new(format!("{}", kw_args_len), Some(ERR), Some(ATTR)); Self::new( ErrorCore::new( vec![SubMessage::only_loc(loc)], @@ -674,9 +672,8 @@ passed keyword args: {kw_args_len}" missing_len: usize, missing_params: Vec, ) -> Self { - let name = readable_name(callee_name); - let vec_cxt = - StyledString::new(&fmt_vec(&missing_params), Some(WARN), Some(Attribute::Bold)); + let name = StyledStr::new(readable_name(callee_name), Some(ACCENT), Some(ATTR)); + let vec_cxt = StyledString::new(&fmt_vec(&missing_params), Some(WARN), Some(ATTR)); Self::new( ErrorCore::new( vec![SubMessage::only_loc(loc)], @@ -703,8 +700,8 @@ passed keyword args: {kw_args_len}" caused_by: String, arg_name: &str, ) -> Self { - let name = readable_name(callee_name); - let found = StyledString::new(arg_name, Some(ERR), Some(Attribute::Bold)); + let name = StyledStr::new(readable_name(callee_name), Some(ACCENT), Some(ATTR)); + let found = StyledString::new(arg_name, Some(ERR), Some(ATTR)); Self::new( ErrorCore::new( vec![SubMessage::only_loc(loc)], @@ -731,8 +728,8 @@ passed keyword args: {kw_args_len}" caused_by: String, param_name: &str, ) -> Self { - let name = readable_name(callee_name); - let found = StyledString::new(param_name, Some(ERR), Some(Attribute::Bold)); + let name = StyledStr::new(readable_name(callee_name), Some(ACCENT), Some(ATTR)); + let found = StyledString::new(param_name, Some(ERR), Some(ATTR)); Self::new( ErrorCore::new( vec![SubMessage::only_loc(loc)], @@ -766,7 +763,7 @@ passed keyword args: {kw_args_len}" "traditional_chinese" => lhs_typ.push_str("左邊: "), "english" => lhs_typ.push_str("lhs: "), ); - lhs_typ.push_str_with_color_and_attribute(&format!("{}", lhs_t), WARN, Attribute::Bold); + lhs_typ.push_str_with_color_and_attribute(format!("{}", lhs_t), WARN, ATTR); let mut rhs_typ = StyledStrings::default(); switch_lang!( "japanese" => rhs_typ.push_str("右辺: "), @@ -774,12 +771,12 @@ passed keyword args: {kw_args_len}" "traditional_chinese" => rhs_typ.push_str("右邊: "), "english" => rhs_typ.push_str("rhs: "), ); - rhs_typ.push_str_with_color_and_attribute(&format!("{}", rhs_t), WARN, Attribute::Bold); + rhs_typ.push_str_with_color_and_attribute(format!("{}", rhs_t), WARN, ATTR); Self::new( ErrorCore::new( vec![SubMessage::ambiguous_new( loc, - vec![lhs_typ.into(), rhs_typ.into()], + vec![lhs_typ.to_string(), rhs_typ.to_string()], None, )], switch_lang!( @@ -805,16 +802,34 @@ passed keyword args: {kw_args_len}" loc: Location, caused_by: String, ) -> Self { - let lhs_t = StyledString::new(&format!("{}", lhs_t), Some(WARN), Some(Attribute::Bold)); - let rhs_t = StyledString::new(&format!("{}", rhs_t), Some(WARN), Some(Attribute::Bold)); + let mut lhs_typ = StyledStrings::default(); + switch_lang!( + "japanese" => lhs_typ.push_str("左辺: "), + "simplified_chinese" => lhs_typ.push_str("左边: "), + "traditional_chinese" => lhs_typ.push_str("左邊: "), + "english" => lhs_typ.push_str("lhs: "), + ); + lhs_typ.push_str_with_color_and_attribute(format!("{}", lhs_t), WARN, ATTR); + let mut rhs_typ = StyledStrings::default(); + switch_lang!( + "japanese" => rhs_typ.push_str("右辺: "), + "simplified_chinese" => rhs_typ.push_str("右边: "), + "traditional_chinese" => rhs_typ.push_str("右邊: "), + "english" => rhs_typ.push_str("rhs: "), + ); + rhs_typ.push_str_with_color_and_attribute(format!("{}", rhs_t), WARN, ATTR); Self::new( ErrorCore::new( - vec![SubMessage::only_loc(loc)], + vec![SubMessage::ambiguous_new( + loc, + vec![lhs_typ.to_string(), rhs_typ.to_string()], + None, + )], switch_lang!( - "japanese" => format!("型の再単一化に失敗しました\n\n左辺: {lhs_t}\n右辺: {rhs_t}"), - "simplified_chinese" => format!("重新统一类型失败\n\n左边: {lhs_t}\n右边: {rhs_t}"), - "traditional_chinese" => format!("重新統一類型失敗\n\n左邊: {lhs_t}\n右邊: {rhs_t}"), - "english" => format!("re-unification failed\n\nlhs: {lhs_t}\nrhs: {rhs_t}"), + "japanese" => format!("型の再単一化に失敗しました"), + "simplified_chinese" => format!("重新统一类型失败"), + "traditional_chinese" => format!("重新統一類型失敗"), + "english" => format!("re-unification failed"), ), errno, TypeError, @@ -838,31 +853,31 @@ passed keyword args: {kw_args_len}" "japanese" => sub_type.push_str("部分型: "), "simplified_chinese" => sub_type.push_str("超类型: "), "simplified_chinese" =>sub_type.push_str("超類型: "), - "english" => sub_type.push_str("super type: "), + "english" => sub_type.push_str("subtype: "), ); - sub_type.push_str_with_color(&format!("{}", sub_t), WARN); + sub_type.push_str_with_color_and_attribute(format!("{}", sub_t), WARN, ATTR); let mut sup_type = StyledStrings::default(); switch_lang!( "japanese" => sup_type.push_str("汎化型: "), "simplified_chinese" => sup_type.push_str("超类型: "), "simplified_chinese" => sup_type.push_str("超類型: "), - "english" =>sup_type.push_str("super type: "), + "english" =>sup_type.push_str("supertype: "), ); - sup_type.push_str_with_color(&format!("{}", sup_t), WARN); + sup_type.push_str_with_color_and_attribute(format!("{}", sup_t), WARN, ATTR); Self::new( ErrorCore::new( vec![SubMessage::ambiguous_new( loc, - vec![sub_type.into(), sup_type.into()], + vec![sub_type.to_string(), sup_type.to_string()], None, )], switch_lang!( "japanese" => format!("この式の部分型制約を満たせません"), "simplified_chinese" => format!("无法满足此表达式中的子类型约束"), "traditional_chinese" => format!("無法滿足此表達式中的子類型約束"), - "english" => format!("the subtype constraint in this expression cannot be satisfied:"), + "english" => format!("the subtype constraint in this expression cannot be satisfied"), ), errno, TypeError, @@ -887,7 +902,7 @@ passed keyword args: {kw_args_len}" "traditional_chinese" => lhs_uni.push_str("左邊: "), "english" => lhs_uni.push_str("lhs: "), ); - lhs_uni.push_str_with_color_and_attribute(&format!("{}", lhs), WARN, Attribute::Bold); + lhs_uni.push_str_with_color_and_attribute(format!("{}", lhs), WARN, ATTR); let mut rhs_uni = StyledStrings::default(); switch_lang!( "japanese" => rhs_uni.push_str("右辺: "), @@ -895,12 +910,12 @@ passed keyword args: {kw_args_len}" "traditional_chinese" => rhs_uni.push_str("右邊: "), "english" => rhs_uni.push_str("rhs: "), ); - rhs_uni.push_str_with_color_and_attribute(&format!("{}", rhs), WARN, Attribute::Bold); + rhs_uni.push_str_with_color_and_attribute(format!("{}", rhs), WARN, ATTR); Self::new( ErrorCore::new( vec![SubMessage::ambiguous_new( Location::Unknown, - vec![lhs_uni.into(), rhs_uni.into()], + vec![lhs_uni.to_string(), rhs_uni.to_string()], None, )], switch_lang!( @@ -979,7 +994,7 @@ passed keyword args: {kw_args_len}" name: &str, hint: Option, ) -> Self { - let found = StyledString::new(name, Some(ERR), Some(Attribute::Bold)); + let found = StyledString::new(name, Some(ERR), Some(ATTR)); Self::new( ErrorCore::new( vec![SubMessage::ambiguous_new(loc, vec![], hint)], @@ -1019,28 +1034,39 @@ passed keyword args: {kw_args_len}" hint: Option, ) -> Self { let mut expct = StyledStrings::default(); - expct.push_str_with_color_and_attribute(&format!("{}", trait_type), WARN, Attribute::Bold); switch_lang!( - "japanese" => expct.push_str("で宣言された型: "), - "simplified_chinese" => expct.push_str("中声明的类型: "), - "traditional_chinese" => expct.push_str("中聲明的類型: "), - "english" => expct.push_str("declared in: "), + "japanese" => { + expct.push_str_with_color_and_attribute(format!("{}", trait_type), ACCENT, ATTR); + expct.push_str("で宣言された型: "); + }, + "simplified_chinese" => { + expct.push_str_with_color_and_attribute(format!("{}", trait_type), ACCENT, ATTR); + expct.push_str("中声明的类型: "); + }, + "traditional_chinese" => { + expct.push_str_with_color_and_attribute(format!("{}", trait_type), ACCENT, ATTR); + expct.push_str("中聲明的類型: "); + }, + "english" => { + expct.push_str("declared in "); + expct.push_str_with_color(format!("{}: ", trait_type), ACCENT); + }, ); - expct.push_str_with_color(&format!("{}", expect), HINT); + expct.push_str_with_color(format!("{}", expect), HINT); let mut fnd = StyledStrings::default(); - fnd.push_str_with_color_and_attribute(member_name, WARN, Attribute::Bold); switch_lang!( - "japanese" => expct.push_str("与えられた型: "), - "simplified_chinese" => expct.push_str("但找到: "), - "traditional_chinese" => expct.push_str("但找到: "), - "english" => expct.push_str("but found: "), + "japanese" => fnd.push_str("与えられた型: "), + "simplified_chinese" => fnd.push_str("但找到: "), + "traditional_chinese" => fnd.push_str("但找到: "), + "english" => fnd.push_str("but found: "), ); - fnd.push_str_with_color(&format!("{}", found), ERR); + fnd.push_str_with_color(format!("{}", found), ERR); + let member_name = StyledStr::new(member_name, Some(ACCENT), Some(ATTR)); Self::new( ErrorCore::new( vec![SubMessage::ambiguous_new( loc, - vec![expct.into(), fnd.into()], + vec![expct.to_string(), fnd.to_string()], hint, )], switch_lang!( @@ -1068,7 +1094,7 @@ passed keyword args: {kw_args_len}" class_type: &Type, hint: Option, ) -> Self { - let member_name = StyledString::new(member_name, Some(WARN), Some(Attribute::Bold)); + let member_name = StyledString::new(member_name, Some(WARN), Some(ATTR)); Self::new( ErrorCore::new( vec![SubMessage::ambiguous_new(Location::Unknown, vec![], hint)], @@ -1097,7 +1123,7 @@ passed keyword args: {kw_args_len}" class_type: &Type, hint: Option, ) -> Self { - let member_name = StyledString::new(member_name, Some(WARN), Some(Attribute::Bold)); + let member_name = StyledString::new(member_name, Some(WARN), Some(ATTR)); Self::new( ErrorCore::new( vec![SubMessage::ambiguous_new(Location::Unknown, vec![], hint)], @@ -1123,7 +1149,7 @@ passed keyword args: {kw_args_len}" loc: Location, caused_by: String, ) -> Self { - let found = StyledString::new(name, Some(ERR), Some(Attribute::Bold)); + let found = StyledString::new(name, Some(ERR), Some(ATTR)); Self::new( ErrorCore::new( vec![SubMessage::only_loc(loc)], @@ -1150,26 +1176,59 @@ passed keyword args: {kw_args_len}" caused_by: String, ) -> Self { let hint = Some( - switch_lang!( - "japanese" => "多相関数の場合は`f|T := Int|`, 型属性の場合は`T|T <: Trait|.X`などのようにして型を指定してください", - "simplified_chinese" => "如果是多态函数,请使用`f|T := Int|`,如果是类型属性,请使用`T|T <: Trait|.X`等方式指定类型", - "traditional_chinese" => "如果是多型函數,請使用`f|T := Int|`,如果是類型屬性,請使用`T|T <: Trait|.X`等方式指定類型", - "english" => "if it is a polymorphic function, use `f|T := Int|`, or if it is a type attribute, use `T|T <: Trait|.X` etc. to specify the type", - ).into(), - ); - let mut candi = StyledStrings::default(); - switch_lang!( - "japanese" => candi.push_str("候補: "), - "simplified_chinese" => candi.push_str("候选: "), - "traditional_chinese" => candi.push_str("候選: "), - "english" => candi.push_str("candidates: "), + switch_lang!( + "japanese" => { + let mut s = StyledStrings::default(); + s.push_str("多相関数の場合は"); + s.push_str_with_color("f|T := Int", ACCENT); + s.push_str(", 型属性の場合は"); + s.push_str_with_color("f|T := Trait|.X", ACCENT); + s.push_str(", などのようにして型を指定してください"); + s + }, + "simplified_chinese" => { + let mut s = StyledStrings::default(); + s.push_str("如果是多态函数,请使用"); + s.push_str_with_color("f|T := Int", ACCENT); + s.push_str(",如果是类型属性,请使用"); + s.push_str_with_color("f|T := Trait|.X", ACCENT); + s.push_str("等方式指定类型"); + s + }, + "traditional_chinese" => { + let mut s = StyledStrings::default(); + s.push_str("如果是多型函數,請使用"); + s.push_str_with_color("f|T := Int", ACCENT); + s.push_str(",如果是類型屬性,請使用"); + s.push_str_with_color("f|T := Trait|.X", ACCENT); + s.push_str("等方式指定類型"); + s + }, + "english" => { + let mut s = StyledStrings::default(); + s.push_str("if it is a polymorphic function, use "); + s.push_str_with_color("f|T := Int", ACCENT); + s.push_str(", or if it is a type attribute, use "); + s.push_str_with_color("f|T := Trait|.X", ACCENT); + s.push_str(" etc. to specify the type"); + s + }, + ) + .to_string(), ); - candi.push_str_with_color_and_attribute(&fmt_vec(candidates), WARN, Attribute::Bold); + let mut candidate = StyledStrings::default(); + switch_lang!( + "japanese" => candidate.push_str("候補: "), + "simplified_chinese" => candidate.push_str("候选: "), + "traditional_chinese" => candidate.push_str("候選: "), + "english" => candidate.push_str("candidates: "), + ); + candidate.push_str_with_color_and_attribute(&fmt_vec(candidates), WARN, ATTR); Self::new( ErrorCore::new( vec![SubMessage::ambiguous_new( expr.loc(), - vec![candi.into()], + vec![candidate.into()], hint, )], switch_lang!( @@ -1275,12 +1334,35 @@ impl EffectError { ) -> Self { let hint = Some( switch_lang!( - "japanese" => "変数の末尾に`!`をつけてください", - "simplified_chinese" => "请在变量名后加上`!`", - "traditional_chinese" => "請在變量名後加上`!`", - "english" => "add `!` to the end of the variable name", + "japanese" => { + let mut s = StyledStrings::default(); + s.push_str("変数の末尾に"); + s.push_str_with_color_and_attribute("!", ACCENT, ATTR); + s.push_str("をつけてください"); + s + }, + "simplified_chinese" => { + let mut s = StyledStrings::default(); + s.push_str("请在变量名后加上"); + s.push_str_with_color_and_attribute("!", ACCENT, ATTR); + s + }, + "traditional_chinese" => { + let mut s = StyledStrings::default(); + s.push_str("請在變量名後加上"); + s.push_str_with_color_and_attribute("!", ACCENT, ATTR); + s + }, + "english" => { + + let mut s = StyledStrings::default(); + s.push_str("add "); + s.push_str_with_color_and_attribute("!", ACCENT, ATTR); + s.push_str(" to the end of the variable name"); + s + }, ) - .into(), + .to_string(), ); Self::new( ErrorCore::new( @@ -1313,7 +1395,7 @@ impl OwnershipError { moved_loc: Location, caused_by: S, ) -> Self { - let found = StyledString::new(name, Some(ERR), Some(Attribute::Bold)); + let found = StyledString::new(name, Some(ERR), Some(ATTR)); Self::new( ErrorCore::new( vec![SubMessage::only_loc(name_loc)], @@ -1435,9 +1517,9 @@ impl LowerError { spec_t: &Type, found_t: &Type, ) -> Self { - let name = readable_name(name); - let expect = StyledString::new(&format!("{}", spec_t), Some(HINT), Some(Attribute::Bold)); - let found = StyledString::new(&format!("{}", found_t), Some(ERR), Some(Attribute::Bold)); + let name = StyledString::new(readable_name(name), Some(ACCENT), None); + let expect = StyledString::new(format!("{}", spec_t), Some(HINT), Some(ATTR)); + let found = StyledString::new(format!("{}", found_t), Some(ERR), Some(ATTR)); Self::new( ErrorCore::new( vec![SubMessage::only_loc(loc)], @@ -1466,7 +1548,7 @@ impl LowerError { ) -> Self { let name = readable_name(name); let hint = similar_name.map(|n| { - let n = StyledStr::new(n, Some(HINT), Some(Attribute::Bold)); + let n = StyledStr::new(n, Some(HINT), Some(ATTR)); switch_lang!( "japanese" => format!("似た名前の変数があります: {n}"), "simplified_chinese" => format!("存在相同名称变量: {n}"), @@ -1474,7 +1556,7 @@ impl LowerError { "english" => format!("exists a similar name variable: {n}"), ) }); - let found = StyledString::new(name, Some(ERR), Some(Attribute::Bold)); + let found = StyledString::new(name, Some(ERR), Some(ATTR)); Self::new( ErrorCore::new( vec![SubMessage::ambiguous_new(loc, vec![], hint)], @@ -1500,14 +1582,13 @@ impl LowerError { caused_by: String, typ: &Type, ) -> Self { - let typ = StyledString::new(&typ.to_string(), Some(ERR), Some(Attribute::Bold)); + let typ = StyledString::new(&typ.to_string(), Some(ERR), Some(ATTR)); let hint = Some(switch_lang!( - "japanese" => format!("恐らくこれはErgコンパイラのバグです、{URL}へ報告してください"), - "simplified_chinese" => format!("这可能是Erg编译器的错误,请报告给{URL}"), - "traditional_chinese" => format!("這可能是Erg編譯器的錯誤,請報告給{URL}"), - "english" => format!("This may be a bug of Erg compiler, please report to {URL}"), - ).into(), - ); + "japanese" => format!("恐らくこれはErgコンパイラのバグです、{URL}へ報告してください"), + "simplified_chinese" => format!("这可能是Erg编译器的错误,请报告给{URL}"), + "traditional_chinese" => format!("這可能是Erg編譯器的錯誤,請報告給{URL}"), + "english" => format!("This may be a bug of Erg compiler, please report to {URL}"), + )); Self::new( ErrorCore::new( vec![SubMessage::ambiguous_new(loc, vec![], hint)], @@ -1543,7 +1624,7 @@ impl LowerError { "english" => format!("has a similar name attribute: {n}"), ) }); - let found = StyledString::new(name, Some(ERR), Some(Attribute::Bold)); + let found = StyledString::new(name, Some(ERR), Some(ATTR)); Self::new( ErrorCore::new( vec![SubMessage::ambiguous_new(loc, vec![], hint)], @@ -1574,7 +1655,7 @@ impl LowerError { similar_name: Option<&str>, ) -> Self { let hint = similar_name.map(|n| { - let n = StyledStr::new(n, Some(HINT), Some(Attribute::Bold)); + let n = StyledStr::new(n, Some(HINT), Some(ATTR)); switch_lang!( "japanese" => format!("似た名前の属性があります: {n}"), "simplified_chinese" => format!("具有相同名称的属性: {n}"), @@ -1582,7 +1663,7 @@ impl LowerError { "english" => format!("has a similar name attribute: {n}"), ) }); - let found = StyledString::new(name, Some(ERR), Some(Attribute::Bold)); + let found = StyledString::new(name, Some(ERR), Some(ATTR)); Self::new( ErrorCore::new( vec![SubMessage::ambiguous_new(loc, vec![], hint)], @@ -1608,7 +1689,7 @@ impl LowerError { caused_by: String, name: &str, ) -> Self { - let name = StyledString::new(readable_name(name), Some(WARN), Some(Attribute::Bold)); + let name = StyledStr::new(readable_name(name), Some(WARN), Some(ATTR)); Self::new( ErrorCore::new( vec![SubMessage::only_loc(loc)], @@ -1634,7 +1715,7 @@ impl LowerError { name: &str, caused_by: String, ) -> Self { - let name = StyledString::new(readable_name(name), Some(WARN), Some(Attribute::Bold)); + let name = StyledString::new(readable_name(name), Some(WARN), Some(ATTR)); Self::new( ErrorCore::new( vec![SubMessage::only_loc(loc)], @@ -1654,11 +1735,7 @@ impl LowerError { } pub fn del_error(input: Input, errno: usize, ident: &Identifier, caused_by: String) -> Self { - let name = StyledString::new( - readable_name(ident.inspect()), - Some(WARN), - Some(Attribute::Bold), - ); + let name = StyledString::new(readable_name(ident.inspect()), Some(WARN), Some(ATTR)); Self::new( ErrorCore::new( vec![SubMessage::only_loc(ident.loc())], @@ -1701,7 +1778,7 @@ impl LowerError { "english" => "public", ) }; - let found = StyledString::new(name, Some(ERR), Some(Attribute::Bold)); + let found = StyledString::new(name, Some(ERR), Some(ATTR)); Self::new( ErrorCore::new( vec![SubMessage::only_loc(loc)], @@ -1728,12 +1805,8 @@ impl LowerError { superclass: &Type, caused_by: S, ) -> Self { - let name = StyledString::new(name, Some(ERR), Some(Attribute::Bold)); - let superclass = StyledString::new( - &format!("{}", superclass), - Some(WARN), - Some(Attribute::Bold), - ); + let name = StyledString::new(name, Some(ERR), Some(ATTR)); + let superclass = StyledString::new(format!("{}", superclass), Some(WARN), Some(ATTR)); let hint = Some( switch_lang!( "japanese" => "`Override`デコレータを使用してください", @@ -1753,7 +1826,7 @@ impl LowerError { ErrorCore::new( vec![SubMessage::ambiguous_new( name_loc, - vec![sub_msg.into()], + vec![sub_msg.to_string()], hint, )], switch_lang!( @@ -1853,24 +1926,23 @@ impl LowerError { let mut erg_str = StyledStrings::default(); let mut py_str = StyledStrings::default(); let hint = switch_lang!( - "japanese" => { match (similar_erg_mod, similar_py_mod) { (Some(erg), Some(py)) => { erg_str.push_str("似た名前のergモジュールが存在します: "); - erg_str.push_str_with_color_and_attribute(&erg, WARN, Attribute::Bold); + erg_str.push_str_with_color_and_attribute(erg, WARN, ATTR); py_str.push_str("似た名前のpythonモジュールが存在します: "); - py_str.push_str_with_color_and_attribute(&py, WARN, Attribute::Bold); + py_str.push_str_with_color_and_attribute(py, WARN, ATTR); Some("pythonのモジュールをインポートするためには`pyimport`を使用してください".to_string()) } (Some(erg), None) => { erg_str.push_str("似た名前のergモジュールが存在します"); - erg_str.push_str_with_color_and_attribute(&erg, WARN, Attribute::Bold); + erg_str.push_str_with_color_and_attribute(erg, WARN, ATTR); None } (None, Some(py)) => { py_str.push_str("似た名前のpythonモジュールが存在します"); - py_str.push_str_with_color_and_attribute(&py, WARN, Attribute::Bold); + py_str.push_str_with_color_and_attribute(py, WARN, ATTR); Some("pythonのモジュールをインポートするためには`pyimport`を使用してください".to_string()) } (None, None) => None, @@ -1880,19 +1952,19 @@ impl LowerError { match (similar_erg_mod, similar_py_mod) { (Some(erg), Some(py)) => { erg_str.push_str("存在相似名称的erg模块: "); - erg_str.push_str_with_color_and_attribute(&erg, WARN, Attribute::Bold); + erg_str.push_str_with_color_and_attribute(erg, WARN, ATTR); py_str.push_str("存在相似名称的python模块: "); - py_str.push_str_with_color_and_attribute(&py, WARN, Attribute::Bold); + py_str.push_str_with_color_and_attribute(py, WARN, ATTR); Some("要导入python模块,请使用`pyimport`".to_string()) } (Some(erg), None) => { erg_str.push_str("存在相似名称的erg模块: "); - erg_str.push_str_with_color_and_attribute(&erg, WARN, Attribute::Bold); + erg_str.push_str_with_color_and_attribute(erg, WARN, ATTR); None } (None, Some(py)) => { py_str.push_str("存在相似名称的python模块: "); - py_str.push_str_with_color_and_attribute(&py, WARN, Attribute::Bold); + py_str.push_str_with_color_and_attribute(py, WARN, ATTR); Some("要导入python模块,请使用`pyimport`".to_string()) } (None, None) => None, @@ -1902,19 +1974,19 @@ impl LowerError { match (similar_erg_mod, similar_py_mod) { (Some(erg), Some(py)) => { erg_str.push_str("存在類似名稱的erg模塊: "); - erg_str.push_str_with_color_and_attribute(&erg, WARN, Attribute::Bold); + erg_str.push_str_with_color_and_attribute(erg, WARN, ATTR); py_str.push_str("存在類似名稱的python模塊: "); - py_str.push_str_with_color_and_attribute(&py, WARN, Attribute::Bold); + py_str.push_str_with_color_and_attribute(py, WARN, ATTR); Some("要導入python模塊, 請使用`pyimport`".to_string()) } (Some(erg), None) => { erg_str.push_str("存在類似名稱的erg模塊: "); - erg_str.push_str_with_color_and_attribute(&erg, WARN, Attribute::Bold); + erg_str.push_str_with_color_and_attribute(erg, WARN, ATTR); None } (None, Some(py)) => { py_str.push_str("存在類似名稱的python模塊: "); - py_str.push_str_with_color_and_attribute(&py, WARN, Attribute::Bold); + py_str.push_str_with_color_and_attribute(py, WARN, ATTR); Some("要導入python模塊, 請使用`pyimport`".to_string()) } (None, None) => None, @@ -1924,32 +1996,35 @@ impl LowerError { match (similar_erg_mod, similar_py_mod) { (Some(erg), Some(py)) => { erg_str.push_str("similar name erg module exists: "); - erg_str.push_str_with_color_and_attribute(&erg, WARN, Attribute::Bold); + erg_str.push_str_with_color_and_attribute(erg, WARN, ATTR); py_str.push_str("similar name python module exists: "); - py_str.push_str_with_color_and_attribute(&py, WARN, Attribute::Bold); + py_str.push_str_with_color_and_attribute(py, WARN, ATTR); Some("to import python modules, use `pyimport`".to_string()) } (Some(erg), None) => { erg_str.push_str("similar name erg module exists: "); - erg_str.push_str_with_color_and_attribute(&erg, WARN, Attribute::Bold); + erg_str.push_str_with_color_and_attribute(erg, WARN, ATTR); None } (None, Some(py)) => { py_str.push_str("similar name python module: "); - py_str.push_str_with_color_and_attribute(&py, WARN, Attribute::Bold); + py_str.push_str_with_color_and_attribute(py, WARN, ATTR); Some("to import python modules, use `pyimport`".to_string()) } (None, None) => None, } }, ); + // .to_string().is_empty() is not necessarily empty because there are Color or Attribute that are not displayed + let msg = match (erg_str.is_empty(), py_str.is_empty()) { + (false, false) => vec![erg_str.to_string(), py_str.to_string()], + (false, true) => vec![erg_str.to_string()], + (true, false) => vec![py_str.to_string()], + (true, true) => vec![], + }; Self::new( ErrorCore::new( - vec![SubMessage::ambiguous_new( - loc, - vec![erg_str.into(), py_str.into()], - hint, - )], + vec![SubMessage::ambiguous_new(loc, msg, hint)], desc, errno, ImportError, @@ -2013,8 +2088,8 @@ impl LowerError { cast_to: &Type, hint: Option, ) -> Self { - let name = StyledString::new(name, Some(WARN), Some(Attribute::Bold)); - let found = StyledString::new(&format!("{}", cast_to), Some(WARN), Some(Attribute::Bold)); + let name = StyledString::new(name, Some(WARN), Some(ATTR)); + let found = StyledString::new(format!("{}", cast_to), Some(WARN), Some(ATTR)); Self::new( ErrorCore::new( vec![SubMessage::ambiguous_new(loc, vec![], hint)], From a42d3b704d2c91651353090384777ac12bf1add2 Mon Sep 17 00:00:00 2001 From: GreasySlug <9619abgoni@gmail.com> Date: Mon, 21 Nov 2022 14:31:14 +0900 Subject: [PATCH 15/23] Fix: not displaying when not cols --- compiler/erg_common/error.rs | 87 +++++++++++------- compiler/erg_common/style.rs | 2 +- compiler/erg_compiler/error.rs | 163 ++++++++++++++++++++++++++++++++- 3 files changed, 218 insertions(+), 34 deletions(-) diff --git a/compiler/erg_common/error.rs b/compiler/erg_common/error.rs index 4d827d5b..a02005b8 100644 --- a/compiler/erg_common/error.rs +++ b/compiler/erg_common/error.rs @@ -467,7 +467,15 @@ impl SubMessage { cxt.push_str_with_color(&mark.repeat(cmp::max(1, codes[i].len())), err_color); cxt.push_str("\n"); } - cxt.push_str("\n"); + cxt.push_str("\n\n"); + for msg in self.msg.iter() { + cxt.push_str(msg); + cxt.push_str("\n"); + } + if let Some(hint) = self.hint.as_ref() { + cxt.push_str(hint); + cxt.push_str("\n"); + } cxt.to_string() } Location::Line(lineno) => { @@ -482,17 +490,34 @@ impl SubMessage { cxt.push_str_with_color(&format!(" {lineno} {} ", vbar), gutter_color); cxt.push_str(&code); cxt.push_str("\n\n"); + for msg in self.msg.iter() { + cxt.push_str(msg); + cxt.push_str("\n"); + } + if let Some(hint) = self.hint.as_ref() { + cxt.push_str(hint); + cxt.push_str("\n"); + } + cxt.push_str("\n"); cxt.to_string() } Location::Unknown => match e.input() { Input::File(_) => "\n".to_string(), - other => { let (_, vbar) = chars.gutters(); let mut cxt = StyledStrings::default(); - cxt.push_str_with_color(&format!(" ? {}", vbar), gutter_color); + cxt.push_str_with_color(&format!(" ? {} ", vbar), gutter_color); cxt.push_str(&other.reread()); cxt.push_str("\n\n"); + for msg in self.msg.iter() { + cxt.push_str(msg); + cxt.push_str("\n"); + } + if let Some(hint) = self.hint.as_ref() { + cxt.push_str(hint); + cxt.push_str("\n"); + } + cxt.push_str("\n"); cxt.to_string() } }, @@ -566,7 +591,7 @@ impl ErrorCore { ) } - pub fn fmt_header(&self, kind: StyledString, caused_by: &str, input: &str) -> String { + pub fn fmt_header(&self, color: Color, caused_by: &str, input: &str) -> String { let loc = match self.loc { Location::Range { ln_begin, ln_end, .. @@ -578,7 +603,29 @@ impl ErrorCore { Location::Line(lineno) => format!(", line {lineno}"), Location::Unknown => "".to_string(), }; - format!("{kind}: File {input}{loc}{caused_by}",) + let kind = if self.kind.is_error() { + "Error" + } else if self.kind.is_warning() { + "Warning" + } else { + "Exception" + }; + let kind = self.theme.characters.error_kind_format(kind, self.errno); + format!( + "{kind}: File {input}{loc}{caused_by}", + kind = StyledStr::new(&kind, Some(color), Some(Attribute::Bold)) + ) + } + + fn specified_theme(&self) -> (Color, char) { + let (color, mark) = if self.kind.is_error() { + self.theme.error() + } else if self.kind.is_warning() { + self.theme.warning() + } else { + self.theme.exception() + }; + (color, mark) } } @@ -633,21 +680,10 @@ pub trait ErrorDisplay { fn show(&self) -> String { let core = self.core(); - let ((color, mark), kind) = if core.kind.is_error() { - (core.theme.error(), "Error") - } else if core.kind.is_warning() { - (core.theme.warning(), "Warning") - } else { - (core.theme.exception(), "Exception") - }; + let (color, mark) = core.specified_theme(); let (gutter_color, chars) = core.theme.characters(); - let kind = StyledString::new( - &chars.error_kind_format(kind, core.errno), - Some(color), - Some(Attribute::Bold), - ); let mut msg = String::new(); - msg += &core.fmt_header(kind, self.caused_by(), self.input().enclosed_name()); + msg += &core.fmt_header(color, self.caused_by(), self.input().enclosed_name()); msg += "\n\n"; for sub_msg in &core.sub_messages { msg += &sub_msg.format_code_and_pointer(self, color, gutter_color, mark, chars); @@ -660,23 +696,12 @@ pub trait ErrorDisplay { /// for fmt::Display fn format(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let core = self.core(); - let ((color, mark), kind) = if core.kind.is_error() { - (core.theme.error(), "Error") - } else if core.kind.is_warning() { - (core.theme.warning(), "Warning") - } else { - (core.theme.exception(), "Exception") - }; + let (color, mark) = core.specified_theme(); let (gutter_color, chars) = core.theme.characters(); - let kind = StyledString::new( - &chars.error_kind_format(kind, core.errno), - Some(color), - Some(Attribute::Bold), - ); write!( f, "{}\n\n", - core.fmt_header(kind, self.caused_by(), self.input().enclosed_name()) + core.fmt_header(color, self.caused_by(), self.input().enclosed_name()) )?; for sub_msg in &core.sub_messages { write!( diff --git a/compiler/erg_common/style.rs b/compiler/erg_common/style.rs index 2aa890e8..6e94f3fb 100644 --- a/compiler/erg_common/style.rs +++ b/compiler/erg_common/style.rs @@ -471,7 +471,7 @@ impl StyledStrings { false } - pub fn is_same_attribute(&self, attr: Attribute) -> bool { + fn is_same_attribute(&self, attr: Attribute) -> bool { if let Some(text) = self.texts.last() { if let Some(text_attr) = text.attribute { return text_attr == attr; diff --git a/compiler/erg_compiler/error.rs b/compiler/erg_compiler/error.rs index ea8868fb..f260da0c 100644 --- a/compiler/erg_compiler/error.rs +++ b/compiler/erg_compiler/error.rs @@ -2154,11 +2154,16 @@ pub type CompileWarnings = CompileErrors; #[cfg(test)] mod test { use super::TyCheckError; - use crate::{error::CompileError, ty::Type}; + use crate::{ + error::CompileError, + ty::{Predicate, Type}, + }; use erg_common::{config::Input, error::Location}; + // These Erg codes are not correct grammar. + // This test make sure sub_msg and hint are displayed correctly. #[test] - fn default_arg_error_test() { + fn default_error_format_confirmation() { let input = Input::Pipe("line error".into()); let loc = Location::Line(1); let err = CompileError::stack_bug(input, loc, 0, 0, "FileName"); @@ -2231,5 +2236,159 @@ mod test { Some("hint message here".into()), ); print!("{}", err); + + let input = Input::Pipe( + "f some_long_name_variable_1, + some_long_name_variable_2, + some_long_name_variable_3, + some_long_name_variable_4 =" + .to_string(), + ); + let errno = 0; + let loc = Location::LineRange(1, 4); + let callee_name = "callee name"; + let caused_by = "cause by".to_owned(); + let params_len = 3; + let pos_args_len = 4; + let kw_args_len = 4; + let err = TyCheckError::too_many_args_error( + input, + errno, + loc, + callee_name, + caused_by, + params_len, + pos_args_len, + kw_args_len, + ); + print!("{}", err); + + let input = Input::Pipe("Pearson = Class {.name = Str}".to_string()); + let errno = 0; + let loc = Location::range(1, 0, 1, 7); + let caused_by = "caused by".to_string(); + let err = TyCheckError::argument_error(input, errno, loc, caused_by, 1, 2); + print!("{}", err); + + let input = Input::Pipe("Nat <: Int <: Ratio".to_string()); + let loc = Location::range(1, 0, 1, 10); + let errno = 0; + let sub_t = &Type::Nat; + let sup_t = &Type::Int; + let caused_by = "caused_by".to_string(); + let err = TyCheckError::subtyping_error(input, errno, sub_t, sup_t, loc, caused_by); + print!("{}", err); + + /* + let input = Input::Pipe("".to_string()); + let errno = 0; + let expr = Location::Range { + ln_begin: 1, + col_begin: 1, + ln_end: 1, + col_end: 1, + }; + let candidates = &[Type::Int, Type::Nat, Type::Bool]; + let caused_by = "".to_string(); + let err = TyCheckError::ambiguous_type_error(input, errno, expr, candidates, caused_by); + println!("{}", err); + */ + + let input = Input::Pipe("pred unification error".to_string()); + let errno = 0; + let loc = Location::Range { + ln_begin: 1, + col_begin: 0, + ln_end: 1, + col_end: 10, + }; + let lhs = &Predicate::Const("Str".into()); + let rhs = &Predicate::Const("Str".into()); + let caused_by = "".to_string(); + let err = TyCheckError::pred_unification_error(input, errno, lhs, rhs, caused_by); + print!("{}", err); + + let input = Input::Pipe("Trait member type error".to_string()); + let errno = 0; + let t_ty = &Type::Float; + let exp = &Type::Nat; + let fnd = &Type::Obj; + let caused_by = "".to_string(); + let err = TyCheckError::trait_member_type_error( + input, + errno, + loc, + caused_by, + "member name", + t_ty, + exp, + fnd, + Some("sample".to_string()), + ); + print!("{}", err); + + let input = Input::Pipe("trait member not defined error".to_string()); + let errno = 0; + let caused_by = "".to_string(); + let member_name = "member name"; + let trait_type = &Type::ClassType; + let class_type = &Type::Ellipsis; + let hint = Some("hint message here".to_string()); + let err = TyCheckError::trait_member_not_defined_error( + input, + errno, + caused_by, + member_name, + trait_type, + class_type, + hint, + ); + print!("{}", err); + } + + #[test] + fn import_error_format_test() { + let input = Input::Pipe("import nunpy as np".to_string()); + let errno = 0; + let desc = "nunpy is not defined".to_string(); + let loc = Location::range(1, 7, 1, 12); + let caused_by = "".to_string(); + let similar_erg_mod = Some("numpyer".into()); + let similar_py_mod = Some("numpy".into()); + let imp_err = TyCheckError::import_error( + input.clone(), + errno, + desc.clone(), + loc, + caused_by.clone(), + similar_erg_mod.clone(), + similar_py_mod.clone(), + ); + println!("{}", imp_err); + + let imp_err = TyCheckError::import_error( + input.clone(), + errno, + desc.clone(), + loc, + caused_by.clone(), + None, + similar_py_mod, + ); + println!("{}", imp_err); + + let imp_err = TyCheckError::import_error( + input.clone(), + errno, + desc.clone(), + loc, + caused_by.clone(), + similar_erg_mod, + None, + ); + println!("{}", imp_err); + + let imp_err = TyCheckError::import_error(input, errno, desc, loc, caused_by, None, None); + println!("{}", imp_err); } } From f79eb2597569a45e3f8c7018fc8e3cdb35fbff4b Mon Sep 17 00:00:00 2001 From: GreasySlug <9619abgoni@gmail.com> Date: Mon, 21 Nov 2022 14:32:42 +0900 Subject: [PATCH 16/23] Clean: warning and miss --- compiler/erg_common/error.rs | 1 - compiler/erg_common/style.rs | 32 ++++++++++++++++---------------- 2 files changed, 16 insertions(+), 17 deletions(-) diff --git a/compiler/erg_common/error.rs b/compiler/erg_common/error.rs index a02005b8..5af2c41f 100644 --- a/compiler/erg_common/error.rs +++ b/compiler/erg_common/error.rs @@ -10,7 +10,6 @@ use crate::style::Attribute; use crate::style::Characters; use crate::style::Color; use crate::style::StyledStr; -use crate::style::StyledString; use crate::style::StyledStrings; use crate::style::Theme; use crate::style::THEME; diff --git a/compiler/erg_common/style.rs b/compiler/erg_common/style.rs index 6e94f3fb..5e686bf2 100644 --- a/compiler/erg_common/style.rs +++ b/compiler/erg_common/style.rs @@ -17,13 +17,13 @@ pub const RED: &str = "\x1b[91m"; pub const WHITE: &str = "\x1b[97m"; pub const YELLOW: &str = "\x1b[93m"; // custom colors when use `pretty` -pub const CUSTOM_RED: &str = "\x1b[38;2;185;64;71m"; -pub const CUSTOM_BLUE: &str = "\x1b[38;2;230;234;227m"; -pub const CUSTOM_GRAY: &str = "\x1b[38;2;244;0;25m"; -pub const CUSTOM_CYAN: &str = "\x1b[38;2;160;216;239m"; -pub const CUSTOM_MAGENTA: &str = "\x1b[38;2;103;65;150m"; -pub const CUSTOM_GREEN: &str = "\x1b[38;2;170;209;71m"; -pub const CUSTOM_YELLOW: &str = "\x1b[38;2;230;180;34m"; +pub const CUSTOM_RED: &str = "\x1b[38;2;255;76;76m"; +pub const CUSTOM_BLUE: &str = "\x1b[38;2;76;76;255"; +pub const CUSTOM_GRAY: &str = "\x1b[38;2;231;231;235m"; +pub const CUSTOM_CYAN: &str = "\x1b[38;2;76;255;255"; +pub const CUSTOM_MAGENTA: &str = "\x1b[38;2;165;76;255"; +pub const CUSTOM_GREEN: &str = "\x1b[38;2;76;255;76m"; +pub const CUSTOM_YELLOW: &str = "\x1b[38;2;255;255;76m"; #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Hash)] pub enum Color { @@ -70,7 +70,7 @@ impl Color { } } -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Hash)] pub enum Attribute { Reset, Underline, @@ -271,11 +271,7 @@ pub struct StyledStr<'a> { } impl<'a> StyledStr<'a> { - pub const fn new<'b: 'a>( - text: &'b str, - color: Option, - attribute: Option, - ) -> Self { + pub const fn new(text: &'a str, color: Option, attribute: Option) -> Self { Self { text, color, @@ -342,7 +338,11 @@ impl StyledString { /// println!("{text}"); // Two lines of text underlined are displayed /// ``` pub fn push_str(&mut self, s: &str) { - self.text.push_str(s); + self.text.push_str(s) + } + + pub fn is_empty(&self) -> bool { + self.text.is_empty() } } @@ -548,12 +548,12 @@ mod tests { Attribute::Bold, ); texts.push_str_with_color_and_attribute( - "White and underlined text\n", + "Blue and underlined text\n", Color::Blue, Attribute::Underline, ); texts.push_str_with_color_and_attribute( - "White and underlined text", + "Red and reversed text", Color::Red, Attribute::Reversed, ); From d080e21b78c3fc086b84acc5502e646c35acd0a6 Mon Sep 17 00:00:00 2001 From: GreasySlug <9619abgoni@gmail.com> Date: Mon, 21 Nov 2022 14:33:01 +0900 Subject: [PATCH 17/23] Update: doc comment --- compiler/erg_common/error.rs | 46 ++++++++++++++++++++++++++++++++++++ compiler/erg_common/style.rs | 21 +++++++++++++++- 2 files changed, 66 insertions(+), 1 deletion(-) diff --git a/compiler/erg_common/error.rs b/compiler/erg_common/error.rs index 5af2c41f..55198aec 100644 --- a/compiler/erg_common/error.rs +++ b/compiler/erg_common/error.rs @@ -397,10 +397,56 @@ pub struct SubMessage { } impl SubMessage { + /// + /// Used when the msg or hint si empty. + /// `msg` is Vec\ instead of Option\ because it can be used when there are multiple `msg`s as well as multiple lines. + /// # Example + /// ``` + /// let msg = SubMessage::ambiguous_new(loc, vec![], None); // this code same as only_loc() + /// + /// let hint = Some("hint message here".to_string()) + /// let msg = SubMessage::ambiguous_new(loc, vec![], hint); + /// /* example + /// ------- + /// `- hint message here + /// */ + /// + /// let hint = Some("hint here".to_string()) + /// let first = StyledString::new("1th message", Color::Red, None); + /// let second = StyledString::new("2th message", Color::White, None); + /// : + /// let nth = StyledString::new("nth message", Color::Green, None); + /// let msg = SubMessage::ambiguous_new( + /// loc, + /// vec![ + /// first.to_string(), + /// second.to_string(), + /// ..., + /// nth.to_string(), + /// ], + /// hint); + /// /* example + /// ------- + /// :- 1th message + /// :- 2th message + /// : + /// :- nth message + /// `- hint here + /// */ + /// + /// ``` + /// pub fn ambiguous_new(loc: Location, msg: Vec, hint: Option) -> Self { Self { loc, msg, hint } } + /// + /// Used when only Location is fixed. + /// In this case, error position is just modified + /// # Example + /// ``` + /// let sub_msg = SubMessage::only_loc(loc); + /// ``` pub fn only_loc(loc: Location) -> Self { Self { loc, diff --git a/compiler/erg_common/style.rs b/compiler/erg_common/style.rs index 5e686bf2..d67bb1a8 100644 --- a/compiler/erg_common/style.rs +++ b/compiler/erg_common/style.rs @@ -313,6 +313,14 @@ pub struct StyledString { } impl StyledString { + /// + /// # Example + /// ``` + /// let s = String::from("Hello, world"); + /// StyledString::new(s, None, None); + /// let s = "Hello, world"; + /// StyledString::new(s, None, None); + /// ``` pub fn new<'a, S: Into>>( s: S, color: Option, @@ -464,7 +472,18 @@ impl StyledStrings { } } - pub fn is_same_color(&self, color: Color) -> bool { + /// + /// Determine if all strings in Vec are empty + /// Returns False if any string is present. + /// + pub fn is_empty(&self) -> bool { + self.texts + .iter() + .inspect(|x| println!("{:#?}", x)) + .all(|s| s.is_empty()) + } + + fn is_same_color(&self, color: Color) -> bool { if let Some(text) = self.texts.last() { return text.color == Some(color); } From c100f344ab53aa8685e7ac10dc0a3d6eac88101f Mon Sep 17 00:00:00 2001 From: GreasySlug <9619abgoni@gmail.com> Date: Mon, 21 Nov 2022 14:58:59 +0900 Subject: [PATCH 18/23] Fix: forgot to add "m" at the end custom color --- compiler/erg_common/style.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/erg_common/style.rs b/compiler/erg_common/style.rs index d67bb1a8..2bc75e72 100644 --- a/compiler/erg_common/style.rs +++ b/compiler/erg_common/style.rs @@ -18,10 +18,10 @@ pub const WHITE: &str = "\x1b[97m"; pub const YELLOW: &str = "\x1b[93m"; // custom colors when use `pretty` pub const CUSTOM_RED: &str = "\x1b[38;2;255;76;76m"; -pub const CUSTOM_BLUE: &str = "\x1b[38;2;76;76;255"; +pub const CUSTOM_BLUE: &str = "\x1b[38;2;76;76;255m"; pub const CUSTOM_GRAY: &str = "\x1b[38;2;231;231;235m"; -pub const CUSTOM_CYAN: &str = "\x1b[38;2;76;255;255"; -pub const CUSTOM_MAGENTA: &str = "\x1b[38;2;165;76;255"; +pub const CUSTOM_CYAN: &str = "\x1b[38;2;76;255;255m"; +pub const CUSTOM_MAGENTA: &str = "\x1b[38;2;165;76;255m"; pub const CUSTOM_GREEN: &str = "\x1b[38;2;76;255;76m"; pub const CUSTOM_YELLOW: &str = "\x1b[38;2;255;255;76m"; From dad6fd199614c861a98df7f1dec0a3fc334da777 Mon Sep 17 00:00:00 2001 From: GreasySlug <9619abgoni@gmail.com> Date: Tue, 22 Nov 2022 14:29:24 +0900 Subject: [PATCH 19/23] Clean: into() convert to_string() or to_owned() --- compiler/erg_compiler/error.rs | 102 ++++++++++++++++----------------- compiler/erg_compiler/lower.rs | 21 ++++--- 2 files changed, 62 insertions(+), 61 deletions(-) diff --git a/compiler/erg_compiler/error.rs b/compiler/erg_compiler/error.rs index f260da0c..dcdbbcf1 100644 --- a/compiler/erg_compiler/error.rs +++ b/compiler/erg_compiler/error.rs @@ -147,11 +147,11 @@ impl ErrorDisplay for CompileError { // found, error const ERR: Color = THEME.colors.error; -// name +// var name, lhs, rhs const WARN: Color = THEME.colors.warning; // expect, hint const HINT: Color = THEME.colors.hint; -// url and var name +// url const ACCENT: Color = THEME.colors.accent; // url and feature = pretty const UNDERLINE: Attribute = Attribute::Underline; @@ -197,7 +197,7 @@ impl CompileError { loc, ), input, - "".into(), + "".to_owned(), ) } @@ -230,7 +230,7 @@ impl CompileError { loc, ), input, - "".into(), + "".to_owned(), ) } @@ -268,7 +268,7 @@ impl CompileError { Location::Unknown, ), Input::Dummy, - "".into(), + "".to_owned(), ) } } @@ -277,11 +277,11 @@ pub type TyCheckError = CompileError; impl TyCheckError { pub fn dummy(input: Input, errno: usize) -> Self { - Self::new(ErrorCore::dummy(errno), input, "".into()) + Self::new(ErrorCore::dummy(errno), input, "".to_string()) } pub fn unreachable(input: Input, fn_name: &str, line: u32) -> Self { - Self::new(ErrorCore::unreachable(fn_name, line), input, "".into()) + Self::new(ErrorCore::unreachable(fn_name, line), input, "".to_string()) } pub fn checker_bug( @@ -305,7 +305,7 @@ impl TyCheckError { loc, ), input, - "".into(), + "".to_string(), ) } @@ -385,7 +385,7 @@ impl TyCheckError { "traditional_chinese" => format!("(第{pos}個參數)"), "english" => format!(" (the {} argument)", ordinal_num(pos)), ), - None => "".into(), + None => "".to_owned(), }; let name = StyledString::new(format!("{}{}", name, ord), Some(WARN), Some(ATTR)); let mut expct = StyledStrings::default(); @@ -601,11 +601,11 @@ impl TyCheckError { } pub fn dummy_infer_error(input: Input, fn_name: &str, line: u32) -> Self { - Self::new(ErrorCore::unreachable(fn_name, line), input, "".into()) + Self::new(ErrorCore::unreachable(fn_name, line), input, "".to_owned()) } pub fn not_relation(input: Input, fn_name: &str, line: u32) -> Self { - Self::new(ErrorCore::unreachable(fn_name, line), input, "".into()) + Self::new(ErrorCore::unreachable(fn_name, line), input, "".to_owned()) } #[allow(clippy::too_many_arguments)] @@ -855,7 +855,7 @@ passed keyword args: {kw_args_len}" "simplified_chinese" =>sub_type.push_str("超類型: "), "english" => sub_type.push_str("subtype: "), ); - sub_type.push_str_with_color_and_attribute(format!("{}", sub_t), WARN, ATTR); + sub_type.push_str_with_color_and_attribute(format!("{}", sub_t), HINT, ATTR); let mut sup_type = StyledStrings::default(); switch_lang!( @@ -864,7 +864,7 @@ passed keyword args: {kw_args_len}" "simplified_chinese" => sup_type.push_str("超類型: "), "english" =>sup_type.push_str("supertype: "), ); - sup_type.push_str_with_color_and_attribute(format!("{}", sup_t), WARN, ATTR); + sup_type.push_str_with_color_and_attribute(format!("{}", sup_t), ERR, ATTR); Self::new( ErrorCore::new( @@ -902,7 +902,7 @@ passed keyword args: {kw_args_len}" "traditional_chinese" => lhs_uni.push_str("左邊: "), "english" => lhs_uni.push_str("lhs: "), ); - lhs_uni.push_str_with_color_and_attribute(format!("{}", lhs), WARN, ATTR); + lhs_uni.push_str_with_color_and_attribute(format!("{}", lhs), HINT, ATTR); let mut rhs_uni = StyledStrings::default(); switch_lang!( "japanese" => rhs_uni.push_str("右辺: "), @@ -910,7 +910,7 @@ passed keyword args: {kw_args_len}" "traditional_chinese" => rhs_uni.push_str("右邊: "), "english" => rhs_uni.push_str("rhs: "), ); - rhs_uni.push_str_with_color_and_attribute(format!("{}", rhs), WARN, ATTR); + rhs_uni.push_str_with_color_and_attribute(format!("{}", rhs), ERR, ATTR); Self::new( ErrorCore::new( vec![SubMessage::ambiguous_new( @@ -1228,7 +1228,7 @@ passed keyword args: {kw_args_len}" ErrorCore::new( vec![SubMessage::ambiguous_new( expr.loc(), - vec![candidate.into()], + vec![candidate.to_string()], hint, )], switch_lang!( @@ -1302,12 +1302,7 @@ pub type EffectError = TyCheckError; pub type EffectErrors = TyCheckErrors; impl EffectError { - pub fn has_effect>( - input: Input, - errno: usize, - expr: &Expr, - caused_by: S, - ) -> Self { + pub fn has_effect(input: Input, errno: usize, expr: &Expr, caused_by: String) -> Self { Self::new( ErrorCore::new( vec![SubMessage::only_loc(expr.loc())], @@ -1322,15 +1317,15 @@ impl EffectError { expr.loc(), ), input, - caused_by.into(), + caused_by, ) } - pub fn proc_assign_error>( + pub fn proc_assign_error( input: Input, errno: usize, sig: &Signature, - caused_by: S, + caused_by: String, ) -> Self { let hint = Some( switch_lang!( @@ -1378,7 +1373,7 @@ impl EffectError { sig.loc(), ), input, - caused_by.into(), + caused_by, ) } } @@ -1387,13 +1382,13 @@ pub type OwnershipError = TyCheckError; pub type OwnershipErrors = TyCheckErrors; impl OwnershipError { - pub fn move_error>( + pub fn move_error( input: Input, errno: usize, name: &str, name_loc: Location, moved_loc: Location, - caused_by: S, + caused_by: String, ) -> Self { let found = StyledString::new(name, Some(ERR), Some(ATTR)); Self::new( @@ -1422,7 +1417,7 @@ impl OwnershipError { name_loc, ), input, - caused_by.into(), + caused_by, ) } } @@ -1435,18 +1430,18 @@ pub type LowerResult = TyCheckResult; pub type SingleLowerResult = SingleTyCheckResult; impl LowerError { - pub fn syntax_error>( + pub fn syntax_error( input: Input, errno: usize, loc: Location, caused_by: String, - desc: S, + desc: String, hint: Option, ) -> Self { Self::new( ErrorCore::new( vec![SubMessage::ambiguous_new(loc, vec![], hint)], - desc.into(), + desc, errno, SyntaxError, loc, @@ -2007,7 +2002,7 @@ impl LowerError { None } (None, Some(py)) => { - py_str.push_str("similar name python module: "); + py_str.push_str("similar name python module exits: "); py_str.push_str_with_color_and_attribute(py, WARN, ATTR); Some("to import python modules, use `pyimport`".to_string()) } @@ -2155,7 +2150,7 @@ pub type CompileWarnings = CompileErrors; mod test { use super::TyCheckError; use crate::{ - error::CompileError, + error::{CompileError, LowerError}, ty::{Predicate, Type}, }; use erg_common::{config::Input, error::Location}; @@ -2164,12 +2159,12 @@ mod test { // This test make sure sub_msg and hint are displayed correctly. #[test] fn default_error_format_confirmation() { - let input = Input::Pipe("line error".into()); + let input = Input::Pipe("line error".to_owned()); let loc = Location::Line(1); let err = CompileError::stack_bug(input, loc, 0, 0, "FileName"); print!("{}", err); - let input = Input::Pipe("a: Nat = -1".into()); + let input = Input::Pipe("a: Nat = -1".to_owned()); let err = TyCheckError::checker_bug(input, 0, Location::Unknown, "name", 1); print!("{}", err); @@ -2233,7 +2228,7 @@ mod test { &expect, &found, None, - Some("hint message here".into()), + Some("hint message here".to_owned()), ); print!("{}", err); @@ -2279,21 +2274,6 @@ mod test { let err = TyCheckError::subtyping_error(input, errno, sub_t, sup_t, loc, caused_by); print!("{}", err); - /* - let input = Input::Pipe("".to_string()); - let errno = 0; - let expr = Location::Range { - ln_begin: 1, - col_begin: 1, - ln_end: 1, - col_end: 1, - }; - let candidates = &[Type::Int, Type::Nat, Type::Bool]; - let caused_by = "".to_string(); - let err = TyCheckError::ambiguous_type_error(input, errno, expr, candidates, caused_by); - println!("{}", err); - */ - let input = Input::Pipe("pred unification error".to_string()); let errno = 0; let loc = Location::Range { @@ -2344,6 +2324,24 @@ mod test { hint, ); print!("{}", err); + + let input = Input::Pipe("singular no attribute error".to_string()); + let caused_by = "".to_string(); + let obj_name = "ojb name"; + let obj_t = Type::Bool; + let name = "name"; + let similar_name = Some("object name"); + let err = LowerError::singular_no_attr_error( + input, + errno, + loc, + caused_by, + obj_name, + &obj_t, + name, + similar_name, + ); + print!("{err}"); } #[test] diff --git a/compiler/erg_compiler/lower.rs b/compiler/erg_compiler/lower.rs index ba73865f..d619c366 100644 --- a/compiler/erg_compiler/lower.rs +++ b/compiler/erg_compiler/lower.rs @@ -174,7 +174,7 @@ impl ASTLowerer { "traditional_chinese" => "如果您不想使用該值,請使用discard函數", "english" => "if you don't use the value, use discard function", ) - .into(), + .to_owned(), ), )) } else { @@ -231,7 +231,8 @@ impl ASTLowerer { "simplified_chinese" => "数组元素必须全部是相同类型", "traditional_chinese" => "數組元素必須全部是相同類型", "english" => "all elements of an array must be of the same type", - ), + ) + .to_owned(), Some( switch_lang!( "japanese" => "Int or Strなど明示的に型を指定してください", @@ -239,7 +240,7 @@ impl ASTLowerer { "traditional_chinese" => "請明確指定類型,例如: Int or Str", "english" => "please specify the type explicitly, e.g. Int or Str", ) - .into(), + .to_owned(), ), ))); } @@ -377,7 +378,8 @@ impl ASTLowerer { "simplified_chinese" => "集合元素必须全部是相同类型", "traditional_chinese" => "集合元素必須全部是相同類型", "english" => "all elements of a set must be of the same type", - ), + ) + .to_owned(), Some( switch_lang!( "japanese" => "Int or Strなど明示的に型を指定してください", @@ -385,7 +387,7 @@ impl ASTLowerer { "traditional_chinese" => "明確指定類型,例如: Int or Str", "english" => "please specify the type explicitly, e.g. Int or Str", ) - .into(), + .to_owned(), ), ))); } @@ -503,7 +505,8 @@ impl ASTLowerer { "simplified_chinese" => "Dict的值必须是同一类型", "traditional_chinese" => "Dict的值必須是同一類型", "english" => "Values of Dict must be the same type", - ), + ) + .to_owned(), Some( switch_lang!( "japanese" => "Int or Strなど明示的に型を指定してください", @@ -511,7 +514,7 @@ impl ASTLowerer { "traditional_chinese" => "明確指定類型,例如: Int or Str", "english" => "please specify the type explicitly, e.g. Int or Str", ) - .into(), + .to_owned(), ), ))); } @@ -657,7 +660,7 @@ impl ASTLowerer { line!() as usize, call.args.loc(), self.ctx.caused_by(), - "invalid assert casting type", + "invalid assert casting type".to_owned(), None, ))); } @@ -716,7 +719,7 @@ impl ASTLowerer { line!() as usize, other.loc(), self.ctx.caused_by(), - "", + "".to_owned(), None, ))) } From 8f4ced6b3866f50378090c0a16c15522f3bfc421 Mon Sep 17 00:00:00 2001 From: GreasySlug <9619abgoni@gmail.com> Date: Wed, 23 Nov 2022 11:39:18 +0900 Subject: [PATCH 20/23] Fix: remove inspect --- compiler/erg_common/style.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/compiler/erg_common/style.rs b/compiler/erg_common/style.rs index 2bc75e72..171a8830 100644 --- a/compiler/erg_common/style.rs +++ b/compiler/erg_common/style.rs @@ -477,10 +477,7 @@ impl StyledStrings { /// Returns False if any string is present. /// pub fn is_empty(&self) -> bool { - self.texts - .iter() - .inspect(|x| println!("{:#?}", x)) - .all(|s| s.is_empty()) + self.texts.iter().all(|s| s.is_empty()) } fn is_same_color(&self, color: Color) -> bool { From 955b86716e7dcee25da20a6f8be6691e8c6d7ec8 Mon Sep 17 00:00:00 2001 From: GreasySlug <9619abgoni@gmail.com> Date: Wed, 23 Nov 2022 11:42:48 +0900 Subject: [PATCH 21/23] Clean: remove blank line --- compiler/erg_common/error.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/compiler/erg_common/error.rs b/compiler/erg_common/error.rs index 55198aec..e5230e4f 100644 --- a/compiler/erg_common/error.rs +++ b/compiler/erg_common/error.rs @@ -463,6 +463,8 @@ impl SubMessage { self.hint } + // Line breaks are not included except for line breaks that signify the end of a sentence. + // In other words, do not include blank lines for formatting purposes. fn format_code_and_pointer( &self, e: &E, @@ -512,7 +514,7 @@ impl SubMessage { cxt.push_str_with_color(&mark.repeat(cmp::max(1, codes[i].len())), err_color); cxt.push_str("\n"); } - cxt.push_str("\n\n"); + cxt.push_str("\n"); for msg in self.msg.iter() { cxt.push_str(msg); cxt.push_str("\n"); @@ -534,7 +536,7 @@ impl SubMessage { let mut cxt = StyledStrings::default(); cxt.push_str_with_color(&format!(" {lineno} {} ", vbar), gutter_color); cxt.push_str(&code); - cxt.push_str("\n\n"); + cxt.push_str("\n"); for msg in self.msg.iter() { cxt.push_str(msg); cxt.push_str("\n"); @@ -553,7 +555,7 @@ impl SubMessage { let mut cxt = StyledStrings::default(); cxt.push_str_with_color(&format!(" ? {} ", vbar), gutter_color); cxt.push_str(&other.reread()); - cxt.push_str("\n\n"); + cxt.push_str("\n"); for msg in self.msg.iter() { cxt.push_str(msg); cxt.push_str("\n"); From 97a9b6f6d53b2ebeb30fac0c840862059d24d637 Mon Sep 17 00:00:00 2001 From: GreasySlug <9619abgoni@gmail.com> Date: Wed, 23 Nov 2022 13:46:20 +0900 Subject: [PATCH 22/23] Clean: add comma for visibility --- compiler/erg_common/error.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/erg_common/error.rs b/compiler/erg_common/error.rs index e5230e4f..714c8480 100644 --- a/compiler/erg_common/error.rs +++ b/compiler/erg_common/error.rs @@ -659,7 +659,7 @@ impl ErrorCore { }; let kind = self.theme.characters.error_kind_format(kind, self.errno); format!( - "{kind}: File {input}{loc}{caused_by}", + "{kind}: File {input}{loc}, {caused_by}", kind = StyledStr::new(&kind, Some(color), Some(Attribute::Bold)) ) } From 31f2d8901c19d33f56562bd1ce3ac71e83dff73b Mon Sep 17 00:00:00 2001 From: GreasySlug <9619abgoni@gmail.com> Date: Wed, 23 Nov 2022 13:48:53 +0900 Subject: [PATCH 23/23] Add: test code simply and modify format --- compiler/erg_compiler/error.rs | 423 +++++++++++++++++++++------------ 1 file changed, 267 insertions(+), 156 deletions(-) diff --git a/compiler/erg_compiler/error.rs b/compiler/erg_compiler/error.rs index dcdbbcf1..3c3e1904 100644 --- a/compiler/erg_compiler/error.rs +++ b/compiler/erg_compiler/error.rs @@ -212,18 +212,22 @@ impl CompileError { ErrorCore::new( vec![SubMessage::only_loc(loc)], switch_lang!( - "japanese" => format!("スタックの要素数が異常です (要素数: {stack_len}, ブロックID: {block_id})\n\ - これはコンパイラのバグです、開発者に報告して下さい ({URL})\n\ - {fn_name}より発生"), - "simplified_chinese" => format!("堆栈中的元素数无效(元素数: {stack_len},块id: {block_id})\n\ - 这是 Erg 编译器的一个错误,请报告它 ({URL})\n\ - 起因于: {fn_name}"), - "traditional_chinese" => format!("堆棧中的元素數無效(元素數: {stack_len},塊id: {block_id})\n\ - 這是 Erg 編譯器的一個錯誤,請報告它 ({URL})\n\ - 起因於: {fn_name}"), - "english" => format!("the number of elements in the stack is invalid (num of elems: {stack_len}, block id: {block_id})\n\ - this is a bug of the Erg compiler, please report it to {URL}\n\ - caused from: {fn_name}"), + "japanese" => format!("\ +スタックの要素数が異常です (要素数: {stack_len}, ブロックID: {block_id}) +これはコンパイラのバグです、開発者に報告して下さい ({URL}) +{fn_name}より発生"), + "simplified_chinese" => format!("\ +堆栈中的元素数无效(元素数: {stack_len},块id: {block_id}) +这是 Erg 编译器的一个错误,请报告它 ({URL}) +起因于: {fn_name}"), + "traditional_chinese" => format!("\ +堆棧中的元素數無效(元素數: {stack_len},塊id: {block_id})\n +這是 Erg 編譯器的一個錯誤,請報告它 ({URL}) +起因於: {fn_name}"), + "english" => format!("\ +the number of elements in the stack is invalid (num of elems: {stack_len}, block id: {block_id})\n +this is a bug of the Erg compiler, please report it to {URL} +caused from: {fn_name}"), ), 0, CompilerSystemError, @@ -1180,42 +1184,44 @@ passed keyword args: {kw_args_len}" "japanese" => { let mut s = StyledStrings::default(); s.push_str("多相関数の場合は"); - s.push_str_with_color("f|T := Int", ACCENT); - s.push_str(", 型属性の場合は"); - s.push_str_with_color("f|T := Trait|.X", ACCENT); - s.push_str(", などのようにして型を指定してください"); + s.push_str_with_color_and_attribute("f|T := Int|", ACCENT, ATTR); + s.push_str(", \n型属性の場合は"); + s.push_str_with_color_and_attribute("f|T := Trait|.X", ACCENT, ATTR); s }, "simplified_chinese" => { let mut s = StyledStrings::default(); s.push_str("如果是多态函数,请使用"); - s.push_str_with_color("f|T := Int", ACCENT); - s.push_str(",如果是类型属性,请使用"); - s.push_str_with_color("f|T := Trait|.X", ACCENT); - s.push_str("等方式指定类型"); + s.push_str_with_color_and_attribute("f|T := Int|", ACCENT, ATTR); + s.push_str(",\n如果是类型属性,请使用"); + s.push_str_with_color_and_attribute("f|T := Trait|.X", ACCENT, ATTR); s }, "traditional_chinese" => { let mut s = StyledStrings::default(); s.push_str("如果是多型函數,請使用"); - s.push_str_with_color("f|T := Int", ACCENT); - s.push_str(",如果是類型屬性,請使用"); - s.push_str_with_color("f|T := Trait|.X", ACCENT); - s.push_str("等方式指定類型"); + s.push_str_with_color_and_attribute("f|T := Int|", ACCENT, ATTR); + s.push_str(",\n如果是類型屬性,請使用"); + s.push_str_with_color_and_attribute("f|T := Trait|.X", ACCENT, ATTR); s }, "english" => { let mut s = StyledStrings::default(); - s.push_str("if it is a polymorphic function, use "); - s.push_str_with_color("f|T := Int", ACCENT); - s.push_str(", or if it is a type attribute, use "); - s.push_str_with_color("f|T := Trait|.X", ACCENT); - s.push_str(" etc. to specify the type"); + s.push_str("if it is a polymorphic function, like "); + s.push_str_with_color_and_attribute("f|T := Int|", ACCENT, ATTR); + s.push_str("\nif it is a type attribute, like "); + s.push_str_with_color_and_attribute("f|T := Trait|.X ", ACCENT, ATTR); s }, ) .to_string(), ); + let sub_msg = switch_lang!( + "japanese" => "型を指定してください", + "simplified_chinese" => "方式指定类型", + "traditional_chinese" => "specify the type", + "english" => "specify the type", + ); let mut candidate = StyledStrings::default(); switch_lang!( "japanese" => candidate.push_str("候補: "), @@ -1228,7 +1234,7 @@ passed keyword args: {kw_args_len}" ErrorCore::new( vec![SubMessage::ambiguous_new( expr.loc(), - vec![candidate.to_string()], + vec![sub_msg.to_string(), candidate.to_string()], hint, )], switch_lang!( @@ -1757,7 +1763,6 @@ impl LowerError { name: &str, vis: Visibility, ) -> Self { - let name = readable_name(name); let visibility = if vis.is_private() { switch_lang!( "japanese" => "非公開", @@ -1773,7 +1778,7 @@ impl LowerError { "english" => "public", ) }; - let found = StyledString::new(name, Some(ERR), Some(ATTR)); + let found = StyledString::new(readable_name(name), Some(ACCENT), Some(ATTR)); Self::new( ErrorCore::new( vec![SubMessage::only_loc(loc)], @@ -1804,12 +1809,35 @@ impl LowerError { let superclass = StyledString::new(format!("{}", superclass), Some(WARN), Some(ATTR)); let hint = Some( switch_lang!( - "japanese" => "`Override`デコレータを使用してください", - "simplified_chinese" => "请使用`Override`装饰器", - "traditional_chinese" => "請使用`Override`裝飾器", - "english" => "use `Override` decorator", + "japanese" => { + let mut ovr = StyledStrings::default(); + ovr.push_str_with_color_and_attribute("@Override", HINT, ATTR); + ovr.push_str("デコレータを使用してください"); + ovr + }, + "simplified_chinese" => { + let mut ovr = StyledStrings::default(); + ovr.push_str("请使用"); + ovr.push_str_with_color_and_attribute("@Override", HINT, ATTR); + ovr.push_str("装饰器"); + ovr + }, + "traditional_chinese" => { + let mut ovr = StyledStrings::default(); + ovr.push_str("請使用"); + ovr.push_str_with_color_and_attribute("@Override", HINT, ATTR); + ovr.push_str("裝飾器"); + ovr + }, + "english" => { + let mut ovr = StyledStrings::default(); + ovr.push_str("use "); + ovr.push_str_with_color_and_attribute("@Override", HINT, ATTR); + ovr.push_str(" decorator"); + ovr + }, ) - .into(), + .to_string(), ); let sub_msg = switch_lang!( "japanese" => "デフォルトでオーバーライドはできません", @@ -1925,20 +1953,28 @@ impl LowerError { match (similar_erg_mod, similar_py_mod) { (Some(erg), Some(py)) => { erg_str.push_str("似た名前のergモジュールが存在します: "); - erg_str.push_str_with_color_and_attribute(erg, WARN, ATTR); + erg_str.push_str_with_color_and_attribute(erg, HINT, ATTR); py_str.push_str("似た名前のpythonモジュールが存在します: "); - py_str.push_str_with_color_and_attribute(py, WARN, ATTR); - Some("pythonのモジュールをインポートするためには`pyimport`を使用してください".to_string()) + py_str.push_str_with_color_and_attribute(py, HINT, ATTR); + let mut hint = StyledStrings::default(); + hint.push_str("pythonのモジュールをインポートするためには"); + hint.push_str_with_color_and_attribute("pyimport", ACCENT, ATTR); + hint.push_str("を使用してください"); + Some(hint.to_string()) } (Some(erg), None) => { erg_str.push_str("似た名前のergモジュールが存在します"); - erg_str.push_str_with_color_and_attribute(erg, WARN, ATTR); + erg_str.push_str_with_color_and_attribute(erg, ACCENT, ATTR); None } (None, Some(py)) => { py_str.push_str("似た名前のpythonモジュールが存在します"); - py_str.push_str_with_color_and_attribute(py, WARN, ATTR); - Some("pythonのモジュールをインポートするためには`pyimport`を使用してください".to_string()) + py_str.push_str_with_color_and_attribute(py, HINT, ATTR); + let mut hint = StyledStrings::default(); + hint.push_str("pythonのモジュールをインポートするためには"); + hint.push_str_with_color_and_attribute("pyimport", ACCENT, ATTR); + hint.push_str("を使用してください"); + Some(hint.to_string()) } (None, None) => None, } @@ -1947,20 +1983,26 @@ impl LowerError { match (similar_erg_mod, similar_py_mod) { (Some(erg), Some(py)) => { erg_str.push_str("存在相似名称的erg模块: "); - erg_str.push_str_with_color_and_attribute(erg, WARN, ATTR); + erg_str.push_str_with_color_and_attribute(erg, HINT, ATTR); py_str.push_str("存在相似名称的python模块: "); - py_str.push_str_with_color_and_attribute(py, WARN, ATTR); - Some("要导入python模块,请使用`pyimport`".to_string()) + py_str.push_str_with_color_and_attribute(py, HINT, ATTR); + let mut hint = StyledStrings::default(); + hint.push_str("要导入python模块,请使用"); + hint.push_str_with_color_and_attribute("pyimport", ACCENT, ATTR); + Some(hint.to_string()) } (Some(erg), None) => { erg_str.push_str("存在相似名称的erg模块: "); - erg_str.push_str_with_color_and_attribute(erg, WARN, ATTR); + erg_str.push_str_with_color_and_attribute(erg, HINT, ATTR); None } (None, Some(py)) => { py_str.push_str("存在相似名称的python模块: "); - py_str.push_str_with_color_and_attribute(py, WARN, ATTR); - Some("要导入python模块,请使用`pyimport`".to_string()) + py_str.push_str_with_color_and_attribute(py, HINT, ATTR); + let mut hint = StyledStrings::default(); + hint.push_str("要导入python模块,请使用"); + hint.push_str_with_color_and_attribute("pyimport", ACCENT, ATTR); + Some(hint.to_string()) } (None, None) => None, } @@ -1969,20 +2011,26 @@ impl LowerError { match (similar_erg_mod, similar_py_mod) { (Some(erg), Some(py)) => { erg_str.push_str("存在類似名稱的erg模塊: "); - erg_str.push_str_with_color_and_attribute(erg, WARN, ATTR); + erg_str.push_str_with_color_and_attribute(erg, HINT, ATTR); py_str.push_str("存在類似名稱的python模塊: "); - py_str.push_str_with_color_and_attribute(py, WARN, ATTR); - Some("要導入python模塊, 請使用`pyimport`".to_string()) + py_str.push_str_with_color_and_attribute(py, HINT, ATTR); + let mut hint = StyledStrings::default(); + hint.push_str("要導入python模塊, 請使用"); + hint.push_str_with_color_and_attribute("pyimport", ACCENT, ATTR); + Some(hint.to_string()) } (Some(erg), None) => { erg_str.push_str("存在類似名稱的erg模塊: "); - erg_str.push_str_with_color_and_attribute(erg, WARN, ATTR); + erg_str.push_str_with_color_and_attribute(erg, HINT, ATTR); None } (None, Some(py)) => { py_str.push_str("存在類似名稱的python模塊: "); - py_str.push_str_with_color_and_attribute(py, WARN, ATTR); - Some("要導入python模塊, 請使用`pyimport`".to_string()) + py_str.push_str_with_color_and_attribute(py, HINT, ATTR); + let mut hint = StyledStrings::default(); + hint.push_str("要導入python模塊, 請使用"); + hint.push_str_with_color_and_attribute("pyimport", ACCENT, ATTR); + Some(hint.to_string()) } (None, None) => None, } @@ -1991,20 +2039,26 @@ impl LowerError { match (similar_erg_mod, similar_py_mod) { (Some(erg), Some(py)) => { erg_str.push_str("similar name erg module exists: "); - erg_str.push_str_with_color_and_attribute(erg, WARN, ATTR); + erg_str.push_str_with_color_and_attribute(erg, HINT, ATTR); py_str.push_str("similar name python module exists: "); - py_str.push_str_with_color_and_attribute(py, WARN, ATTR); - Some("to import python modules, use `pyimport`".to_string()) + py_str.push_str_with_color_and_attribute(py, HINT, ATTR); + let mut hint = StyledStrings::default(); + hint.push_str("to import python modules, use "); + hint.push_str_with_color_and_attribute("pyimport", ACCENT, ATTR); + Some(hint.to_string()) } (Some(erg), None) => { erg_str.push_str("similar name erg module exists: "); - erg_str.push_str_with_color_and_attribute(erg, WARN, ATTR); + erg_str.push_str_with_color_and_attribute(erg, HINT, ATTR); None } (None, Some(py)) => { py_str.push_str("similar name python module exits: "); - py_str.push_str_with_color_and_attribute(py, WARN, ATTR); - Some("to import python modules, use `pyimport`".to_string()) + py_str.push_str_with_color_and_attribute(py, HINT, ATTR); + let mut hint = StyledStrings::default(); + hint.push_str("to import python modules, use "); + hint.push_str_with_color_and_attribute("pyimport", ACCENT, ATTR); + Some(hint.to_string()) } (None, None) => None, } @@ -2084,7 +2138,7 @@ impl LowerError { hint: Option, ) -> Self { let name = StyledString::new(name, Some(WARN), Some(ATTR)); - let found = StyledString::new(format!("{}", cast_to), Some(WARN), Some(ATTR)); + let found = StyledString::new(format!("{}", cast_to), Some(ERR), Some(ATTR)); Self::new( ErrorCore::new( vec![SubMessage::ambiguous_new(loc, vec![], hint)], @@ -2150,99 +2204,97 @@ pub type CompileWarnings = CompileErrors; mod test { use super::TyCheckError; use crate::{ - error::{CompileError, LowerError}, + error::{CompileError, EvalError, LowerError}, + hir::Identifier, ty::{Predicate, Type}, + varinfo::VarInfo, }; use erg_common::{config::Input, error::Location}; + use erg_parser::ast::VarName; // These Erg codes are not correct grammar. // This test make sure sub_msg and hint are displayed correctly. #[test] fn default_error_format_confirmation() { - let input = Input::Pipe("line error".to_owned()); + let mut errors = Vec::new(); + + let input = Input::Pipe("stack bug error".to_owned()); let loc = Location::Line(1); let err = CompileError::stack_bug(input, loc, 0, 0, "FileName"); - print!("{}", err); + errors.push(err); - let input = Input::Pipe("a: Nat = -1".to_owned()); - let err = TyCheckError::checker_bug(input, 0, Location::Unknown, "name", 1); - print!("{}", err); + let input = Input::Pipe("checker bug error".to_owned()); + let errno = 0; + let err = TyCheckError::checker_bug(input, errno, Location::Unknown, "name", 1); + errors.push(err); let loc = Location::LineRange(1, 3); - let input = Input::Pipe( - "if True: - sample - end" - .to_string(), - ); - let caused_by = "File name here basically"; + let input = Input::Pipe("args\nmissing\nerror".to_string()); + let caused_by = ""; let err = TyCheckError::args_missing_error( input, - 0, + errno, loc, "\"Callee name here\"", caused_by.into(), 0, vec!["sample".into(), "args".into(), "here".into()], ); - print!("{}", err); - - let loc = Location::Range { - ln_begin: 1, - col_begin: 11, - ln_end: 1, - col_end: 14, - }; - let expect = Type::Nat; - let found = Type::Int; - let input = Input::Pipe("add(x, y): Nat = x - y".to_string()); - let caused_by = "File name here basically"; - let err = TyCheckError::return_type_error( - input, - 0, - loc, - caused_by.into(), - "name", - &expect, - &found, - ); - print!("{}", err); + errors.push(err); let loc = Location::Range { ln_begin: 1, col_begin: 0, ln_end: 1, - col_end: 1, + col_end: 17, }; let expect = Type::Nat; let found = Type::Int; - let input = Input::Pipe("a: Nat = -1".to_string()); - let caused_by = "File name here basically"; + let input = Input::Pipe("return type error".to_string()); + let name = "name"; + let err = TyCheckError::return_type_error( + input, + errno, + loc, + caused_by.to_string(), + name, + &expect, + &found, + ); + errors.push(err); + + let loc = Location::Range { + ln_begin: 1, + col_begin: 0, + ln_end: 1, + col_end: 4, + }; + let expect = Type::Nat; + let found = Type::Int; + let input = Input::Pipe("type mismatch error".to_string()); let err = TyCheckError::type_mismatch_error( input, - 0, + errno, loc, caused_by.into(), - "name", + name, Some(1), &expect, &found, None, Some("hint message here".to_owned()), ); - print!("{}", err); + errors.push(err); let input = Input::Pipe( - "f some_long_name_variable_1, + "too_many_args_error(some_long_name_variable_1, some_long_name_variable_2, some_long_name_variable_3, - some_long_name_variable_4 =" + some_long_name_variable_4) =" .to_string(), ); - let errno = 0; let loc = Location::LineRange(1, 4); let callee_name = "callee name"; - let caused_by = "cause by".to_owned(); let params_len = 3; let pos_args_len = 4; let kw_args_len = 4; @@ -2251,65 +2303,58 @@ mod test { errno, loc, callee_name, - caused_by, + caused_by.to_string(), params_len, pos_args_len, kw_args_len, ); - print!("{}", err); + errors.push(err); - let input = Input::Pipe("Pearson = Class {.name = Str}".to_string()); - let errno = 0; - let loc = Location::range(1, 0, 1, 7); - let caused_by = "caused by".to_string(); - let err = TyCheckError::argument_error(input, errno, loc, caused_by, 1, 2); - print!("{}", err); + let input = Input::Pipe("argument error".to_string()); + let loc = Location::range(1, 0, 1, 8); + let err = TyCheckError::argument_error(input, errno, loc, caused_by.to_string(), 1, 2); + errors.push(err); let input = Input::Pipe("Nat <: Int <: Ratio".to_string()); let loc = Location::range(1, 0, 1, 10); - let errno = 0; let sub_t = &Type::Nat; let sup_t = &Type::Int; - let caused_by = "caused_by".to_string(); - let err = TyCheckError::subtyping_error(input, errno, sub_t, sup_t, loc, caused_by); - print!("{}", err); + let err = + TyCheckError::subtyping_error(input, errno, sub_t, sup_t, loc, caused_by.to_string()); + errors.push(err); let input = Input::Pipe("pred unification error".to_string()); + let lhs = &Predicate::Const("Str".into()); + let rhs = &Predicate::Const("Nat".into()); + let err = + TyCheckError::pred_unification_error(input, errno, lhs, rhs, caused_by.to_string()); + errors.push(err); + + let input = Input::Pipe("Trait member type error".to_string()); let errno = 0; let loc = Location::Range { ln_begin: 1, col_begin: 0, ln_end: 1, - col_end: 10, + col_end: 5, }; - let lhs = &Predicate::Const("Str".into()); - let rhs = &Predicate::Const("Str".into()); - let caused_by = "".to_string(); - let err = TyCheckError::pred_unification_error(input, errno, lhs, rhs, caused_by); - print!("{}", err); - - let input = Input::Pipe("Trait member type error".to_string()); - let errno = 0; let t_ty = &Type::Float; let exp = &Type::Nat; let fnd = &Type::Obj; - let caused_by = "".to_string(); let err = TyCheckError::trait_member_type_error( input, errno, loc, - caused_by, + caused_by.to_string(), "member name", t_ty, exp, fnd, - Some("sample".to_string()), + Some("hint message here".to_string()), ); - print!("{}", err); + errors.push(err); let input = Input::Pipe("trait member not defined error".to_string()); - let errno = 0; - let caused_by = "".to_string(); let member_name = "member name"; let trait_type = &Type::ClassType; let class_type = &Type::Ellipsis; @@ -2317,76 +2362,142 @@ mod test { let err = TyCheckError::trait_member_not_defined_error( input, errno, - caused_by, + caused_by.to_string(), member_name, trait_type, class_type, hint, ); - print!("{}", err); + errors.push(err); let input = Input::Pipe("singular no attribute error".to_string()); - let caused_by = "".to_string(); + let loc = Location::Range { + ln_begin: 1, + col_begin: 0, + ln_end: 1, + col_end: 8, + }; let obj_name = "ojb name"; let obj_t = Type::Bool; let name = "name"; - let similar_name = Some("object name"); + let similar_name = Some("similar name"); let err = LowerError::singular_no_attr_error( input, errno, loc, - caused_by, + caused_by.to_string(), obj_name, &obj_t, name, similar_name, ); - print!("{err}"); - } + errors.push(err); + + let input = Input::Pipe("ambiguous type error".to_string()); + let expr = Identifier::new( + Some(erg_parser::token::Token { + kind: erg_parser::token::TokenKind::EOF, + content: "expr_content".into(), + lineno: 1, + col_begin: 1, + }), + VarName::from_str("variable_name".into()), + None, + VarInfo::new( + Type::Nat, + crate::varinfo::Mutability::Const, + erg_common::vis::Visibility::Private, + crate::varinfo::VarKind::Builtin, + None, + None, + None, + ), + ); + let candidates = &[Type::Nat, Type::Inf, Type::Bool]; + let err = + EvalError::ambiguous_type_error(input, errno, &expr, candidates, caused_by.to_string()); + errors.push(err); + + let input = Input::Pipe("invalid type cast error".to_string()); + let loc = Location::range(1, 8, 1, 17); + let cast_to = Type::Error; + let hint = Some("hint message here".to_string()); + let err = EvalError::invalid_type_cast_error( + input, + errno, + loc, + caused_by.to_string(), + name, + &cast_to, + hint, + ); + errors.push(err); + + let input = Input::Pipe("override error".to_string()); + let name_loc = Location::range(1, 0, 1, 8); + let superclass = &Type::Failure; + let err = TyCheckError::override_error( + input, + errno, + name, + name_loc, + superclass, + caused_by.to_string(), + ); + errors.push(err); + + let input = Input::Pipe("visibility error".to_string()); + let loc = Location::Line(1); + let vis = erg_common::vis::Visibility::Private; + let err = + TyCheckError::visibility_error(input, errno, loc, caused_by.to_string(), name, vis); + errors.push(err); - #[test] - fn import_error_format_test() { let input = Input::Pipe("import nunpy as np".to_string()); let errno = 0; let desc = "nunpy is not defined".to_string(); let loc = Location::range(1, 7, 1, 12); - let caused_by = "".to_string(); let similar_erg_mod = Some("numpyer".into()); let similar_py_mod = Some("numpy".into()); - let imp_err = TyCheckError::import_error( + let err = TyCheckError::import_error( input.clone(), errno, desc.clone(), loc, - caused_by.clone(), + caused_by.to_string(), similar_erg_mod.clone(), similar_py_mod.clone(), ); - println!("{}", imp_err); + errors.push(err); - let imp_err = TyCheckError::import_error( + let err = TyCheckError::import_error( input.clone(), errno, desc.clone(), loc, - caused_by.clone(), + caused_by.to_string(), None, similar_py_mod, ); - println!("{}", imp_err); + errors.push(err); - let imp_err = TyCheckError::import_error( + let err = TyCheckError::import_error( input.clone(), errno, desc.clone(), loc, - caused_by.clone(), + caused_by.to_string(), similar_erg_mod, None, ); - println!("{}", imp_err); + errors.push(err); - let imp_err = TyCheckError::import_error(input, errno, desc, loc, caused_by, None, None); - println!("{}", imp_err); + let err = + TyCheckError::import_error(input, errno, desc, loc, caused_by.to_string(), None, None); + errors.push(err); + + for err in errors.into_iter() { + print!("{err}"); + } } }