diff --git a/compiler/erg_compiler/context/inquire.rs b/compiler/erg_compiler/context/inquire.rs index 137fe0b3..40e7466a 100644 --- a/compiler/erg_compiler/context/inquire.rs +++ b/compiler/erg_compiler/context/inquire.rs @@ -284,6 +284,22 @@ impl Context { return Ok(vi.t()); } } + if let Some(ctx) = self.rec_get_singular_ctx(obj) { + if let Some(vi) = ctx.locals.get(method_name.inspect()) { + return Ok(vi.t()); + } else if let Some(vi) = ctx.decls.get(method_name.inspect()) { + return Ok(vi.t()); + } + return Err(TyCheckError::singular_no_attr_error( + line!() as usize, + method_name.loc(), + namespace.clone(), + obj.__name__().unwrap_or("?"), + obj.ref_t(), + method_name.inspect(), + self.get_similar_attr(obj.ref_t(), method_name.inspect()), + )); + } // TODO: patch Err(TyCheckError::no_attr_error( line!() as usize, @@ -993,6 +1009,15 @@ impl Context { } } + fn rec_get_singular_ctx(&self, obj: &hir::Expr) -> Option<&Context> { + match obj.ref_t() { + Type::Module => self.rec_get_mod(obj.__name__()?), + Type::Class => todo!(), + Type::Trait => todo!(), + _ => None, + } + } + pub(crate) fn rec_get_trait_impls(&self, name: &Str) -> Vec { let current = if let Some(impls) = self.trait_impls.get(name) { impls.clone() diff --git a/compiler/erg_compiler/error.rs b/compiler/erg_compiler/error.rs index 7c17226a..dd61fc78 100644 --- a/compiler/erg_compiler/error.rs +++ b/compiler/erg_compiler/error.rs @@ -442,6 +442,42 @@ impl TyCheckError { ) } + pub fn singular_no_attr_error( + errno: usize, + loc: Location, + caused_by: Str, + obj_name: &str, + obj_t: &Type, + name: &str, + similar_name: Option<&Str>, + ) -> Self { + let hint = similar_name.map(|n| { + let n = readable_name(n); + switch_lang!( + "japanese" => format!("似た名前の属性があります: {n}"), + "simplified_chinese" => format!("具有相同名称的属性:{n}"), + "traditional_chinese" => format!("具有相同名稱的屬性:{n}"), + "english" => format!("has a similar name attribute: {n}"), + ) + .into() + }); + Self::new( + ErrorCore::new( + errno, + AttributeError, + loc, + switch_lang!( + "japanese" => format!("{obj_name}(: {obj_t})に{RED}{name}{RESET}という属性はありません"), + "simplified_chinese" => format!("{obj_name}(: {obj_t})没有属性{RED}{name}{RESET}"), + "traditional_chinese" => format!("{obj_name}(: {obj_t})沒有屬性{RED}{name}{RESET}"), + "english" => format!("{obj_name}(: {obj_t}) has no attribute {RED}{name}{RESET}"), + ), + hint, + ), + caused_by, + ) + } + pub fn callable_impl_error<'a, C: Locational + Display>( errno: usize, callee: &C,