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, Identifier, VarName}; use erg_parser::ast; use erg_type::constructors::{enum_t, func, func1, proc, ref_, ref_mut}; use erg_type::value::{GenTypeObj, TypeKind, TypeObj, ValueObj}; use erg_type::{HasType, ParamTy, SubrType, TyBound, Type}; use Type::*; use crate::context::{ClassDefType, Context, DefaultInfo, RegistrationMode, TraitInstance}; 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 { /// 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( &self, name: &str, is_const: bool, ) -> Option<(&VarName, &VarInfo)> { if let Some((name, vi)) = self.params.iter().find(|(maybe_name, _)| { maybe_name .as_ref() .map(|n| &n.inspect()[..] == name) .unwrap_or(false) }) { return Some((name.as_ref().unwrap(), vi)); } else if let Some((name, vi)) = self.locals.get_key_value(name) { return Some((name, vi)); } if is_const { if let Some(outer) = &self.outer { outer.registered_info(name, is_const) } else { None } } else { None } } 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) => { 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(TyCheckError::duplicate_decl_error( 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), ); 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); let t = self.instantiate_sub_sig_t(sig, opt_ret_t, PreRegister)?; let comptime_decos = sig .decorators .iter() .filter_map(|deco| match &deco.0 { ast::Expr::Accessor(ast::Accessor::Ident(local)) if local.is_const() => { Some(local.inspect().clone()) } _ => None, }) .collect(); let vi = VarInfo::new(t, muty, vis, kind, Some(comptime_decos)); if let Some(_decl) = self.decls.remove(name) { 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<()> { // already defined as const if sig.is_const() { return Ok(()); } 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.decls.remove(ident.inspect()).is_some() { // something to do? } let vis = ident.vis(); let vi = VarInfo::new(generalized, muty, vis, VarKind::Defined(id), None); 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::Lit(_) => Ok(()), ast::ParamPattern::Discard(_token) => Ok(()), ast::ParamPattern::VarName(name) => { if self .registered_info(name.inspect(), name.is_const()) .is_some() { Err(TyCheckError::reassign_error( line!() as usize, name.loc(), self.caused_by(), name.inspect(), )) } else { // ok, not defined let spec_t = self.instantiate_param_sig_t(sig, opt_decl_t, Normal)?; if &name.inspect()[..] == "self" { let self_t = self.rec_get_self_t().unwrap(); self.sub_unify( &spec_t, &self_t, Some(name.loc()), None, Some(name.inspect()), )?; } 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, name))), idx, default); self.params.push(( Some(name.clone()), VarInfo::new(spec_t, Immutable, Private, kind, None), )); Ok(()) } } ast::ParamPattern::Ref(name) => { if self .registered_info(name.inspect(), name.is_const()) .is_some() { Err(TyCheckError::reassign_error( line!() as usize, name.loc(), self.caused_by(), name.inspect(), )) } else { // ok, not defined let spec_t = self.instantiate_param_sig_t(sig, opt_decl_t, Normal)?; if &name.inspect()[..] == "self" { let self_t = self.rec_get_self_t().unwrap(); self.sub_unify( &spec_t, &self_t, Some(name.loc()), None, Some(name.inspect()), )?; } let spec_t = ref_(spec_t); 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, name))), idx, default); self.params.push(( Some(name.clone()), VarInfo::new(spec_t, Immutable, Private, kind, None), )); Ok(()) } } ast::ParamPattern::RefMut(name) => { if self .registered_info(name.inspect(), name.is_const()) .is_some() { Err(TyCheckError::reassign_error( line!() as usize, name.loc(), self.caused_by(), name.inspect(), )) } else { // ok, not defined let spec_t = self.instantiate_param_sig_t(sig, opt_decl_t, Normal)?; if &name.inspect()[..] == "self" { let self_t = self.rec_get_self_t().unwrap(); self.sub_unify( &spec_t, &self_t, Some(name.loc()), None, Some(name.inspect()), )?; } let spec_t = ref_mut(spec_t.clone(), Some(spec_t)); 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, name))), idx, default); self.params.push(( Some(name.clone()), VarInfo::new(spec_t, Immutable, Private, kind, None), )); Ok(()) } } other => { log!(err "{other}"); 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<()> { // already defined as const if sig.is_const() { return Ok(()); } 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, ) })?; } let sub_t = if sig.ident.is_procedural() { proc( non_default_params.clone(), var_args.cloned(), default_params.clone(), body_t.clone(), ) } else { func( non_default_params.clone(), var_args.cloned(), 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.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, )); } } let comptime_decos = sig .decorators .iter() .filter_map(|deco| match &deco.0 { ast::Expr::Accessor(ast::Accessor::Ident(local)) if local.is_const() => { Some(local.inspect().clone()) } _ => None, }) .collect(); let vi = VarInfo::new( found_t, muty, sig.ident.vis(), VarKind::Defined(id), Some(comptime_decos), ); log!(info "Registered {}::{name}: {}", self.name, &vi.t); self.locals.insert(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() { match expr { ast::Expr::Def(def) => { self.preregister_def(def)?; } ast::Expr::ClassDef(class_def) => { self.preregister_def(&class_def.def)?; } _ => {} } } Ok(()) } pub(crate) fn preregister_def(&mut self, def: &ast::Def) -> TyCheckResult<()> { let id = Some(def.body.id); let __name__ = def.sig.ident().map(|i| i.inspect()); match &def.sig { ast::Signature::Subr(sig) => { if sig.is_const() { let (obj, const_t) = match self.eval_const_block(&def.body.block, __name__) { Ok(obj) => (obj.clone(), enum_t(set! {obj})), Err(e) => { return Err(e); } }; if let Some(spec) = sig.return_t_spec.as_ref() { let spec_t = self.instantiate_typespec(spec, PreRegister)?; self.sub_unify(&const_t, &spec_t, Some(def.body.loc()), None, None)?; } self.register_gen_const(def.sig.ident().unwrap(), obj)?; } else { let opt_ret_t = if let Some(spec) = sig.return_t_spec.as_ref() { let spec_t = self.instantiate_typespec(spec, PreRegister)?; Some(spec_t) } else { None }; self.declare_sub(sig, opt_ret_t, id)?; } } ast::Signature::Var(sig) if sig.is_const() => { let (obj, const_t) = match self.eval_const_block(&def.body.block, __name__) { Ok(obj) => (obj.clone(), enum_t(set! {obj})), Err(e) => { return Err(e); } }; if let Some(spec) = sig.t_spec.as_ref() { let spec_t = self.instantiate_typespec(spec, PreRegister)?; self.sub_unify(&const_t, &spec_t, Some(def.body.loc()), None, None)?; } self.register_gen_const(sig.ident().unwrap(), obj)?; } _ => {} } Ok(()) } /// e.g. .new fn register_auto_impl( &mut self, name: &'static str, t: Type, muty: Mutability, vis: Visibility, ) { let name = VarName::from_static(name); if self.locals.get(&name).is_some() { panic!("already registered: {name}"); } else { self.locals .insert(name, VarInfo::new(t, muty, vis, VarKind::Auto, None)); } } /// e.g. ::__new__ fn register_fixed_auto_impl( &mut self, name: &'static str, t: Type, muty: Mutability, vis: Visibility, ) { let name = VarName::from_static(name); if self.locals.get(&name).is_some() { panic!("already registered: {name}"); } else { self.locals .insert(name, VarInfo::new(t, muty, vis, VarKind::FixedAuto, None)); } } fn _register_gen_decl(&mut self, name: VarName, t: Type, vis: Visibility) { if self.decls.get(&name).is_some() { panic!("already registered: {name}"); } else { self.decls.insert( name, VarInfo::new(t, Immutable, vis, VarKind::Declared, None), ); } } fn _register_gen_impl(&mut self, name: VarName, t: Type, muty: Mutability, vis: Visibility) { if self.locals.get(&name).is_some() { panic!("already registered: {name}"); } else { let id = DefId(get_hash(&(&self.name, &name))); self.locals .insert(name, VarInfo::new(t, muty, vis, VarKind::Defined(id), None)); } } pub(crate) fn register_trait(&mut self, class: Type, trait_: Type, methods: Self) { self.super_traits.push(trait_.clone()); self.methods_list .push((ClassDefType::impl_trait(class, trait_), methods)); } pub(crate) fn register_marker_trait(&mut self, trait_: Type) { self.super_traits.push(trait_); } pub(crate) fn register_gen_const( &mut self, ident: &Identifier, obj: ValueObj, ) -> TyCheckResult<()> { if self.rec_get_const_obj(ident.inspect()).is_some() { Err(TyCheckError::reassign_error( line!() as usize, ident.loc(), self.caused_by(), ident.inspect(), )) } else { match obj { ValueObj::Type(t) => { let gen = enum_unwrap!(t, TypeObj::Generated); self.register_gen_type(ident, gen); } // TODO: not all value objects are comparable other => { let id = DefId(get_hash(ident)); let vi = VarInfo::new( enum_t(set! {other.clone()}), Const, ident.vis(), VarKind::Defined(id), None, ); self.consts.insert(ident.name.clone(), other); self.decls.insert(ident.name.clone(), vi); } } Ok(()) } } fn register_gen_type(&mut self, ident: &Identifier, gen: GenTypeObj) { match gen.kind { TypeKind::Class => { if gen.t.is_monomorphic() { // let super_traits = gen.impls.iter().map(|to| to.typ().clone()).collect(); let mut ctx = Self::mono_class(gen.t.name(), self.level); let mut methods = Self::methods(gen.t.name(), self.level); let require = gen.require_or_sup.typ().clone(); let new_t = func1(require, gen.t.clone()); methods.register_fixed_auto_impl("__new__", new_t.clone(), Immutable, Private); // 必要なら、ユーザーが独自に上書きする methods.register_auto_impl("new", new_t, Immutable, Public); ctx.methods_list .push((ClassDefType::Simple(gen.t.clone()), methods)); self.register_gen_mono_type(ident, gen, ctx, Const); } else { todo!() } } TypeKind::Subclass => { if gen.t.is_monomorphic() { let super_classes = vec![gen.require_or_sup.typ().clone()]; // let super_traits = gen.impls.iter().map(|to| to.typ().clone()).collect(); let mut ctx = Self::mono_class(gen.t.name(), self.level); for sup in super_classes.into_iter() { let (_, sup_ctx) = self.get_nominal_type_ctx(&sup).unwrap(); ctx.register_superclass(sup, sup_ctx); } let mut methods = Self::methods(gen.t.name(), self.level); if let Some(sup) = self.rec_get_const_obj(&gen.require_or_sup.typ().name()) { let sup = enum_unwrap!(sup, ValueObj::Type); let param_t = match sup { TypeObj::Builtin(t) => t, TypeObj::Generated(t) => t.require_or_sup.as_ref().typ(), }; // `Super.Requirement := {x = Int}` and `Self.Additional := {y = Int}` // => `Self.Requirement := {x = Int; y = Int}` let param_t = if let Some(additional) = &gen.additional { self.intersection(param_t, additional.typ()) } else { param_t.clone() }; let new_t = func1(param_t, gen.t.clone()); methods.register_fixed_auto_impl( "__new__", new_t.clone(), Immutable, Private, ); // 必要なら、ユーザーが独自に上書きする methods.register_auto_impl("new", new_t, Immutable, Public); ctx.methods_list .push((ClassDefType::Simple(gen.t.clone()), methods)); self.register_gen_mono_type(ident, gen, ctx, Const); } else { todo!("super class not found") } } else { todo!() } } other => todo!("{other:?}"), } } fn register_gen_mono_type( &mut self, ident: &Identifier, gen: GenTypeObj, ctx: Self, muty: Mutability, ) { // FIXME: not panic but error // FIXME: recursive search if self.mono_types.contains_key(&gen.t.name()) { panic!("{} has already been registered", gen.t.name()); } else if self.rec_get_const_obj(&gen.t.name()).is_some() { panic!("{} has already been registered as const", gen.t.name()); } else { let t = gen.t.clone(); let meta_t = gen.meta_type(); let name = &ident.name; let id = DefId(get_hash(&(&self.name, &name))); self.decls.insert( name.clone(), VarInfo::new(meta_t, muty, Private, VarKind::Defined(id), None), ); self.consts .insert(name.clone(), ValueObj::Type(TypeObj::Generated(gen))); for impl_trait in ctx.super_traits.iter() { if let Some(impls) = self.trait_impls.get_mut(&impl_trait.name()) { impls.push(TraitInstance::new(t.clone(), impl_trait.clone())); } else { self.trait_impls.insert( impl_trait.name(), vec![TraitInstance::new(t.clone(), impl_trait.clone())], ); } } self.mono_types.insert(name.clone(), (t, ctx)); } } pub(crate) fn import_mod( &mut self, var_name: &VarName, mod_name: &hir::Expr, ) -> TyCheckResult<()> { match mod_name { hir::Expr::Lit(lit) => { if self.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_candidates(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)); } }