From 622e1fa350adb3030ba88f4552fb647b75e517cc Mon Sep 17 00:00:00 2001 From: Shunsuke Shibayama Date: Fri, 30 Sep 2022 15:46:27 +0900 Subject: [PATCH] Fix lowerer crash bugs --- compiler/erg_compiler/context/inquire.rs | 39 +++++++++++++++++------ compiler/erg_compiler/context/register.rs | 22 ++++++++----- compiler/erg_compiler/error.rs | 32 +++++++++++++++++++ compiler/erg_compiler/lower.rs | 38 +++++++++++++--------- 4 files changed, 99 insertions(+), 32 deletions(-) diff --git a/compiler/erg_compiler/context/inquire.rs b/compiler/erg_compiler/context/inquire.rs index 59c9dd0e..2b3dafa6 100644 --- a/compiler/erg_compiler/context/inquire.rs +++ b/compiler/erg_compiler/context/inquire.rs @@ -495,9 +495,15 @@ impl Context { self.get_similar_attr_from_singular(obj, method_name.inspect()), )); } - if let Some(trait_) = self.rec_get_method_traits(method_name) { - let (_, ctx) = self.get_nominal_type_ctx(trait_).unwrap(); - return ctx.rec_get_var_t(method_name, input, namespace); + match self.rec_get_method_traits(method_name) { + Ok(trait_) => { + let (_, ctx) = self.get_nominal_type_ctx(trait_).unwrap(); + return ctx.rec_get_var_t(method_name, input, namespace); + } + Err(err) if err.core.kind == ErrorKind::TypeError => { + return Err(err); + } + _ => {} } // TODO: patch Err(TyCheckError::no_attr_error( @@ -1561,17 +1567,32 @@ impl Context { } } - fn rec_get_method_traits(&self, name: &Identifier) -> Option<&Type> { - if let Some(t) = self.method_traits.get(name.inspect()) { - if t.len() == 1 { - Some(&t[0]) + fn rec_get_method_traits(&self, name: &Identifier) -> SingleTyCheckResult<&Type> { + if let Some(candidates) = self.method_traits.get(name.inspect()) { + let first_t = candidates.first().unwrap(); + if candidates.iter().skip(1).all(|t| t == first_t) { + Ok(&candidates[0]) } else { - None + Err(TyCheckError::ambiguous_type_error( + self.cfg.input.clone(), + line!() as usize, + name, + candidates, + self.caused_by(), + )) } } else if let Some(outer) = self.get_outer().or_else(|| self.get_builtins()) { outer.rec_get_method_traits(name) } else { - None + Err(TyCheckError::no_attr_error( + self.cfg.input.clone(), + line!() as usize, + name.loc(), + self.caused_by(), + &Type::Failure, + name.inspect(), + None, + )) } } diff --git a/compiler/erg_compiler/context/register.rs b/compiler/erg_compiler/context/register.rs index 9a236862..06a01b68 100644 --- a/compiler/erg_compiler/context/register.rs +++ b/compiler/erg_compiler/context/register.rs @@ -50,11 +50,8 @@ impl Context { return Some((name, vi)); } if is_const { - if let Some(outer) = self.get_outer().or_else(|| self.get_builtins()) { - outer.registered_info(name, is_const) - } else { - None - } + let outer = self.get_outer().or_else(|| self.get_builtins())?; + outer.registered_info(name, is_const) } else { None } @@ -460,18 +457,27 @@ impl Context { // To allow forward references and recursive definitions pub(crate) fn preregister(&mut self, block: &ast::Block) -> TyCheckResult<()> { + let mut total_errs = TyCheckErrors::empty(); for expr in block.iter() { match expr { ast::Expr::Def(def) => { - self.preregister_def(def)?; + if let Err(errs) = self.preregister_def(def) { + total_errs.extend(errs.into_iter()); + } } ast::Expr::ClassDef(class_def) => { - self.preregister_def(&class_def.def)?; + if let Err(errs) = self.preregister_def(&class_def.def) { + total_errs.extend(errs.into_iter()); + } } _ => {} } } - Ok(()) + if total_errs.is_empty() { + Ok(()) + } else { + Err(total_errs) + } } pub(crate) fn preregister_def(&mut self, def: &ast::Def) -> TyCheckResult<()> { diff --git a/compiler/erg_compiler/error.rs b/compiler/erg_compiler/error.rs index 0069e10a..50adb5b8 100644 --- a/compiler/erg_compiler/error.rs +++ b/compiler/erg_compiler/error.rs @@ -920,6 +920,38 @@ passed keyword args: {RED}{kw_args_len}{RESET}" caused_by, ) } + + pub fn ambiguous_type_error( + input: Input, + errno: usize, + expr: &(impl Locational + Display), + candidates: &[Type], + caused_by: AtomicStr, + ) -> Self { + Self::new( + ErrorCore::new( + errno, + TypeError, + expr.loc(), + switch_lang!( + "japanese" => format!("{expr}の型を一意に決定できませんでした\n候補: {}", fmt_vec(candidates)), + "simplified_chinese" => format!("无法确定{expr}的类型\n候选:{}", fmt_vec(candidates)), + "traditional_chinese" => format!("無法確定{expr}的類型\n候選:{}", fmt_vec(candidates)), + "english" => format!("cannot determine the type of {expr}\ncandidates: {}", fmt_vec(candidates)), + ), + 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(), + ), + ), + input, + caused_by, + ) + } } pub type TyCheckErrors = CompileErrors; diff --git a/compiler/erg_compiler/lower.rs b/compiler/erg_compiler/lower.rs index 790c2a79..4e219fa5 100644 --- a/compiler/erg_compiler/lower.rs +++ b/compiler/erg_compiler/lower.rs @@ -508,16 +508,12 @@ impl ASTLowerer { ContextKind::Func }; self.ctx.grow(&name, kind, Private)?; - self.ctx - .assign_params(&lambda.sig.params, None) - .map_err(|e| { - self.pop_append_errs(); - e - })?; - self.ctx.preregister(&lambda.body).map_err(|e| { - self.pop_append_errs(); - e - })?; + if let Err(errs) = self.ctx.assign_params(&lambda.sig.params, None) { + self.errs.extend(errs.into_iter()); + } + if let Err(errs) = self.ctx.preregister(&lambda.body) { + self.errs.extend(errs.into_iter()); + } let body = self.lower_block(lambda.body).map_err(|e| { self.pop_append_errs(); e @@ -606,8 +602,13 @@ impl ASTLowerer { body: ast::DefBody, ) -> LowerResult { log!(info "entered {}({sig})", fn_name!()); - self.ctx.preregister(&body.block)?; - let block = self.lower_block(body.block)?; + if let Err(errs) = self.ctx.preregister(&body.block) { + self.errs.extend(errs.into_iter()); + } + let block = self.lower_block(body.block).map_err(|e| { + self.pop_append_errs(); + e + })?; let found_body_t = block.ref_t(); let opt_expect_body_t = self .ctx @@ -660,9 +661,16 @@ impl ASTLowerer { .t .clone(); let t = enum_unwrap!(t, Type::Subr); - self.ctx.assign_params(&sig.params, Some(t.clone()))?; - self.ctx.preregister(&body.block)?; - let block = self.lower_block(body.block)?; + if let Err(errs) = self.ctx.assign_params(&sig.params, Some(t.clone())) { + self.errs.extend(errs.into_iter()); + } + if let Err(errs) = self.ctx.preregister(&body.block) { + self.errs.extend(errs.into_iter()); + } + let block = self.lower_block(body.block).map_err(|e| { + self.pop_append_errs(); + e + })?; let found_body_t = block.ref_t(); let expect_body_t = t.return_t.as_ref(); if !sig.is_const() {