diff --git a/compiler/erg_compiler/context/eval.rs b/compiler/erg_compiler/context/eval.rs index df67fb95..88a8c386 100644 --- a/compiler/erg_compiler/context/eval.rs +++ b/compiler/erg_compiler/context/eval.rs @@ -13,6 +13,8 @@ use erg_common::{dict, fn_name, option_enum_unwrap, set}; use erg_common::{RcArray, Str}; use OpKind::*; +use erg_parser::ast::Dict as AstDict; +use erg_parser::ast::Set as AstSet; use erg_parser::ast::*; use erg_parser::token::{Token, TokenKind}; @@ -227,10 +229,21 @@ impl Context { let args = self.eval_args(&call.args)?; self.call(subr, args, call.loc()) } - Accessor::Attr(_attr) => todo!(), - Accessor::TupleAttr(_attr) => todo!(), - Accessor::Subscr(_subscr) => todo!(), - Accessor::TypeApp(_type_app) => todo!(), + // TODO: eval attr + Accessor::Attr(_attr) => Err(EvalErrors::from(EvalError::not_const_expr( + self.cfg.input.clone(), + line!() as usize, + call.loc(), + self.caused_by(), + ))), + // TODO: eval type app + Accessor::TypeApp(_type_app) => Err(EvalErrors::from(EvalError::not_const_expr( + self.cfg.input.clone(), + line!() as usize, + call.loc(), + self.caused_by(), + ))), + _ => unreachable!(), } } else { todo!() @@ -306,6 +319,52 @@ impl Context { Ok(ValueObj::Array(RcArray::from(elems))) } + fn eval_const_set(&self, set: &AstSet) -> EvalResult { + let mut elems = vec![]; + match set { + AstSet::Normal(arr) => { + for elem in arr.elems.pos_args().iter() { + let elem = self.eval_const_expr(&elem.expr)?; + elems.push(elem); + } + } + _ => { + todo!() + } + } + Ok(ValueObj::Set(Set::from(elems))) + } + + fn eval_const_dict(&self, dict: &AstDict) -> EvalResult { + let mut elems = dict! {}; + match dict { + AstDict::Normal(dic) => { + for elem in dic.kvs.iter() { + let key = self.eval_const_expr(&elem.key)?; + let value = self.eval_const_expr(&elem.value)?; + elems.insert(key, value); + } + } + _ => { + todo!() + } + } + Ok(ValueObj::Dict(elems)) + } + + fn eval_const_tuple(&self, tuple: &Tuple) -> EvalResult { + let mut elems = vec![]; + match tuple { + Tuple::Normal(arr) => { + for elem in arr.elems.pos_args().iter() { + let elem = self.eval_const_expr(&elem.expr)?; + elems.push(elem); + } + } + } + Ok(ValueObj::Tuple(RcArray::from(elems))) + } + fn eval_const_record(&self, record: &Record) -> EvalResult { match record { Record::Normal(rec) => self.eval_const_normal_record(rec), @@ -456,9 +515,17 @@ impl Context { Expr::Call(call) => self.eval_const_call(call), Expr::Def(def) => self.eval_const_def(def), Expr::Array(arr) => self.eval_const_array(arr), + Expr::Set(set) => self.eval_const_set(set), + Expr::Dict(dict) => self.eval_const_dict(dict), + Expr::Tuple(tuple) => self.eval_const_tuple(tuple), Expr::Record(rec) => self.eval_const_record(rec), Expr::Lambda(lambda) => self.eval_const_lambda(lambda), - other => todo!("{other}"), + other => Err(EvalErrors::from(EvalError::not_const_expr( + self.cfg.input.clone(), + line!() as usize, + other.loc(), + self.caused_by(), + ))), } } diff --git a/compiler/erg_compiler/context/inquire.rs b/compiler/erg_compiler/context/inquire.rs index ae21919b..3d065a4b 100644 --- a/compiler/erg_compiler/context/inquire.rs +++ b/compiler/erg_compiler/context/inquire.rs @@ -351,19 +351,34 @@ impl Context { } } } + } else if let Some((name, _vi)) = self + .future_defined_locals + .get_key_value(&ident.inspect()[..]) + { + return Err(TyCheckError::access_before_def_error( + input.clone(), + line!() as usize, + ident.loc(), + namespace.into(), + ident.inspect(), + name.ln_begin().unwrap(), + self.get_similar_name(ident.inspect()), + )); } if let Some(parent) = self.get_outer().or_else(|| self.get_builtins()) { - if let Ok(vi) = parent.rec_get_var_info(ident, acc_kind, input, namespace) { - Ok(vi) - } else { - Err(TyCheckError::no_var_error( - input.clone(), - line!() as usize, - ident.loc(), - namespace.into(), - ident.inspect(), - self.get_similar_name(ident.inspect()), - )) + match parent.rec_get_var_info(ident, acc_kind, input, namespace) { + Ok(vi) => Ok(vi), + Err(err) if err.core.kind == ErrorKind::DummyError => { + Err(TyCheckError::no_var_error( + input.clone(), + line!() as usize, + ident.loc(), + namespace.into(), + ident.inspect(), + self.get_similar_name(ident.inspect()), + )) + } + Err(err) => Err(err), } } else { Err(TyCheckError::dummy( diff --git a/compiler/erg_compiler/context/mod.rs b/compiler/erg_compiler/context/mod.rs index a4d5a7f5..088793d9 100644 --- a/compiler/erg_compiler/context/mod.rs +++ b/compiler/erg_compiler/context/mod.rs @@ -346,6 +346,8 @@ pub struct Context { pub(crate) trait_impls: Dict>, /// stores declared names (not initialized) pub(crate) decls: Dict, + /// for error reporting + pub(crate) future_defined_locals: Dict, // stores defined names // 型の一致はHashMapでは判定できないため、keyはVarNameとして1つずつ見ていく /// ```python @@ -537,6 +539,7 @@ impl Context { trait_impls: Dict::default(), params: params_, decls: Dict::default(), + future_defined_locals: Dict::default(), locals: Dict::with_capacity(capacity), consts: Dict::default(), mono_types: Dict::default(), diff --git a/compiler/erg_compiler/context/register.rs b/compiler/erg_compiler/context/register.rs index 9c062f06..d91b122e 100644 --- a/compiler/erg_compiler/context/register.rs +++ b/compiler/erg_compiler/context/register.rs @@ -37,6 +37,8 @@ use Visibility::*; use super::instantiate::TyVarCache; +const UBAR: &Str = &Str::ever("_"); + impl Context { /// If it is a constant that is defined, there must be no variable of the same name defined across all scopes pub(crate) fn registered_info( @@ -62,35 +64,37 @@ impl Context { } } - fn _declare_var( + fn pre_define_var( &mut self, sig: &ast::VarSignature, opt_t: Option, id: Option, ) -> TyCheckResult<()> { - let muty = Mutability::from(&sig.inspect().unwrap()[..]); - match &sig.pat { - ast::VarPattern::Ident(ident) => { - let vis = ident.vis(); - let kind = id.map_or(VarKind::Declared, VarKind::Defined); - let sig_t = self.instantiate_var_sig_t(sig.t_spec.as_ref(), opt_t, PreRegister)?; - if let Some(_decl) = self.decls.remove(&ident.name) { - Err(TyCheckErrors::from(TyCheckError::duplicate_decl_error( - self.cfg.input.clone(), - line!() as usize, - sig.loc(), - self.caused_by(), - ident.name.inspect(), - ))) - } else { - self.decls.insert( - ident.name.clone(), - VarInfo::new(sig_t, muty, vis, kind, None, self.impl_of(), None), - ); - Ok(()) - } + let muty = Mutability::from(&sig.inspect().unwrap_or(UBAR)[..]); + let ident = match &sig.pat { + ast::VarPattern::Ident(ident) => ident, + ast::VarPattern::Discard(_) => { + return Ok(()); } _ => todo!(), + }; + let vis = ident.vis(); + let kind = id.map_or(VarKind::Declared, VarKind::Defined); + let sig_t = self.instantiate_var_sig_t(sig.t_spec.as_ref(), opt_t, PreRegister)?; + if let Some(_decl) = self.decls.remove(&ident.name) { + Err(TyCheckErrors::from(TyCheckError::duplicate_decl_error( + self.cfg.input.clone(), + line!() as usize, + sig.loc(), + self.caused_by(), + ident.name.inspect(), + ))) + } else { + self.future_defined_locals.insert( + ident.name.clone(), + VarInfo::new(sig_t, muty, vis, kind, None, self.impl_of(), None), + ); + Ok(()) } } @@ -555,8 +559,7 @@ impl Context { pub(crate) fn preregister_def(&mut self, def: &ast::Def) -> TyCheckResult<()> { let id = Some(def.body.id); - let ubar = Str::ever("_"); - let __name__ = def.sig.ident().map(|i| i.inspect()).unwrap_or(&ubar); + let __name__ = def.sig.ident().map(|i| i.inspect()).unwrap_or(UBAR); match &def.sig { ast::Signature::Subr(sig) => { if sig.is_const() { @@ -587,32 +590,39 @@ impl Context { self.declare_sub(sig, id)?; } } - ast::Signature::Var(sig) if sig.is_const() => { - let kind = ContextKind::from(def.def_kind()); - self.grow(__name__, kind, sig.vis(), None); - let (obj, const_t) = match self.eval_const_block(&def.body.block) { - Ok(obj) => (obj.clone(), v_enum(set! {obj})), - Err(e) => { - return Err(e); + ast::Signature::Var(sig) => { + if sig.is_const() { + let kind = ContextKind::from(def.def_kind()); + self.grow(__name__, kind, sig.vis(), None); + let (obj, const_t) = match self.eval_const_block(&def.body.block) { + Ok(obj) => (obj.clone(), v_enum(set! {obj})), + Err(e) => { + return Err(e); + } + }; + if let Some(spec) = sig.t_spec.as_ref() { + let mut dummy_tv_cache = TyVarCache::new(self.level, self); + let spec_t = self.instantiate_typespec( + spec, + None, + &mut dummy_tv_cache, + PreRegister, + false, + )?; + self.sub_unify(&const_t, &spec_t, def.body.loc(), None)?; } - }; - if let Some(spec) = sig.t_spec.as_ref() { - let mut dummy_tv_cache = TyVarCache::new(self.level, self); - let spec_t = self.instantiate_typespec( - spec, - None, - &mut dummy_tv_cache, - PreRegister, - false, - )?; - self.sub_unify(&const_t, &spec_t, def.body.loc(), None)?; - } - self.pop(); - if let Some(ident) = sig.ident() { - self.register_gen_const(ident, obj)?; + self.pop(); + if let Some(ident) = sig.ident() { + self.register_gen_const(ident, obj)?; + } + } else { + let opt_t = self + .eval_const_block(&def.body.block) + .map(|o| v_enum(set! {o})) + .ok(); + self.pre_define_var(sig, opt_t, id)?; } } - _ => {} } Ok(()) } diff --git a/compiler/erg_compiler/error.rs b/compiler/erg_compiler/error.rs index 706851ed..199e917e 100644 --- a/compiler/erg_compiler/error.rs +++ b/compiler/erg_compiler/error.rs @@ -1577,6 +1577,44 @@ impl LowerError { ) } + pub fn access_before_def_error( + input: Input, + errno: usize, + loc: Location, + caused_by: String, + name: &str, + defined_line: usize, + similar_name: Option<&str>, + ) -> Self { + let name = readable_name(name); + let hint = similar_name.map(|n| { + let n = StyledStr::new(n, Some(HINT), Some(ATTR)); + switch_lang!( + "japanese" => format!("似た名前の変数があります: {n}"), + "simplified_chinese" => format!("存在相同名称变量: {n}"), + "traditional_chinese" => format!("存在相同名稱變量: {n}"), + "english" => format!("exists a similar name variable: {n}"), + ) + }); + let found = StyledString::new(name, Some(ERR), Some(ATTR)); + Self::new( + ErrorCore::new( + vec![SubMessage::ambiguous_new(loc, vec![], hint)], + switch_lang!( + "japanese" => format!("定義({defined_line}行目)より前で{found}を参照することは出来ません"), + "simplified_chinese" => format!("在{found}定义({defined_line}行)之前引用是不允许的"), + "traditional_chinese" => format!("在{found}定義({defined_line}行)之前引用是不允許的"), + "english" => format!("cannot reference {found} before its definition (line {defined_line})"), + ), + errno, + NameError, + loc, + ), + input, + caused_by, + ) + } + pub fn no_type_error( input: Input, errno: usize, diff --git a/compiler/erg_compiler/ty/value.rs b/compiler/erg_compiler/ty/value.rs index f1ae8f49..7fdfd693 100644 --- a/compiler/erg_compiler/ty/value.rs +++ b/compiler/erg_compiler/ty/value.rs @@ -20,7 +20,7 @@ use erg_common::{dict, fmt_iter, impl_display_from_debug, switch_lang}; use erg_common::{RcArray, Str}; use super::codeobj::CodeObj; -use super::constructors::{array_t, mono, poly, refinement, set_t, tuple_t}; +use super::constructors::{array_t, dict_t, mono, poly, refinement, set_t, tuple_t}; use super::free::fresh_varname; use super::typaram::TyParam; use super::{ConstSubr, HasType, Predicate, Type}; @@ -743,7 +743,12 @@ impl ValueObj { arr.iter().next().unwrap().class(), TyParam::value(arr.len()), ), - Self::Dict(_dict) => todo!(), + Self::Dict(dict) => { + let tp = dict + .iter() + .map(|(k, v)| (TyParam::value(k.clone()), TyParam::value(v.clone()))); + dict_t(TyParam::Dict(tp.collect())) + } Self::Tuple(tup) => tuple_t(tup.iter().map(|v| v.class()).collect()), Self::Set(st) => set_t(st.iter().next().unwrap().class(), TyParam::value(st.len())), Self::Code(_) => Type::Code, @@ -771,7 +776,13 @@ impl ValueObj { Self::Array(arr) => poly( "Array!", vec![ - TyParam::t(arr.iter().next().unwrap().class()), + // REVIEW: Never? + TyParam::t( + arr.iter() + .next() + .map(|elem| elem.class()) + .unwrap_or(Type::Never), + ), TyParam::value(arr.len()).mutate(), ], ),