use std::option::Option; // conflicting to Type::Option use erg_common::traits::{Locational, Stream}; use erg_common::vis::Visibility; use erg_common::Str; use erg_common::{enum_unwrap, get_hash, log, set}; use erg_type::free::HasLevel; use ast::{DefId, VarName}; use erg_parser::ast; use erg_type::constructors::{enum_t, func, proc}; use erg_type::value::ValueObj; use erg_type::{HasType, ParamTy, SubrType, TyBound, Type}; use Type::*; use crate::context::{Context, DefaultInfo, RegistrationMode}; use crate::error::readable_name; use crate::error::{TyCheckError, TyCheckResult}; use crate::hir; use crate::varinfo::{Mutability, ParamIdx, VarInfo, VarKind}; use Mutability::*; use RegistrationMode::*; use Visibility::*; impl Context { fn registered(&self, name: &Str, recursive: bool) -> bool { if self.params.iter().any(|(maybe_name, _)| { maybe_name .as_ref() .map(|n| n.inspect() == name) .unwrap_or(false) }) || self.locals.contains_key(name) { return true; } if recursive { if let Some(outer) = &self.outer { outer.registered(name, recursive) } else { false } } else { false } } fn declare_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) => { if sig.t_spec.is_none() && opt_t.is_none() { Err(TyCheckError::no_type_spec_error( line!() as usize, sig.loc(), self.caused_by(), ident.inspect(), )) } else { if self.registered(ident.inspect(), ident.is_const()) { return Err(TyCheckError::duplicate_decl_error( line!() as usize, sig.loc(), self.caused_by(), ident.inspect(), )); } 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)?; self.decls .insert(ident.name.clone(), VarInfo::new(sig_t, muty, vis, kind)); Ok(()) } } _ => todo!(), } } pub(crate) fn declare_sub( &mut self, sig: &ast::SubrSignature, opt_ret_t: Option, id: Option, ) -> TyCheckResult<()> { let name = sig.ident.inspect(); let vis = sig.ident.vis(); let muty = Mutability::from(&name[..]); let kind = id.map_or(VarKind::Declared, VarKind::Defined); if self.registered(name, sig.is_const()) { return Err(TyCheckError::duplicate_decl_error( line!() as usize, sig.loc(), self.caused_by(), name, )); } let t = self.instantiate_sub_sig_t(sig, opt_ret_t, PreRegister)?; let vi = VarInfo::new(t, muty, vis, kind); if let Some(_decl) = self.decls.remove(name) { return Err(TyCheckError::duplicate_decl_error( line!() as usize, sig.loc(), self.caused_by(), name, )); } else { self.decls.insert(sig.ident.name.clone(), vi); } Ok(()) } pub(crate) fn assign_var_sig( &mut self, sig: &ast::VarSignature, body_t: &Type, id: DefId, ) -> TyCheckResult<()> { let ident = match &sig.pat { ast::VarPattern::Ident(ident) => ident, _ => todo!(), }; self.validate_var_sig_t(ident, sig.t_spec.as_ref(), body_t, Normal)?; let muty = Mutability::from(&ident.inspect()[..]); let generalized = self.generalize_t(body_t.clone()); if self.registered(ident.inspect(), ident.is_const()) { Err(TyCheckError::reassign_error( line!() as usize, ident.loc(), self.caused_by(), ident.inspect(), )) } else { if self.decls.remove(ident.inspect()).is_some() { // something to do? } let vis = ident.vis(); let vi = VarInfo::new(generalized, muty, vis, VarKind::Defined(id)); self.locals.insert(ident.name.clone(), vi); Ok(()) } } /// 宣言が既にある場合、opt_decl_tに宣言の型を渡す fn assign_param( &mut self, sig: &ast::ParamSignature, outer: Option, nth: usize, opt_decl_t: Option<&ParamTy>, ) -> TyCheckResult<()> { match &sig.pat { ast::ParamPattern::Discard(_token) => Ok(()), ast::ParamPattern::VarName(v) => { if self.registered(v.inspect(), v.inspect().is_uppercase()) { Err(TyCheckError::reassign_error( line!() as usize, v.loc(), self.caused_by(), v.inspect(), )) } else { // ok, not defined let spec_t = self.instantiate_param_sig_t(sig, opt_decl_t, Normal)?; let idx = if let Some(outer) = outer { ParamIdx::nested(outer, nth) } else { ParamIdx::Nth(nth) }; let default = if sig.opt_default_val.is_some() { DefaultInfo::WithDefault } else { DefaultInfo::NonDefault }; let kind = VarKind::parameter(DefId(get_hash(&(&self.name, v))), idx, default); self.params.push(( Some(v.clone()), VarInfo::new(spec_t, Immutable, Private, kind), )); Ok(()) } } ast::ParamPattern::Lit(_) => Ok(()), _ => unreachable!(), } } pub(crate) fn assign_params( &mut self, params: &ast::Params, opt_decl_subr_t: Option, ) -> TyCheckResult<()> { if let Some(decl_subr_t) = opt_decl_subr_t { for (nth, (sig, pt)) in params .non_defaults .iter() .zip(decl_subr_t.non_default_params.iter()) .enumerate() { self.assign_param(sig, None, nth, Some(pt))?; } for (nth, (sig, pt)) in params .defaults .iter() .zip(decl_subr_t.default_params.iter()) .enumerate() { // TODO: .clone() self.assign_param(sig, None, nth, Some(pt))?; } } else { for (nth, sig) in params .non_defaults .iter() .chain(params.defaults.iter()) .enumerate() { self.assign_param(sig, None, nth, None)?; } } Ok(()) } /// ## Errors /// * TypeError: if `return_t` != typeof `body` /// * AssignError: if `name` has already been registered pub(crate) fn assign_subr( &mut self, sig: &ast::SubrSignature, id: DefId, body_t: &Type, ) -> TyCheckResult<()> { let muty = if sig.ident.is_const() { Mutability::Const } else { Mutability::Immutable }; let name = &sig.ident.name; // FIXME: constでない関数 let t = self .get_current_scope_var(name.inspect()) .map(|v| &v.t) .unwrap(); let non_default_params = t.non_default_params().unwrap(); let var_args = t.var_args(); let default_params = t.default_params().unwrap(); if let Some(spec_ret_t) = t.return_t() { self.sub_unify(body_t, spec_ret_t, None, Some(sig.loc()), None) .map_err(|e| { TyCheckError::return_type_error( line!() as usize, e.core.loc, e.caused_by, readable_name(name.inspect()), spec_ret_t, body_t, ) })?; } if self.registered(name.inspect(), name.inspect().is_uppercase()) { Err(TyCheckError::reassign_error( line!() as usize, name.loc(), self.caused_by(), name.inspect(), )) } else { let sub_t = if sig.ident.is_procedural() { proc( non_default_params.clone(), var_args.as_ref().map(|v| *(*v).clone()), default_params.clone(), body_t.clone(), ) } else { func( non_default_params.clone(), var_args.as_ref().map(|v| *(*v).clone()), default_params.clone(), body_t.clone(), ) }; sub_t.lift(); let found_t = self.generalize_t(sub_t); if let Some(mut vi) = self.decls.remove(name) { if vi.t.has_unbound_var() { vi.t.lift(); vi.t = self.generalize_t(vi.t.clone()); } self.decls.insert(name.clone(), vi); } if let Some(vi) = self.decls.remove(name) { if !self.rec_supertype_of(&vi.t, &found_t) { return Err(TyCheckError::violate_decl_error( line!() as usize, sig.loc(), self.caused_by(), name.inspect(), &vi.t, &found_t, )); } } // TODO: visibility let vi = VarInfo::new(found_t, muty, Private, VarKind::Defined(id)); log!(info "Registered {}::{name}: {}", self.name, &vi.t); self.params.push((Some(name.clone()), vi)); Ok(()) } } // To allow forward references and recursive definitions pub(crate) fn preregister(&mut self, block: &ast::Block) -> TyCheckResult<()> { for expr in block.iter() { if let ast::Expr::Def(def) = expr { let id = Some(def.body.id); let __name__ = def.sig.ident().map(|i| i.inspect()); match &def.sig { ast::Signature::Subr(sig) => { let const_t = if sig.is_const() { match self.eval_const_block(&def.body.block, __name__) { Ok(obj) => { self.register_const(__name__.unwrap(), obj.clone()); Some(enum_t(set![obj])) } Err(e) => { return Err(e); } } } else { None }; let opt_ret_t = if let Some(spec) = sig.return_t_spec.as_ref() { let spec_t = self.instantiate_typespec(spec, PreRegister)?; if let Some(const_t) = const_t { self.sub_unify( &const_t, &spec_t, Some(def.body.loc()), None, None, )?; } Some(spec_t) } else { const_t }; self.declare_sub(sig, opt_ret_t, id)?; } ast::Signature::Var(sig) if sig.is_const() => { let const_t = if sig.is_const() { match self.eval_const_block(&def.body.block, __name__) { Ok(obj) => { self.register_const(__name__.unwrap(), obj.clone()); Some(enum_t(set![obj])) } Err(e) => { return Err(e); } } } else { None }; let t = if let Some(spec) = sig.t_spec.as_ref() { let spec_t = self.instantiate_typespec(spec, PreRegister)?; if let Some(const_t) = const_t { self.sub_unify( &const_t, &spec_t, Some(def.body.loc()), None, None, )?; } Some(spec_t) } else { const_t }; self.declare_var(sig, t, id)?; } _ => {} } } } Ok(()) } pub(crate) fn import_mod( &mut self, var_name: &VarName, mod_name: &hir::Expr, ) -> TyCheckResult<()> { match mod_name { hir::Expr::Lit(lit) => { if self.rec_subtype_of(&lit.value.class(), &Str) { let name = enum_unwrap!(lit.value.clone(), ValueObj::Str); match &name[..] { "importlib" => { self.mods .insert(var_name.clone(), Self::init_py_importlib_mod()); } "io" => { self.mods.insert(var_name.clone(), Self::init_py_io_mod()); } "math" => { self.mods.insert(var_name.clone(), Self::init_py_math_mod()); } "random" => { self.mods .insert(var_name.clone(), Self::init_py_random_mod()); } "socket" => { self.mods .insert(var_name.clone(), Self::init_py_socket_mod()); } "sys" => { self.mods.insert(var_name.clone(), Self::init_py_sys_mod()); } "time" => { self.mods.insert(var_name.clone(), Self::init_py_time_mod()); } other => todo!("importing {other}"), } } else { return Err(TyCheckError::type_mismatch_error( line!() as usize, mod_name.loc(), self.caused_by(), "import::name", &Str, mod_name.ref_t(), self.get_type_mismatch_hint(&Str, mod_name.ref_t()), )); } } _ => { return Err(TyCheckError::feature_error( line!() as usize, mod_name.loc(), "non-literal importing", self.caused_by(), )) } } Ok(()) } pub(crate) fn _push_subtype_bound(&mut self, sub: Type, sup: Type) { self.bounds.push(TyBound::subtype_of(sub, sup)); } pub(crate) fn _push_instance_bound(&mut self, name: Str, t: Type) { self.bounds.push(TyBound::instance(name, t)); } }