From e860da2a15a3f1b0a4b074a0057cf9aaa08a835a Mon Sep 17 00:00:00 2001 From: Shunsuke Shibayama Date: Mon, 5 Sep 2022 01:13:14 +0900 Subject: [PATCH] WIP: impl type checker --- compiler/erg_compiler/context/compare.rs | 17 ++- .../erg_compiler/context/initialize/mod.rs | 55 ++++++++- compiler/erg_compiler/context/inquire.rs | 34 +++++ compiler/erg_compiler/context/mod.rs | 10 ++ compiler/erg_compiler/context/register.rs | 116 ++++++++++++++++-- compiler/erg_compiler/context/tyvar.rs | 17 +++ compiler/erg_parser/ast.rs | 18 ++- compiler/erg_type/free.rs | 29 ++++- compiler/erg_type/value.rs | 4 + 9 files changed, 274 insertions(+), 26 deletions(-) diff --git a/compiler/erg_compiler/context/compare.rs b/compiler/erg_compiler/context/compare.rs index 8f3b85ac..9546777b 100644 --- a/compiler/erg_compiler/context/compare.rs +++ b/compiler/erg_compiler/context/compare.rs @@ -399,8 +399,6 @@ impl Context { && kw_check() // contravariant } - // RefMut, OptionMut are invariant - (Ref(lhs), Ref(rhs)) => self.supertype_of(lhs, rhs), // ?T(<: Nat) !:> ?U(:> Int) // ?T(<: Nat) :> ?U(<: Int) (?U can be smaller than ?T) (FreeVar(lfv), FreeVar(rfv)) => { @@ -490,7 +488,18 @@ impl Context { } true } - // (MonoQuantVar(_), _) | (_, MonoQuantVar(_)) => true, + (Type::Record(lhs), Type::Record(rhs)) => { + for (k, l) in lhs.iter() { + if let Some(r) = rhs.get(k) { + if !self.supertype_of(l, r) { + return false; + } + } else { + return false; + } + } + true + } // REVIEW: maybe this is incomplete // ({I: Int | I >= 0} :> {N: Int | N >= 0}) == true, // ({I: Int | I >= 0} :> {I: Int | I >= 1}) == true, @@ -565,6 +574,8 @@ impl Context { } (_lhs, Not(_, _)) => todo!(), (Not(_, _), _rhs) => todo!(), + // RefMut, OptionMut are invariant + (Ref(lhs), Ref(rhs)) => self.supertype_of(lhs, rhs), // TはすべてのRef(T)のメソッドを持つので、Ref(T)のサブタイプ // REVIEW: RefMut is invariant, maybe (Ref(lhs), rhs) | (RefMut(lhs), rhs) => self.supertype_of(lhs, rhs), diff --git a/compiler/erg_compiler/context/initialize/mod.rs b/compiler/erg_compiler/context/initialize/mod.rs index 6d0921d3..69f794a7 100644 --- a/compiler/erg_compiler/context/initialize/mod.rs +++ b/compiler/erg_compiler/context/initialize/mod.rs @@ -9,7 +9,7 @@ use erg_common::vis::Visibility; use erg_common::Str; use erg_type::typaram::TyParam; -use erg_type::value::ValueObj; +use erg_type::value::{TypeKind, TypeObj, ValueObj}; use erg_type::Type; use erg_type::{constructors::*, BuiltinConstSubr, ConstSubr}; use ParamSpec as PS; @@ -51,11 +51,54 @@ impl Context { if self.rec_get_const_obj(name).is_some() { panic!("already registered: {name}"); } else { - // TODO: visibility (not always private) - // TODO: kind (not always Builtin) - let vi = VarInfo::new(enum_t(set! {obj.clone()}), Const, Private, Builtin); - self.consts.insert(VarName::from_str(Str::rc(name)), obj); - self.locals.insert(VarName::from_str(Str::rc(name)), vi); + match obj { + /*ValueObj::Type(TypeObj::Builtin(_builtin)) => { + todo!() + }*/ + ValueObj::Type(TypeObj::Gen(gen)) => match gen.kind { + TypeKind::Class => { + if gen.t.is_monomorphic() { + let super_traits = + gen.impls.into_iter().map(|to| to.typ().clone()).collect(); + let mut ctx = + Self::mono_class(gen.t.name(), vec![], super_traits, self.level); + let require = gen.require_or_sup.typ().clone(); + let new_t = func1(require, gen.t.clone()); + ctx.register_impl("__new__", new_t, Immutable, Private); + self.register_mono_type(gen.t, ctx, Const); + } else { + todo!() + } + } + TypeKind::InheritedClass => { + if gen.t.is_monomorphic() { + let super_classes = vec![gen.require_or_sup.typ().clone()]; + let super_traits = + gen.impls.into_iter().map(|to| to.typ().clone()).collect(); + let mut ctx = Self::mono_class( + gen.t.name(), + super_classes, + super_traits, + self.level, + ); + let sup = gen.require_or_sup.typ().clone(); + let new_t = func1(sup, gen.t.clone()); + ctx.register_impl("__new__", new_t, Immutable, Private); + self.register_mono_type(gen.t, ctx, Const); + } else { + todo!() + } + } + other => todo!("{other:?}"), + }, + other => { + // TODO: visibility (not always private) + // TODO: kind (not always Builtin) + let vi = VarInfo::new(enum_t(set! {other.clone()}), Const, Private, Builtin); + self.consts.insert(VarName::from_str(Str::rc(name)), other); + self.locals.insert(VarName::from_str(Str::rc(name)), vi); + } + } } } diff --git a/compiler/erg_compiler/context/inquire.rs b/compiler/erg_compiler/context/inquire.rs index 605a839a..9d8bcf0b 100644 --- a/compiler/erg_compiler/context/inquire.rs +++ b/compiler/erg_compiler/context/inquire.rs @@ -1020,6 +1020,13 @@ impl Context { typ: &Type, ) -> Option<(&'a Type, &'a Context)> { match typ { + Type::FreeVar(fv) if fv.is_linked() => { + return self.rec_get_nominal_type_ctx(&fv.crack()); + } + Type::FreeVar(fv) => { + let sup = fv.crack_sup()?; + return self.rec_get_nominal_type_ctx(&sup); + } Type::Refinement(refine) => { return self.rec_get_nominal_type_ctx(&refine.t); } @@ -1040,6 +1047,7 @@ impl Context { return Some((t, ctx)); } } + Type::Ref(t) | Type::RefMut(t) => return self.rec_get_nominal_type_ctx(t), other => todo!("{other}"), } if let Some(outer) = &self.outer { @@ -1053,8 +1061,14 @@ impl Context { match obj.ref_t() { // TODO: attr Type::Module => self.rec_get_mod(&obj.var_full_name()?), + Type::Type => self + .rec_get_nominal_type_ctx(&Type::Mono(Str::from(obj.var_full_name().unwrap()))) + .map(|(_, ctx)| ctx), Type::Class => todo!(), Type::Trait => todo!(), + Type::Refinement(refine) => { + self.rec_get_nominal_type_ctx(&refine.t).map(|(_, ctx)| ctx) + } _ => None, } } @@ -1113,4 +1127,24 @@ impl Context { None } } + + pub(crate) fn get_self_t(&self) -> Type { + if self.kind.is_method_def() || self.kind.is_type() { + // TODO: poly type + let name = self.name.split("::").last().unwrap(); + let name = name.split(".").last().unwrap(); + let mono_t = mono(Str::rc(name)); + if let Some((t, _)) = self.rec_get_nominal_type_ctx(&mono_t) { + t.clone() + } else { + todo!("{mono_t}") + } + } else { + if let Some(outer) = &self.outer { + outer.get_self_t() + } else { + todo!() + } + } + } } diff --git a/compiler/erg_compiler/context/mod.rs b/compiler/erg_compiler/context/mod.rs index c417312e..aa42b301 100644 --- a/compiler/erg_compiler/context/mod.rs +++ b/compiler/erg_compiler/context/mod.rs @@ -203,6 +203,16 @@ pub enum ContextKind { Dummy, } +impl ContextKind { + pub const fn is_method_def(&self) -> bool { + matches!(self, Self::MethodDefs) + } + + pub const fn is_type(&self) -> bool { + matches!(self, Self::Class | Self::Trait | Self::StructuralTrait) + } +} + /// 記号表に登録されているモードを表す /// Preregister: サブルーチンまたは定数式、前方参照できる /// Normal: 前方参照できない diff --git a/compiler/erg_compiler/context/register.rs b/compiler/erg_compiler/context/register.rs index 03e969c7..881d2179 100644 --- a/compiler/erg_compiler/context/register.rs +++ b/compiler/erg_compiler/context/register.rs @@ -9,7 +9,7 @@ use erg_type::free::HasLevel; use ast::{DefId, VarName}; use erg_parser::ast; -use erg_type::constructors::{enum_t, func, proc}; +use erg_type::constructors::{enum_t, func, proc, ref_, ref_mut}; use erg_type::value::ValueObj; use erg_type::{HasType, ParamTy, SubrType, TyBound, Type}; use Type::*; @@ -161,18 +161,29 @@ impl Context { opt_decl_t: Option<&ParamTy>, ) -> TyCheckResult<()> { match &sig.pat { + ast::ParamPattern::Lit(_) => Ok(()), ast::ParamPattern::Discard(_token) => Ok(()), - ast::ParamPattern::VarName(v) => { - if self.registered(v.inspect(), v.inspect().is_uppercase()) { + ast::ParamPattern::VarName(name) => { + if self.registered(name.inspect(), name.is_const()) { Err(TyCheckError::reassign_error( line!() as usize, - v.loc(), + name.loc(), self.caused_by(), - v.inspect(), + 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.get_self_t(); + 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 { @@ -183,16 +194,101 @@ impl Context { } else { DefaultInfo::NonDefault }; - let kind = VarKind::parameter(DefId(get_hash(&(&self.name, v))), idx, default); + let kind = + VarKind::parameter(DefId(get_hash(&(&self.name, name))), idx, default); self.params.push(( - Some(v.clone()), + Some(name.clone()), VarInfo::new(spec_t, Immutable, Private, kind), )); Ok(()) } } - ast::ParamPattern::Lit(_) => Ok(()), - _ => unreachable!(), + ast::ParamPattern::Ref(name) => { + if self.registered(name.inspect(), name.is_const()) { + 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.get_self_t(); + 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), + )); + Ok(()) + } + } + ast::ParamPattern::RefMut(name) => { + if self.registered(name.inspect(), name.is_const()) { + 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.get_self_t(); + self.sub_unify( + &spec_t, + &self_t, + Some(name.loc()), + None, + Some(name.inspect()), + )?; + } + let spec_t = ref_mut(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), + )); + Ok(()) + } + } + other => { + log!(err "{other}"); + unreachable!() + } } } @@ -272,7 +368,7 @@ impl Context { ) })?; } - if self.registered(name.inspect(), name.inspect().is_uppercase()) { + if self.registered(name.inspect(), name.is_const()) { Err(TyCheckError::reassign_error( line!() as usize, name.loc(), diff --git a/compiler/erg_compiler/context/tyvar.rs b/compiler/erg_compiler/context/tyvar.rs index 9cea5f59..1c12f78a 100644 --- a/compiler/erg_compiler/context/tyvar.rs +++ b/compiler/erg_compiler/context/tyvar.rs @@ -1111,6 +1111,23 @@ impl Context { return Ok(()); } (Type::FreeVar(_fv), _r) => todo!(), + (Type::Record(lrec), Type::Record(rrec)) => { + for (k, l) in lrec.iter() { + if let Some(r) = rrec.get(k) { + self.sub_unify(l, r, sub_loc, sup_loc, param_name)?; + } else { + return Err(TyCheckError::subtyping_error( + line!() as usize, + maybe_sub, + maybe_sup, + sub_loc, + sup_loc, + self.caused_by(), + )); + } + } + return Ok(()); + } (Type::Subr(lsub), Type::Subr(rsub)) => { for lpt in lsub.default_params.iter() { if let Some(rpt) = rsub.default_params.iter().find(|rpt| rpt.name() == lpt.name()) { diff --git a/compiler/erg_parser/ast.rs b/compiler/erg_parser/ast.rs index 06104050..d4a9a4bd 100644 --- a/compiler/erg_parser/ast.rs +++ b/compiler/erg_parser/ast.rs @@ -2291,7 +2291,23 @@ pub enum ParamPattern { VarArgs(VarName), } -impl_display_for_enum!(ParamPattern; Discard, VarName, Lit, Array, Tuple, Record, Ref, RefMut, VarArgs); +impl NestedDisplay for ParamPattern { + fn fmt_nest(&self, f: &mut fmt::Formatter<'_>, _level: usize) -> fmt::Result { + match self { + Self::Discard(tok) => write!(f, "{}", tok), + Self::VarName(var_name) => write!(f, "{}", var_name), + Self::Lit(lit) => write!(f, "{}", lit), + Self::Array(array) => write!(f, "{}", array), + Self::Tuple(tuple) => write!(f, "{}", tuple), + Self::Record(record) => write!(f, "{}", record), + Self::Ref(var_name) => write!(f, "ref {}", var_name), + Self::RefMut(var_name) => write!(f, "ref! {}", var_name), + Self::VarArgs(var_name) => write!(f, "...{}", var_name), + } + } +} + +impl_display_from_nested!(ParamPattern); impl_locational_for_enum!(ParamPattern; Discard, VarName, Lit, Array, Tuple, Record, Ref, RefMut, VarArgs); impl ParamPattern { diff --git a/compiler/erg_type/free.rs b/compiler/erg_type/free.rs index 267f376f..be3a1bd9 100644 --- a/compiler/erg_type/free.rs +++ b/compiler/erg_type/free.rs @@ -111,19 +111,28 @@ impl LimitedDisplay for Constraint { (true, false) => { write!(f, "<: ")?; sup.limited_fmt(f, limit - 1)?; - write!(f, "(cyclicity: {cyclicity:?})") + if cfg!(feature = "debug") { + write!(f, "(cyclicity: {cyclicity:?})")?; + } + Ok(()) } (false, true) => { write!(f, ":> ")?; sub.limited_fmt(f, limit - 1)?; - write!(f, "(cyclicity: {cyclicity:?})") + if cfg!(feature = "debug") { + write!(f, "(cyclicity: {cyclicity:?})")?; + } + Ok(()) } (false, false) => { write!(f, ":> ")?; sub.limited_fmt(f, limit - 1)?; write!(f, ", <: ")?; sup.limited_fmt(f, limit - 1)?; - write!(f, "(cyclicity: {cyclicity:?})") + if cfg!(feature = "debug") { + write!(f, "(cyclicity: {cyclicity:?})")?; + } + Ok(()) } }, Self::TypeOf(t) => { @@ -258,7 +267,11 @@ impl LimitedDisplay for FreeKind { } => { write!(f, "?{name}(")?; constraint.limited_fmt(f, limit - 1)?; - write!(f, ")[{lev}]") + write!(f, ")")?; + if cfg!(feature = "debug") { + write!(f, "[{lev}]")?; + } + Ok(()) } Self::Unbound { id, @@ -267,7 +280,11 @@ impl LimitedDisplay for FreeKind { } => { write!(f, "?{id}(")?; constraint.limited_fmt(f, limit - 1)?; - write!(f, ")[{lev}]") + write!(f, ")")?; + if cfg!(feature = "debug") { + write!(f, "[{lev}]")?; + } + Ok(()) } } } @@ -501,7 +518,7 @@ impl Free { .and_then(|c| c.get_type().cloned()) } - pub fn crack_subtype(&self) -> Option { + pub fn crack_sup(&self) -> Option { self.borrow() .constraint() .and_then(|c| c.get_super_type().cloned()) diff --git a/compiler/erg_type/value.rs b/compiler/erg_type/value.rs index ac0b037b..9bfd0686 100644 --- a/compiler/erg_type/value.rs +++ b/compiler/erg_type/value.rs @@ -357,6 +357,10 @@ impl ValueObj { } } + pub const fn is_type(&self) -> bool { + matches!(self, Self::Type(_)) + } + pub const fn is_mut(&self) -> bool { matches!(self, Self::Mut(_)) }