mirror of
https://github.com/erg-lang/erg.git
synced 2025-09-29 12:24:45 +00:00
WIP: impl type checker
This commit is contained in:
parent
cf0858ddde
commit
e860da2a15
9 changed files with 274 additions and 26 deletions
|
@ -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),
|
||||
|
|
|
@ -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,13 +51,56 @@ impl Context {
|
|||
if self.rec_get_const_obj(name).is_some() {
|
||||
panic!("already registered: {name}");
|
||||
} else {
|
||||
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! {obj.clone()}), Const, Private, Builtin);
|
||||
self.consts.insert(VarName::from_str(Str::rc(name)), obj);
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn register_const_param_defaults(&mut self, name: &'static str, params: Vec<ConstTemplate>) {
|
||||
if self.const_param_defaults.get(name).is_some() {
|
||||
|
|
|
@ -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!()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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: 前方参照できない
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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()) {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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<T: LimitedDisplay> LimitedDisplay for FreeKind<T> {
|
|||
} => {
|
||||
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<T: LimitedDisplay> LimitedDisplay for FreeKind<T> {
|
|||
} => {
|
||||
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<T: Clone + HasLevel> Free<T> {
|
|||
.and_then(|c| c.get_type().cloned())
|
||||
}
|
||||
|
||||
pub fn crack_subtype(&self) -> Option<Type> {
|
||||
pub fn crack_sup(&self) -> Option<Type> {
|
||||
self.borrow()
|
||||
.constraint()
|
||||
.and_then(|c| c.get_super_type().cloned())
|
||||
|
|
|
@ -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(_))
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue