diff --git a/compiler/erg_compiler/context/register.rs b/compiler/erg_compiler/context/register.rs index 001360df..3d87f67e 100644 --- a/compiler/erg_compiler/context/register.rs +++ b/compiler/erg_compiler/context/register.rs @@ -632,14 +632,23 @@ impl Context { }; if let Some(spec) = sig.return_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)?; + let spec_t = self + .instantiate_typespec( + spec, + None, + &mut dummy_tv_cache, + PreRegister, + false, + ) + .map_err(|err| { + self.pop(); + err + })?; + self.sub_unify(&const_t, &spec_t, def.body.loc(), None) + .map_err(|err| { + self.pop(); + err + })?; } self.pop(); self.register_gen_const(def.sig.ident().unwrap(), obj)?; @@ -659,14 +668,23 @@ impl Context { }; 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)?; + let spec_t = self + .instantiate_typespec( + spec, + None, + &mut dummy_tv_cache, + PreRegister, + false, + ) + .map_err(|err| { + self.pop(); + err + })?; + self.sub_unify(&const_t, &spec_t, def.body.loc(), None) + .map_err(|err| { + self.pop(); + err + })?; } self.pop(); if let Some(ident) = sig.ident() { diff --git a/compiler/erg_compiler/declare.rs b/compiler/erg_compiler/declare.rs new file mode 100644 index 00000000..c10f1b44 --- /dev/null +++ b/compiler/erg_compiler/declare.rs @@ -0,0 +1,301 @@ +use erg_common::traits::{Locational, Runnable, Stream}; +use erg_common::{enum_unwrap, fn_name, log, Str}; + +use erg_parser::ast; +use erg_parser::ast::AST; + +use crate::context::instantiate::TyVarCache; +use crate::lower::ASTLowerer; +use crate::ty::constructors::mono; +use crate::ty::free::HasLevel; +use crate::ty::value::{GenTypeObj, TypeObj}; +use crate::ty::{HasType, Type}; + +use crate::context::RegistrationMode; +use crate::error::{LowerError, LowerErrors, LowerResult}; +use crate::hir; +use crate::hir::HIR; +use crate::varinfo::{Mutability, VarInfo, VarKind}; + +impl ASTLowerer { + fn declare_var( + &mut self, + sig: ast::VarSignature, + mut body: ast::DefBody, + ) -> LowerResult { + log!(info "entered {}({sig})", fn_name!()); + if body.block.len() > 1 { + return Err(LowerErrors::from(LowerError::declare_error( + self.cfg().input.clone(), + line!() as usize, + body.block.loc(), + self.ctx.caused_by(), + ))); + } + let chunk = self.declare_chunk(body.block.remove(0))?; + let py_name = if let hir::Expr::TypeAsc(tasc) = &chunk { + enum_unwrap!(tasc.expr.as_ref(), hir::Expr::Accessor) + .local_name() + .map(Str::rc) + } else { + sig.inspect().cloned() + }; + let block = hir::Block::new(vec![chunk]); + let found_body_t = block.ref_t(); + let ident = match &sig.pat { + ast::VarPattern::Ident(ident) => ident, + _ => unreachable!(), + }; + let id = body.id; + self.ctx + .assign_var_sig(&sig, found_body_t, id, py_name.clone())?; + let mut ident = hir::Identifier::bare(ident.dot.clone(), ident.name.clone()); + ident.vi.t = found_body_t.clone(); + ident.vi.py_name = py_name; + let sig = hir::VarSignature::new(ident); + let body = hir::DefBody::new(body.op, block, body.id); + Ok(hir::Def::new(hir::Signature::Var(sig), body)) + } + + /// allowed: alias, import, const functions (e.g. Class) + fn declare_def(&mut self, def: ast::Def) -> LowerResult { + log!(info "entered {}({})", fn_name!(), def.sig); + let name = if let Some(name) = def.sig.name_as_str() { + name.clone() + } else { + Str::ever("") + }; + if self + .ctx + .registered_info(&name, def.sig.is_const()) + .is_some() + && def.sig.vis().is_private() + { + return Err(LowerErrors::from(LowerError::reassign_error( + self.cfg().input.clone(), + line!() as usize, + def.sig.loc(), + self.ctx.caused_by(), + &name, + ))); + } + #[allow(clippy::let_and_return)] + let res = match def.sig { + ast::Signature::Subr(sig) => { + return Err(LowerErrors::from(LowerError::declare_error( + self.cfg().input.clone(), + line!() as usize, + sig.loc(), + self.ctx.caused_by(), + ))); + } + ast::Signature::Var(sig) => self.declare_var(sig, def.body), + }; + // self.pop_append_errs(); + res + } + + fn declare_class_def(&mut self, _class_def: ast::ClassDef) -> LowerResult { + todo!() + } + + fn fake_lower_obj(&self, obj: ast::Expr) -> LowerResult { + match obj { + ast::Expr::Accessor(ast::Accessor::Ident(ident)) => { + let acc = hir::Accessor::Ident(hir::Identifier::bare(ident.dot, ident.name)); + Ok(hir::Expr::Accessor(acc)) + } + ast::Expr::Accessor(ast::Accessor::Attr(attr)) => { + let obj = self.fake_lower_obj(*attr.obj)?; + let ident = hir::Identifier::bare(attr.ident.dot, attr.ident.name); + Ok(obj.attr_expr(ident)) + } + other => Err(LowerErrors::from(LowerError::declare_error( + self.cfg().input.clone(), + line!() as usize, + other.loc(), + self.ctx.caused_by(), + ))), + } + } + + fn declare_ident(&mut self, tasc: ast::TypeAscription) -> LowerResult { + log!(info "entered {}({})", fn_name!(), tasc); + let is_instance_ascription = tasc.is_instance_ascription(); + let mut dummy_tv_cache = TyVarCache::new(self.ctx.level, &self.ctx); + match *tasc.expr { + ast::Expr::Accessor(ast::Accessor::Ident(mut ident)) => { + if self.cfg().python_compatible_mode { + ident.trim_end_proc_mark(); + } + let py_name = Str::rc(ident.inspect().trim_end_matches('!')); + let t = self.ctx.instantiate_typespec( + &tasc.t_spec, + None, + &mut dummy_tv_cache, + RegistrationMode::Normal, + false, + )?; + t.lift(); + let t = self.ctx.generalize_t(t); + if is_instance_ascription { + self.declare_instance(&ident, &t, py_name)?; + } else { + self.declare_subtype(&ident, &t)?; + } + let muty = Mutability::from(&ident.inspect()[..]); + let vis = ident.vis(); + let py_name = Str::rc(ident.inspect().trim_end_matches('!')); + let vi = VarInfo::new(t, muty, vis, VarKind::Declared, None, None, Some(py_name)); + let ident = hir::Identifier::new(ident.dot, ident.name, None, vi); + Ok(hir::Expr::Accessor(hir::Accessor::Ident(ident)).type_asc(tasc.t_spec)) + } + ast::Expr::Accessor(ast::Accessor::Attr(mut attr)) => { + if self.cfg().python_compatible_mode { + attr.ident.trim_end_proc_mark(); + } + let py_name = Str::rc(attr.ident.inspect().trim_end_matches('!')); + let t = self.ctx.instantiate_typespec( + &tasc.t_spec, + None, + &mut dummy_tv_cache, + RegistrationMode::Normal, + false, + )?; + let namespace = self.ctx.name.clone(); + let ctx = self + .ctx + .get_mut_singular_ctx(attr.obj.as_ref(), &namespace)?; + ctx.assign_var_sig( + &ast::VarSignature::new(ast::VarPattern::Ident(attr.ident.clone()), None), + &t, + ast::DefId(0), + Some(py_name), + )?; + let obj = self.fake_lower_obj(*attr.obj)?; + let muty = Mutability::from(&attr.ident.inspect()[..]); + let vis = attr.ident.vis(); + let py_name = Str::rc(attr.ident.inspect().trim_end_matches('!')); + let vi = VarInfo::new(t, muty, vis, VarKind::Declared, None, None, Some(py_name)); + let ident = hir::Identifier::new(attr.ident.dot, attr.ident.name, None, vi); + let attr = obj.attr_expr(ident); + Ok(attr.type_asc(tasc.t_spec)) + } + other => Err(LowerErrors::from(LowerError::declare_error( + self.cfg().input.clone(), + line!() as usize, + other.loc(), + self.ctx.caused_by(), + ))), + } + } + + fn declare_instance( + &mut self, + ident: &ast::Identifier, + t: &Type, + py_name: Str, + ) -> LowerResult<()> { + // .X = 'x': Type + if ident.is_raw() { + return Ok(()); + } + if ident.is_const() { + let vi = VarInfo::new( + t.clone(), + Mutability::Const, + ident.vis(), + VarKind::Declared, + None, + None, + Some(py_name.clone()), + ); + self.ctx.decls.insert(ident.name.clone(), vi); + } + self.ctx.assign_var_sig( + &ast::VarSignature::new(ast::VarPattern::Ident(ident.clone()), None), + t, + ast::DefId(0), + Some(py_name), + )?; + match t { + Type::ClassType => { + let ty_obj = GenTypeObj::class( + mono(format!("{}{ident}", self.ctx.path())), + TypeObj::Builtin(Type::Uninited), + None, + ); + self.ctx.register_gen_type(ident, ty_obj); + } + Type::TraitType => { + let ty_obj = GenTypeObj::trait_( + mono(format!("{}{ident}", self.ctx.path())), + TypeObj::Builtin(Type::Uninited), + None, + ); + self.ctx.register_gen_type(ident, ty_obj); + } + _ => {} + } + Ok(()) + } + + fn declare_subtype(&mut self, ident: &ast::Identifier, trait_: &Type) -> LowerResult<()> { + if ident.is_raw() { + return Ok(()); + } + if let Some((_, ctx)) = self.ctx.get_mut_type(ident.inspect()) { + ctx.register_marker_trait(trait_.clone()); + Ok(()) + } else { + Err(LowerErrors::from(LowerError::no_var_error( + self.cfg().input.clone(), + line!() as usize, + ident.loc(), + self.ctx.caused_by(), + ident.inspect(), + self.ctx.get_similar_name(ident.inspect()), + ))) + } + } + + fn declare_chunk(&mut self, expr: ast::Expr) -> LowerResult { + log!(info "entered {}", fn_name!()); + match expr { + ast::Expr::Def(def) => Ok(hir::Expr::Def(self.declare_def(def)?)), + ast::Expr::ClassDef(class_def) => { + Ok(hir::Expr::ClassDef(self.declare_class_def(class_def)?)) + } + ast::Expr::TypeAsc(tasc) => Ok(hir::Expr::TypeAsc(self.declare_ident(tasc)?)), + ast::Expr::Call(call) + if call + .additional_operation() + .map(|op| op.is_import()) + .unwrap_or(false) => + { + Ok(hir::Expr::Call(self.lower_call(call)?)) + } + other => Err(LowerErrors::from(LowerError::declare_error( + self.cfg().input.clone(), + line!() as usize, + other.loc(), + self.ctx.caused_by(), + ))), + } + } + + pub(crate) fn declare_module(&mut self, ast: AST) -> HIR { + let mut module = hir::Module::with_capacity(ast.module.len()); + for chunk in ast.module.into_iter() { + match self.declare_chunk(chunk) { + Ok(chunk) => { + module.push(chunk); + } + Err(errs) => { + self.errs.extend(errs); + } + } + } + HIR::new(ast.name, module) + } +} diff --git a/compiler/erg_compiler/lib.rs b/compiler/erg_compiler/lib.rs index 328fcd8f..60206dc7 100644 --- a/compiler/erg_compiler/lib.rs +++ b/compiler/erg_compiler/lib.rs @@ -9,6 +9,7 @@ mod compile; pub use compile::*; mod codegen; pub mod context; +pub mod declare; pub mod desugar_hir; pub mod effectcheck; pub mod error; diff --git a/compiler/erg_compiler/lower.rs b/compiler/erg_compiler/lower.rs index 4a4ad181..ece1404d 100644 --- a/compiler/erg_compiler/lower.rs +++ b/compiler/erg_compiler/lower.rs @@ -22,7 +22,7 @@ use crate::context::instantiate::TyVarCache; use crate::ty::constructors::{ array_mut, array_t, free_var, func, mono, poly, proc, set_mut, set_t, ty_tp, }; -use crate::ty::free::{Constraint, HasLevel}; +use crate::ty::free::Constraint; use crate::ty::typaram::TyParam; use crate::ty::value::{GenTypeObj, TypeObj, ValueObj}; use crate::ty::{HasType, ParamTy, Type}; @@ -38,7 +38,7 @@ use crate::hir; use crate::hir::HIR; use crate::mod_cache::SharedModuleCache; use crate::reorder::Reorderer; -use crate::varinfo::{Mutability, VarInfo, VarKind}; +use crate::varinfo::{VarInfo, VarKind}; use crate::AccessKind; use Visibility::*; @@ -47,8 +47,8 @@ use Visibility::*; pub struct ASTLowerer { cfg: ErgConfig, pub(crate) ctx: Context, - errs: LowerErrors, - warns: LowerWarnings, + pub(crate) errs: LowerErrors, + pub(crate) warns: LowerWarnings, } impl Default for ASTLowerer { @@ -772,7 +772,7 @@ impl ASTLowerer { Ok(hir::UnaryOp::new(unary.op, expr, t)) } - fn lower_call(&mut self, call: ast::Call) -> LowerResult { + pub(crate) fn lower_call(&mut self, call: ast::Call) -> LowerResult { log!(info "entered {}({}{}(...))", fn_name!(), call.obj, fmt_option!(call.attr_name)); let mut errs = LowerErrors::empty(); let opt_cast_to = if call.is_assert_cast() { @@ -1808,286 +1808,6 @@ impl ASTLowerer { Ok(hir::Dummy::new(hir_dummy)) } - fn declare_or_import_var( - &mut self, - sig: ast::VarSignature, - mut body: ast::DefBody, - ) -> LowerResult { - log!(info "entered {}({sig})", fn_name!()); - if body.block.len() > 1 { - return Err(LowerErrors::from(LowerError::declare_error( - self.cfg.input.clone(), - line!() as usize, - body.block.loc(), - self.ctx.caused_by(), - ))); - } - let chunk = self.declare_chunk(body.block.remove(0))?; - let py_name = if let hir::Expr::TypeAsc(tasc) = &chunk { - enum_unwrap!(tasc.expr.as_ref(), hir::Expr::Accessor) - .local_name() - .map(Str::rc) - } else { - sig.inspect().cloned() - }; - let block = hir::Block::new(vec![chunk]); - let found_body_t = block.ref_t(); - let ident = match &sig.pat { - ast::VarPattern::Ident(ident) => ident, - _ => unreachable!(), - }; - let id = body.id; - self.ctx - .assign_var_sig(&sig, found_body_t, id, py_name.clone())?; - let mut ident = hir::Identifier::bare(ident.dot.clone(), ident.name.clone()); - ident.vi.t = found_body_t.clone(); - ident.vi.py_name = py_name; - let sig = hir::VarSignature::new(ident); - let body = hir::DefBody::new(body.op, block, body.id); - Ok(hir::Def::new(hir::Signature::Var(sig), body)) - } - - fn declare_alias_or_import(&mut self, def: ast::Def) -> LowerResult { - log!(info "entered {}({})", fn_name!(), def.sig); - let name = if let Some(name) = def.sig.name_as_str() { - name.clone() - } else { - Str::ever("") - }; - if self - .ctx - .registered_info(&name, def.sig.is_const()) - .is_some() - && def.sig.vis().is_private() - { - return Err(LowerErrors::from(LowerError::reassign_error( - self.cfg.input.clone(), - line!() as usize, - def.sig.loc(), - self.ctx.caused_by(), - &name, - ))); - } - #[allow(clippy::let_and_return)] - let res = match def.sig { - ast::Signature::Subr(sig) => { - return Err(LowerErrors::from(LowerError::declare_error( - self.cfg.input.clone(), - line!() as usize, - sig.loc(), - self.ctx.caused_by(), - ))); - } - ast::Signature::Var(sig) => self.declare_or_import_var(sig, def.body), - }; - // self.pop_append_errs(); - res - } - - fn declare_class_def(&mut self, _class_def: ast::ClassDef) -> LowerResult { - todo!() - } - - fn fake_lower_obj(&self, obj: ast::Expr) -> LowerResult { - match obj { - ast::Expr::Accessor(ast::Accessor::Ident(ident)) => { - let acc = hir::Accessor::Ident(hir::Identifier::bare(ident.dot, ident.name)); - Ok(hir::Expr::Accessor(acc)) - } - ast::Expr::Accessor(ast::Accessor::Attr(attr)) => { - let obj = self.fake_lower_obj(*attr.obj)?; - let ident = hir::Identifier::bare(attr.ident.dot, attr.ident.name); - Ok(obj.attr_expr(ident)) - } - other => Err(LowerErrors::from(LowerError::declare_error( - self.cfg.input.clone(), - line!() as usize, - other.loc(), - self.ctx.caused_by(), - ))), - } - } - - fn declare_ident(&mut self, tasc: ast::TypeAscription) -> LowerResult { - log!(info "entered {}({})", fn_name!(), tasc); - let is_instance_ascription = tasc.is_instance_ascription(); - let mut dummy_tv_cache = TyVarCache::new(self.ctx.level, &self.ctx); - match *tasc.expr { - ast::Expr::Accessor(ast::Accessor::Ident(mut ident)) => { - if self.cfg.python_compatible_mode { - ident.trim_end_proc_mark(); - } - let py_name = Str::rc(ident.inspect().trim_end_matches('!')); - let t = self.ctx.instantiate_typespec( - &tasc.t_spec, - None, - &mut dummy_tv_cache, - RegistrationMode::Normal, - false, - )?; - t.lift(); - let t = self.ctx.generalize_t(t); - if is_instance_ascription { - self.declare_instance(&ident, &t, py_name)?; - } else { - self.declare_subtype(&ident, &t)?; - } - let muty = Mutability::from(&ident.inspect()[..]); - let vis = ident.vis(); - let py_name = Str::rc(ident.inspect().trim_end_matches('!')); - let vi = VarInfo::new(t, muty, vis, VarKind::Declared, None, None, Some(py_name)); - let ident = hir::Identifier::new(ident.dot, ident.name, None, vi); - Ok(hir::Expr::Accessor(hir::Accessor::Ident(ident)).type_asc(tasc.t_spec)) - } - ast::Expr::Accessor(ast::Accessor::Attr(mut attr)) => { - if self.cfg.python_compatible_mode { - attr.ident.trim_end_proc_mark(); - } - let py_name = Str::rc(attr.ident.inspect().trim_end_matches('!')); - let t = self.ctx.instantiate_typespec( - &tasc.t_spec, - None, - &mut dummy_tv_cache, - RegistrationMode::Normal, - false, - )?; - let namespace = self.ctx.name.clone(); - let ctx = self - .ctx - .get_mut_singular_ctx(attr.obj.as_ref(), &namespace)?; - ctx.assign_var_sig( - &ast::VarSignature::new(ast::VarPattern::Ident(attr.ident.clone()), None), - &t, - ast::DefId(0), - Some(py_name), - )?; - let obj = self.fake_lower_obj(*attr.obj)?; - let muty = Mutability::from(&attr.ident.inspect()[..]); - let vis = attr.ident.vis(); - let py_name = Str::rc(attr.ident.inspect().trim_end_matches('!')); - let vi = VarInfo::new(t, muty, vis, VarKind::Declared, None, None, Some(py_name)); - let ident = hir::Identifier::new(attr.ident.dot, attr.ident.name, None, vi); - let attr = obj.attr_expr(ident); - Ok(attr.type_asc(tasc.t_spec)) - } - other => Err(LowerErrors::from(LowerError::declare_error( - self.cfg.input.clone(), - line!() as usize, - other.loc(), - self.ctx.caused_by(), - ))), - } - } - - fn declare_instance( - &mut self, - ident: &ast::Identifier, - t: &Type, - py_name: Str, - ) -> LowerResult<()> { - // .X = 'x': Type - if ident.is_raw() { - return Ok(()); - } - if ident.is_const() { - let vi = VarInfo::new( - t.clone(), - Mutability::Const, - ident.vis(), - VarKind::Declared, - None, - None, - Some(py_name.clone()), - ); - self.ctx.decls.insert(ident.name.clone(), vi); - } - self.ctx.assign_var_sig( - &ast::VarSignature::new(ast::VarPattern::Ident(ident.clone()), None), - t, - ast::DefId(0), - Some(py_name), - )?; - match t { - Type::ClassType => { - let ty_obj = GenTypeObj::class( - mono(format!("{}{ident}", self.ctx.path())), - TypeObj::Builtin(Type::Uninited), - None, - ); - self.ctx.register_gen_type(ident, ty_obj); - } - Type::TraitType => { - let ty_obj = GenTypeObj::trait_( - mono(format!("{}{ident}", self.ctx.path())), - TypeObj::Builtin(Type::Uninited), - None, - ); - self.ctx.register_gen_type(ident, ty_obj); - } - _ => {} - } - Ok(()) - } - - fn declare_subtype(&mut self, ident: &ast::Identifier, trait_: &Type) -> LowerResult<()> { - if ident.is_raw() { - return Ok(()); - } - if let Some((_, ctx)) = self.ctx.get_mut_type(ident.inspect()) { - ctx.register_marker_trait(trait_.clone()); - Ok(()) - } else { - Err(LowerErrors::from(LowerError::no_var_error( - self.cfg.input.clone(), - line!() as usize, - ident.loc(), - self.ctx.caused_by(), - ident.inspect(), - self.ctx.get_similar_name(ident.inspect()), - ))) - } - } - - fn declare_chunk(&mut self, expr: ast::Expr) -> LowerResult { - log!(info "entered {}", fn_name!()); - match expr { - ast::Expr::Def(def) => Ok(hir::Expr::Def(self.declare_alias_or_import(def)?)), - ast::Expr::ClassDef(class_def) => { - Ok(hir::Expr::ClassDef(self.declare_class_def(class_def)?)) - } - ast::Expr::TypeAsc(tasc) => Ok(hir::Expr::TypeAsc(self.declare_ident(tasc)?)), - ast::Expr::Call(call) - if call - .additional_operation() - .map(|op| op.is_import()) - .unwrap_or(false) => - { - Ok(hir::Expr::Call(self.lower_call(call)?)) - } - other => Err(LowerErrors::from(LowerError::declare_error( - self.cfg.input.clone(), - line!() as usize, - other.loc(), - self.ctx.caused_by(), - ))), - } - } - - fn declare_module(&mut self, ast: AST) -> HIR { - let mut module = hir::Module::with_capacity(ast.module.len()); - for chunk in ast.module.into_iter() { - match self.declare_chunk(chunk) { - Ok(chunk) => { - module.push(chunk); - } - Err(errs) => { - self.errs.extend(errs); - } - } - } - HIR::new(ast.name, module) - } - fn return_incomplete_artifact(&mut self, hir: HIR) -> IncompleteArtifact { self.ctx.clear_all_vars(); IncompleteArtifact::new( diff --git a/compiler/erg_parser/ast.rs b/compiler/erg_parser/ast.rs index e3e1f228..d772416f 100644 --- a/compiler/erg_parser/ast.rs +++ b/compiler/erg_parser/ast.rs @@ -25,6 +25,10 @@ pub enum OperationKind { PyImport, Del, AssertCast, + Class, + Inherit, + Trait, + Subsume, } impl OperationKind { @@ -1106,6 +1110,10 @@ impl Call { "import" => Some(OperationKind::Import), "pyimport" | "py" | "__import__" => Some(OperationKind::PyImport), "Del" => Some(OperationKind::Del), + "Class" => Some(OperationKind::Class), + "Inherit" => Some(OperationKind::Inherit), + "Trait" => Some(OperationKind::Trait), + "Subsume" => Some(OperationKind::Subsume), _ => None, }) }