Merge pull request #232 from erg-lang/split-err-msg

Split error messages
This commit is contained in:
Shunsuke Shibayama 2022-11-23 15:55:19 +09:00 committed by GitHub
commit 2caa6b6ec9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 1652 additions and 1006 deletions

View file

@ -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(),

View file

@ -6,29 +6,39 @@ use crate::context::Context;
use crate::ty::constructors::{and, mono};
use crate::ty::value::{EvalValueResult, GenTypeObj, TypeObj, ValueObj};
use crate::ty::ValueArgs;
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<ValueObj> {
let require = args.remove_left_or_key("Requirement").ok_or_else(|| {
ErrorCore::new(
vec![SubMessage::only_loc(Location::Unknown)],
format!("{REQ_ERR} is not passed"),
line!() as usize,
ErrorKind::TypeError,
Location::Unknown,
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)],
format!(
"non-type object {require} is passed to {REQ_WARN}",
),
line!() as usize,
ErrorKind::TypeError,
Location::Unknown,
format!(
"non-type object {RED}{require}{RESET} is passed to {YELLOW}Requirement{RESET}",
),
None,
).into());
};
let impls = args.remove_left_or_key("Impl");
@ -40,23 +50,25 @@ pub fn class_func(mut args: ValueArgs, ctx: &Context) -> EvalValueResult<ValueOb
/// Super: ClassType, Impl := Type, Additional := Type -> ClassType
pub fn inherit_func(mut args: ValueArgs, ctx: &Context) -> EvalValueResult<ValueObj> {
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)],
format!("{sup} is not passed"),
line!() as usize,
ErrorKind::KeyError,
Location::Unknown,
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)],
format!(
"non-class object {sup_ty} is passed to {SUP_WARN}",
),
line!() as usize,
ErrorKind::TypeError,
Location::Unknown,
format!(
"non-class object {RED}{sup}{RESET} is passed to {YELLOW}Super{RESET}",
),
None,
).into());
};
let impls = args.remove_left_or_key("Impl");
@ -74,11 +86,11 @@ pub fn inherit_func(mut args: ValueArgs, ctx: &Context) -> EvalValueResult<Value
pub fn inheritable_func(mut args: ValueArgs, _ctx: &Context) -> EvalValueResult<ValueObj> {
let class = args.remove_left_or_key("Class").ok_or_else(|| {
ErrorCore::new(
vec![SubMessage::only_loc(Location::Unknown)],
format!("{CLASS_ERR} is not passed"),
line!() as usize,
ErrorKind::KeyError,
Location::Unknown,
format!("{RED}Class{RESET} is not passed"),
None,
)
})?;
match class {
@ -106,22 +118,23 @@ pub fn inheritable_func(mut args: ValueArgs, _ctx: &Context) -> EvalValueResult<
pub fn trait_func(mut args: ValueArgs, ctx: &Context) -> EvalValueResult<ValueObj> {
let require = args.remove_left_or_key("Requirement").ok_or_else(|| {
ErrorCore::new(
vec![SubMessage::only_loc(Location::Unknown)],
format!("{REQ_ERR} is not passed"),
line!() as usize,
ErrorKind::KeyError,
Location::Unknown,
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)],
format!(
"non-type object {require} is passed to {REQ_WARN}",
),
line!() as usize,
ErrorKind::TypeError,
Location::Unknown,
format!(
"non-type object {RED}{require}{RESET} is passed to {YELLOW}Requirement{RESET}",
),
None,
).into());
};
let impls = args.remove_left_or_key("Impl");
@ -134,22 +147,23 @@ pub fn trait_func(mut args: ValueArgs, ctx: &Context) -> EvalValueResult<ValueOb
pub fn subsume_func(mut args: ValueArgs, ctx: &Context) -> EvalValueResult<ValueObj> {
let sup = args.remove_left_or_key("Super").ok_or_else(|| {
ErrorCore::new(
vec![SubMessage::only_loc(Location::Unknown)],
format!("{SUP_ERR} is not passed"),
line!() as usize,
ErrorKind::KeyError,
Location::Unknown,
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)],
format!(
"non-trait object {sup} is passed to {SUP_WARN}",
),
line!() as usize,
ErrorKind::TypeError,
Location::Unknown,
format!(
"non-trait object {RED}{sup}{RESET} is passed to {YELLOW}Super{RESET}",
),
None,
).into());
};
let impls = args.remove_left_or_key("Impl");
@ -171,16 +185,16 @@ 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)],
format!(
"[{}] has {} elements, but accessed {}th element",
erg_common::fmt_vec(&slf),
slf.len(),
index
),
None,
line!() as usize,
ErrorKind::IndexError,
Location::Unknown,
)
.into())
}
@ -210,11 +224,11 @@ pub fn __dict_getitem__(mut args: ValueArgs, ctx: &Context) -> EvalValueResult<V
Ok(v.clone())
} else {
Err(ErrorCore::new(
vec![SubMessage::only_loc(Location::Unknown)],
format!("{slf} has no key {index}"),
line!() as usize,
ErrorKind::IndexError,
Location::Unknown,
format!("{slf} has no key {index}"),
None,
)
.into())
}
@ -235,11 +249,11 @@ pub fn __range_getitem__(mut args: ValueArgs, _ctx: &Context) -> EvalValueResult
Ok(ValueObj::Nat(start + index))
} else {
Err(ErrorCore::new(
vec![SubMessage::only_loc(Location::Unknown)],
format!("Index out of range: {}", index),
line!() as usize,
ErrorKind::IndexError,
Location::Unknown,
format!("Index out of range: {index}"),
None,
)
.into())
}

View file

@ -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};
@ -756,13 +756,21 @@ 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(),
vec![],
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,
e.core.loc,
);
TyCheckError::new(core, self.cfg.input.clone(), e.caused_by)
})
@ -797,12 +805,20 @@ 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(),
vec![],
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,
e.core.loc,
);
TyCheckError::new(core, self.cfg.input.clone(), e.caused_by)
})
@ -1052,7 +1068,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),
@ -1107,7 +1124,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),
@ -1164,7 +1182,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),

View file

@ -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,

File diff suppressed because it is too large Load diff

View file

@ -191,7 +191,7 @@ impl ASTLowerer {
"traditional_chinese" => "如果您不想使用該值請使用discard函數",
"english" => "if you don't use the value, use discard function",
)
.into(),
.to_owned(),
),
))
} else {
@ -266,7 +266,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など明示的に型を指定してください",
@ -274,7 +275,7 @@ impl ASTLowerer {
"traditional_chinese" => "請明確指定類型,例如: Int or Str",
"english" => "please specify the type explicitly, e.g. Int or Str",
)
.into(),
.to_owned(),
),
)));
}
@ -412,7 +413,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など明示的に型を指定してください",
@ -420,7 +422,7 @@ impl ASTLowerer {
"traditional_chinese" => "明確指定類型,例如: Int or Str",
"english" => "please specify the type explicitly, e.g. Int or Str",
)
.into(),
.to_owned(),
),
)));
}
@ -538,7 +540,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など明示的に型を指定してください",
@ -546,7 +549,7 @@ impl ASTLowerer {
"traditional_chinese" => "明確指定類型,例如: Int or Str",
"english" => "please specify the type explicitly, e.g. Int or Str",
)
.into(),
.to_owned(),
),
)));
}
@ -692,7 +695,7 @@ impl ASTLowerer {
line!() as usize,
call.args.loc(),
self.ctx.caused_by(),
"invalid assert casting type",
"invalid assert casting type".to_owned(),
None,
)));
}
@ -751,7 +754,7 @@ impl ASTLowerer {
line!() as usize,
other.loc(),
self.ctx.caused_by(),
"",
"".to_owned(),
None,
)))
}

View file

@ -5,7 +5,7 @@ use std::string::FromUtf8Error;
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};
@ -39,11 +39,11 @@ impl From<FromUtf8Error> for DeserializeError {
impl From<DeserializeError> 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::<String>::None,
)
}
}