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()
|
&& kw_check()
|
||||||
// contravariant
|
// contravariant
|
||||||
}
|
}
|
||||||
// RefMut, OptionMut are invariant
|
|
||||||
(Ref(lhs), Ref(rhs)) => self.supertype_of(lhs, rhs),
|
|
||||||
// ?T(<: Nat) !:> ?U(:> Int)
|
// ?T(<: Nat) !:> ?U(:> Int)
|
||||||
// ?T(<: Nat) :> ?U(<: Int) (?U can be smaller than ?T)
|
// ?T(<: Nat) :> ?U(<: Int) (?U can be smaller than ?T)
|
||||||
(FreeVar(lfv), FreeVar(rfv)) => {
|
(FreeVar(lfv), FreeVar(rfv)) => {
|
||||||
|
@ -490,7 +488,18 @@ impl Context {
|
||||||
}
|
}
|
||||||
true
|
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
|
// REVIEW: maybe this is incomplete
|
||||||
// ({I: Int | I >= 0} :> {N: Int | N >= 0}) == true,
|
// ({I: Int | I >= 0} :> {N: Int | N >= 0}) == true,
|
||||||
// ({I: Int | I >= 0} :> {I: Int | I >= 1}) == true,
|
// ({I: Int | I >= 0} :> {I: Int | I >= 1}) == true,
|
||||||
|
@ -565,6 +574,8 @@ impl Context {
|
||||||
}
|
}
|
||||||
(_lhs, Not(_, _)) => todo!(),
|
(_lhs, Not(_, _)) => todo!(),
|
||||||
(Not(_, _), _rhs) => todo!(),
|
(Not(_, _), _rhs) => todo!(),
|
||||||
|
// RefMut, OptionMut are invariant
|
||||||
|
(Ref(lhs), Ref(rhs)) => self.supertype_of(lhs, rhs),
|
||||||
// TはすべてのRef(T)のメソッドを持つので、Ref(T)のサブタイプ
|
// TはすべてのRef(T)のメソッドを持つので、Ref(T)のサブタイプ
|
||||||
// REVIEW: RefMut is invariant, maybe
|
// REVIEW: RefMut is invariant, maybe
|
||||||
(Ref(lhs), rhs) | (RefMut(lhs), rhs) => self.supertype_of(lhs, rhs),
|
(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_common::Str;
|
||||||
|
|
||||||
use erg_type::typaram::TyParam;
|
use erg_type::typaram::TyParam;
|
||||||
use erg_type::value::ValueObj;
|
use erg_type::value::{TypeKind, TypeObj, ValueObj};
|
||||||
use erg_type::Type;
|
use erg_type::Type;
|
||||||
use erg_type::{constructors::*, BuiltinConstSubr, ConstSubr};
|
use erg_type::{constructors::*, BuiltinConstSubr, ConstSubr};
|
||||||
use ParamSpec as PS;
|
use ParamSpec as PS;
|
||||||
|
@ -51,11 +51,54 @@ impl Context {
|
||||||
if self.rec_get_const_obj(name).is_some() {
|
if self.rec_get_const_obj(name).is_some() {
|
||||||
panic!("already registered: {name}");
|
panic!("already registered: {name}");
|
||||||
} else {
|
} else {
|
||||||
// TODO: visibility (not always private)
|
match obj {
|
||||||
// TODO: kind (not always Builtin)
|
/*ValueObj::Type(TypeObj::Builtin(_builtin)) => {
|
||||||
let vi = VarInfo::new(enum_t(set! {obj.clone()}), Const, Private, Builtin);
|
todo!()
|
||||||
self.consts.insert(VarName::from_str(Str::rc(name)), obj);
|
}*/
|
||||||
self.locals.insert(VarName::from_str(Str::rc(name)), vi);
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1020,6 +1020,13 @@ impl Context {
|
||||||
typ: &Type,
|
typ: &Type,
|
||||||
) -> Option<(&'a Type, &'a Context)> {
|
) -> Option<(&'a Type, &'a Context)> {
|
||||||
match typ {
|
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) => {
|
Type::Refinement(refine) => {
|
||||||
return self.rec_get_nominal_type_ctx(&refine.t);
|
return self.rec_get_nominal_type_ctx(&refine.t);
|
||||||
}
|
}
|
||||||
|
@ -1040,6 +1047,7 @@ impl Context {
|
||||||
return Some((t, ctx));
|
return Some((t, ctx));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Type::Ref(t) | Type::RefMut(t) => return self.rec_get_nominal_type_ctx(t),
|
||||||
other => todo!("{other}"),
|
other => todo!("{other}"),
|
||||||
}
|
}
|
||||||
if let Some(outer) = &self.outer {
|
if let Some(outer) = &self.outer {
|
||||||
|
@ -1053,8 +1061,14 @@ impl Context {
|
||||||
match obj.ref_t() {
|
match obj.ref_t() {
|
||||||
// TODO: attr
|
// TODO: attr
|
||||||
Type::Module => self.rec_get_mod(&obj.var_full_name()?),
|
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::Class => todo!(),
|
||||||
Type::Trait => todo!(),
|
Type::Trait => todo!(),
|
||||||
|
Type::Refinement(refine) => {
|
||||||
|
self.rec_get_nominal_type_ctx(&refine.t).map(|(_, ctx)| ctx)
|
||||||
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1113,4 +1127,24 @@ impl Context {
|
||||||
None
|
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,
|
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: サブルーチンまたは定数式、前方参照できる
|
/// Preregister: サブルーチンまたは定数式、前方参照できる
|
||||||
/// Normal: 前方参照できない
|
/// Normal: 前方参照できない
|
||||||
|
|
|
@ -9,7 +9,7 @@ use erg_type::free::HasLevel;
|
||||||
use ast::{DefId, VarName};
|
use ast::{DefId, VarName};
|
||||||
use erg_parser::ast;
|
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::value::ValueObj;
|
||||||
use erg_type::{HasType, ParamTy, SubrType, TyBound, Type};
|
use erg_type::{HasType, ParamTy, SubrType, TyBound, Type};
|
||||||
use Type::*;
|
use Type::*;
|
||||||
|
@ -161,18 +161,29 @@ impl Context {
|
||||||
opt_decl_t: Option<&ParamTy>,
|
opt_decl_t: Option<&ParamTy>,
|
||||||
) -> TyCheckResult<()> {
|
) -> TyCheckResult<()> {
|
||||||
match &sig.pat {
|
match &sig.pat {
|
||||||
|
ast::ParamPattern::Lit(_) => Ok(()),
|
||||||
ast::ParamPattern::Discard(_token) => Ok(()),
|
ast::ParamPattern::Discard(_token) => Ok(()),
|
||||||
ast::ParamPattern::VarName(v) => {
|
ast::ParamPattern::VarName(name) => {
|
||||||
if self.registered(v.inspect(), v.inspect().is_uppercase()) {
|
if self.registered(name.inspect(), name.is_const()) {
|
||||||
Err(TyCheckError::reassign_error(
|
Err(TyCheckError::reassign_error(
|
||||||
line!() as usize,
|
line!() as usize,
|
||||||
v.loc(),
|
name.loc(),
|
||||||
self.caused_by(),
|
self.caused_by(),
|
||||||
v.inspect(),
|
name.inspect(),
|
||||||
))
|
))
|
||||||
} else {
|
} else {
|
||||||
// ok, not defined
|
// ok, not defined
|
||||||
let spec_t = self.instantiate_param_sig_t(sig, opt_decl_t, Normal)?;
|
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 {
|
let idx = if let Some(outer) = outer {
|
||||||
ParamIdx::nested(outer, nth)
|
ParamIdx::nested(outer, nth)
|
||||||
} else {
|
} else {
|
||||||
|
@ -183,16 +194,101 @@ impl Context {
|
||||||
} else {
|
} else {
|
||||||
DefaultInfo::NonDefault
|
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((
|
self.params.push((
|
||||||
Some(v.clone()),
|
Some(name.clone()),
|
||||||
VarInfo::new(spec_t, Immutable, Private, kind),
|
VarInfo::new(spec_t, Immutable, Private, kind),
|
||||||
));
|
));
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ast::ParamPattern::Lit(_) => Ok(()),
|
ast::ParamPattern::Ref(name) => {
|
||||||
_ => unreachable!(),
|
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(
|
Err(TyCheckError::reassign_error(
|
||||||
line!() as usize,
|
line!() as usize,
|
||||||
name.loc(),
|
name.loc(),
|
||||||
|
|
|
@ -1111,6 +1111,23 @@ impl Context {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
(Type::FreeVar(_fv), _r) => todo!(),
|
(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)) => {
|
(Type::Subr(lsub), Type::Subr(rsub)) => {
|
||||||
for lpt in lsub.default_params.iter() {
|
for lpt in lsub.default_params.iter() {
|
||||||
if let Some(rpt) = rsub.default_params.iter().find(|rpt| rpt.name() == lpt.name()) {
|
if let Some(rpt) = rsub.default_params.iter().find(|rpt| rpt.name() == lpt.name()) {
|
||||||
|
|
|
@ -2291,7 +2291,23 @@ pub enum ParamPattern {
|
||||||
VarArgs(VarName),
|
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_locational_for_enum!(ParamPattern; Discard, VarName, Lit, Array, Tuple, Record, Ref, RefMut, VarArgs);
|
||||||
|
|
||||||
impl ParamPattern {
|
impl ParamPattern {
|
||||||
|
|
|
@ -111,19 +111,28 @@ impl LimitedDisplay for Constraint {
|
||||||
(true, false) => {
|
(true, false) => {
|
||||||
write!(f, "<: ")?;
|
write!(f, "<: ")?;
|
||||||
sup.limited_fmt(f, limit - 1)?;
|
sup.limited_fmt(f, limit - 1)?;
|
||||||
write!(f, "(cyclicity: {cyclicity:?})")
|
if cfg!(feature = "debug") {
|
||||||
|
write!(f, "(cyclicity: {cyclicity:?})")?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
(false, true) => {
|
(false, true) => {
|
||||||
write!(f, ":> ")?;
|
write!(f, ":> ")?;
|
||||||
sub.limited_fmt(f, limit - 1)?;
|
sub.limited_fmt(f, limit - 1)?;
|
||||||
write!(f, "(cyclicity: {cyclicity:?})")
|
if cfg!(feature = "debug") {
|
||||||
|
write!(f, "(cyclicity: {cyclicity:?})")?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
(false, false) => {
|
(false, false) => {
|
||||||
write!(f, ":> ")?;
|
write!(f, ":> ")?;
|
||||||
sub.limited_fmt(f, limit - 1)?;
|
sub.limited_fmt(f, limit - 1)?;
|
||||||
write!(f, ", <: ")?;
|
write!(f, ", <: ")?;
|
||||||
sup.limited_fmt(f, limit - 1)?;
|
sup.limited_fmt(f, limit - 1)?;
|
||||||
write!(f, "(cyclicity: {cyclicity:?})")
|
if cfg!(feature = "debug") {
|
||||||
|
write!(f, "(cyclicity: {cyclicity:?})")?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Self::TypeOf(t) => {
|
Self::TypeOf(t) => {
|
||||||
|
@ -258,7 +267,11 @@ impl<T: LimitedDisplay> LimitedDisplay for FreeKind<T> {
|
||||||
} => {
|
} => {
|
||||||
write!(f, "?{name}(")?;
|
write!(f, "?{name}(")?;
|
||||||
constraint.limited_fmt(f, limit - 1)?;
|
constraint.limited_fmt(f, limit - 1)?;
|
||||||
write!(f, ")[{lev}]")
|
write!(f, ")")?;
|
||||||
|
if cfg!(feature = "debug") {
|
||||||
|
write!(f, "[{lev}]")?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
Self::Unbound {
|
Self::Unbound {
|
||||||
id,
|
id,
|
||||||
|
@ -267,7 +280,11 @@ impl<T: LimitedDisplay> LimitedDisplay for FreeKind<T> {
|
||||||
} => {
|
} => {
|
||||||
write!(f, "?{id}(")?;
|
write!(f, "?{id}(")?;
|
||||||
constraint.limited_fmt(f, limit - 1)?;
|
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())
|
.and_then(|c| c.get_type().cloned())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn crack_subtype(&self) -> Option<Type> {
|
pub fn crack_sup(&self) -> Option<Type> {
|
||||||
self.borrow()
|
self.borrow()
|
||||||
.constraint()
|
.constraint()
|
||||||
.and_then(|c| c.get_super_type().cloned())
|
.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 {
|
pub const fn is_mut(&self) -> bool {
|
||||||
matches!(self, Self::Mut(_))
|
matches!(self, Self::Mut(_))
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue