mirror of
https://github.com/erg-lang/erg.git
synced 2025-08-03 10:23:20 +00:00
chore: improve subr type mismatch hint
This commit is contained in:
parent
f0fdcaca9f
commit
cfd0d259a0
3 changed files with 79 additions and 31 deletions
|
@ -3,7 +3,7 @@ use erg_common::{option_enum_unwrap, switch_lang};
|
|||
|
||||
use crate::ty::typaram::TyParam;
|
||||
use crate::ty::value::ValueObj;
|
||||
use crate::ty::{HasType, Predicate, SubrKind, Type};
|
||||
use crate::ty::{HasType, Predicate, SubrKind, SubrType, Type};
|
||||
|
||||
use crate::context::Context;
|
||||
|
||||
|
@ -85,35 +85,22 @@ impl Context {
|
|||
let mut hint = StyledStrings::default();
|
||||
match (&expected, &found) {
|
||||
(Type::Subr(expt), Type::Subr(fnd)) => {
|
||||
if let (SubrKind::Func, SubrKind::Proc) = (expt.kind, fnd.kind) {
|
||||
switch_lang!(
|
||||
"japanese" => {
|
||||
hint.push_str("この仮引数は(副作用のない)関数を受け取りますが、プロシージャは副作用があるため受け取りません。副作用を取り除き、");
|
||||
hint.push_str_with_color_and_attr("=>", ERR, ATTR);
|
||||
hint.push_str("の代わりに");
|
||||
hint.push_str_with_color_and_attr("->", HINT, ATTR);
|
||||
hint.push_str("を使用する必要があります");
|
||||
},
|
||||
"simplified_chinese" => {
|
||||
hint.push_str("此参数接受函数(无副作用),但不接受过程,因为过程有副作用。你应该使用");
|
||||
hint.push_str_with_color_and_attr("=>", HINT, ATTR);
|
||||
hint.push_str("而不是");
|
||||
hint.push_str_with_color_and_attr("->", ERR, ATTR);
|
||||
},
|
||||
"traditional_chinese" => {
|
||||
hint.push_str("此參數接受函數(無副作用),但不接受過程,因為過程有副作用。你應該使用");
|
||||
hint.push_str_with_color_and_attr("=>", HINT, ATTR);
|
||||
hint.push_str("而不是");
|
||||
hint.push_str_with_color_and_attr("->", ERR, ATTR);
|
||||
},
|
||||
"english" => {
|
||||
hint.push_str("This param accepts func (without side-effects) but not proc because of side-effects. You should use ");
|
||||
hint.push_str_with_color_and_attr("=>", HINT, ATTR);
|
||||
hint.push_str(" instead of ");
|
||||
hint.push_str_with_color_and_attr("->", ERR, ATTR);
|
||||
},
|
||||
);
|
||||
return Some(hint.to_string());
|
||||
if let Some(hint) = self.get_subr_type_mismatch_hint(expt, fnd) {
|
||||
return Some(hint);
|
||||
}
|
||||
}
|
||||
(Type::Quantified(expt), Type::Subr(fnd)) => {
|
||||
if let Type::Subr(expt) = expt.as_ref() {
|
||||
if let Some(hint) = self.get_subr_type_mismatch_hint(expt, fnd) {
|
||||
return Some(hint);
|
||||
}
|
||||
}
|
||||
}
|
||||
(Type::Quantified(expt), Type::Quantified(fnd)) => {
|
||||
if let (Type::Subr(expt), Type::Subr(fnd)) = (expt.as_ref(), fnd.as_ref()) {
|
||||
if let Some(hint) = self.get_subr_type_mismatch_hint(expt, fnd) {
|
||||
return Some(hint);
|
||||
}
|
||||
}
|
||||
}
|
||||
(Type::And(l, r), found) => {
|
||||
|
@ -188,6 +175,54 @@ impl Context {
|
|||
}
|
||||
}
|
||||
|
||||
fn get_subr_type_mismatch_hint(&self, expected: &SubrType, found: &SubrType) -> Option<String> {
|
||||
let mut hint = StyledStrings::default();
|
||||
if let (SubrKind::Func, SubrKind::Proc) = (expected.kind, found.kind) {
|
||||
switch_lang!(
|
||||
"japanese" => {
|
||||
hint.push_str("この仮引数は(副作用のない)関数を受け取りますが、プロシージャは副作用があるため受け取りません。副作用を取り除き、");
|
||||
hint.push_str_with_color_and_attr("=>", ERR, ATTR);
|
||||
hint.push_str("の代わりに");
|
||||
hint.push_str_with_color_and_attr("->", HINT, ATTR);
|
||||
hint.push_str("を使用する必要があります");
|
||||
},
|
||||
"simplified_chinese" => {
|
||||
hint.push_str("此参数接受函数(无副作用),但不接受过程,因为过程有副作用。你应该使用");
|
||||
hint.push_str_with_color_and_attr("=>", HINT, ATTR);
|
||||
hint.push_str("而不是");
|
||||
hint.push_str_with_color_and_attr("->", ERR, ATTR);
|
||||
},
|
||||
"traditional_chinese" => {
|
||||
hint.push_str("此參數接受函數(無副作用),但不接受過程,因為過程有副作用。你應該使用");
|
||||
hint.push_str_with_color_and_attr("=>", HINT, ATTR);
|
||||
hint.push_str("而不是");
|
||||
hint.push_str_with_color_and_attr("->", ERR, ATTR);
|
||||
},
|
||||
"english" => {
|
||||
hint.push_str("This param accepts func (without side-effects) but not proc because of side-effects. You should use ");
|
||||
hint.push_str_with_color_and_attr("=>", HINT, ATTR);
|
||||
hint.push_str(" instead of ");
|
||||
hint.push_str_with_color_and_attr("->", ERR, ATTR);
|
||||
},
|
||||
);
|
||||
return Some(hint.to_string());
|
||||
}
|
||||
if let Some((expect, _found)) = expected
|
||||
.non_var_params()
|
||||
.zip(found.non_var_params())
|
||||
.find(|(expect, found)| expect.typ().is_ref() && !found.typ().is_ref())
|
||||
{
|
||||
let hint = switch_lang!(
|
||||
"japanese" => format!("{expect}は参照を受け取るよう宣言されましたが、実体が渡されています(refプレフィックスを追加してください)"),
|
||||
"simplified_chinese" => format!("{expect}被声明为接受引用,但实体被传递(请添加ref前缀)"),
|
||||
"traditional_chinese" => format!("{expect}被宣告為接受引用,但實體被傳遞(請添加ref前綴)"),
|
||||
"english" => format!("{expect} is declared as a reference parameter but definition is an owned parameter (add `ref` prefix)"),
|
||||
);
|
||||
return Some(hint);
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
pub(crate) fn get_no_candidate_hint(&self, proj: &Type) -> Option<String> {
|
||||
match proj {
|
||||
Type::Proj { lhs, rhs: _ } => {
|
||||
|
|
|
@ -2338,6 +2338,10 @@ impl ASTLowerer {
|
|||
.replace(impl_trait, class);
|
||||
unverified_names.remove(name);
|
||||
if !self.module.context.supertype_of(&replaced_decl_t, def_t) {
|
||||
let hint = self
|
||||
.module
|
||||
.context
|
||||
.get_simple_type_mismatch_hint(&replaced_decl_t, def_t);
|
||||
errors.push(LowerError::trait_member_type_error(
|
||||
self.cfg.input.clone(),
|
||||
line!() as usize,
|
||||
|
@ -2347,7 +2351,7 @@ impl ASTLowerer {
|
|||
impl_trait,
|
||||
&decl_vi.t,
|
||||
&vi.t,
|
||||
None,
|
||||
hint,
|
||||
));
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -2021,6 +2021,15 @@ impl Type {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn is_ref(&self) -> bool {
|
||||
match self {
|
||||
Self::FreeVar(fv) if fv.is_linked() => fv.crack().is_ref(),
|
||||
Self::Ref(_) => true,
|
||||
Self::Refinement(refine) => refine.t.is_ref(),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_structural(&self) -> bool {
|
||||
match self {
|
||||
Self::FreeVar(fv) if fv.is_linked() => fv.crack().is_structural(),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue