Merge pull request #521 from erg-lang/perf_or_type

Change And/Or-type structures
This commit is contained in:
Shunsuke Shibayama 2024-09-18 14:31:37 +09:00 committed by GitHub
commit 040811744e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
28 changed files with 1036 additions and 765 deletions

View file

@ -763,9 +763,7 @@ impl Context {
self.structural_supertype_of(&l, rhs)
}
// {1, 2, 3} :> {1} or {2, 3} == true
(Refinement(_refine), Or(l, r)) => {
self.supertype_of(lhs, l) && self.supertype_of(lhs, r)
}
(Refinement(_refine), Or(tys)) => tys.iter().all(|ty| self.supertype_of(lhs, ty)),
// ({I: Int | True} :> Int) == true
// {N: Nat | ...} :> Int) == false
// ({I: Int | I >= 0} :> Int) == false
@ -817,41 +815,37 @@ impl Context {
self.sub_unify(&inst, l, &(), None).is_ok()
}
// Int or Str :> Str or Int == (Int :> Str && Str :> Int) || (Int :> Int && Str :> Str) == true
(Or(l_1, l_2), Or(r_1, r_2)) => {
if l_1.is_union_type() && self.supertype_of(l_1, rhs) {
return true;
}
if l_2.is_union_type() && self.supertype_of(l_2, rhs) {
return true;
}
(self.supertype_of(l_1, r_1) && self.supertype_of(l_2, r_2))
|| (self.supertype_of(l_1, r_2) && self.supertype_of(l_2, r_1))
}
// Int or Str or NoneType :> Str or Int
// Int or Str or NoneType :> Str or NoneType or Nat
(Or(l), Or(r)) => r.iter().all(|r| l.iter().any(|l| self.supertype_of(l, r))),
// not Nat :> not Int == true
(Not(l), Not(r)) => self.subtype_of(l, r),
// (Int or Str) :> Nat == Int :> Nat || Str :> Nat == true
// (Num or Show) :> Show == Num :> Show || Show :> Num == true
(Or(l_or, r_or), rhs) => self.supertype_of(l_or, rhs) || self.supertype_of(r_or, rhs),
(Or(ors), rhs) => ors.iter().any(|or| self.supertype_of(or, rhs)),
// Int :> (Nat or Str) == Int :> Nat && Int :> Str == false
(lhs, Or(l_or, r_or)) => self.supertype_of(lhs, l_or) && self.supertype_of(lhs, r_or),
(And(l_1, l_2), And(r_1, r_2)) => {
if l_1.is_intersection_type() && self.supertype_of(l_1, rhs) {
(lhs, Or(ors)) => ors.iter().all(|or| self.supertype_of(lhs, or)),
// Hash and Eq :> HashEq and ... == true
// Add(T) and Eq :> Add(Int) and Eq == true
(And(l), And(r)) => {
if r.iter().any(|r| l.iter().all(|l| self.supertype_of(l, r))) {
return true;
}
if l_2.is_intersection_type() && self.supertype_of(l_2, rhs) {
return true;
if l.len() == r.len() {
let mut r = r.clone();
for _ in 1..l.len() {
if l.iter().zip(&r).all(|(l, r)| self.supertype_of(l, r)) {
return true;
}
r.rotate_left(1);
}
}
(self.supertype_of(l_1, r_1) && self.supertype_of(l_2, r_2))
|| (self.supertype_of(l_1, r_2) && self.supertype_of(l_2, r_1))
false
}
// (Num and Show) :> Show == false
(And(l_and, r_and), rhs) => {
self.supertype_of(l_and, rhs) && self.supertype_of(r_and, rhs)
}
(And(ands), rhs) => ands.iter().all(|and| self.supertype_of(and, rhs)),
// Show :> (Num and Show) == true
(lhs, And(l_and, r_and)) => {
self.supertype_of(lhs, l_and) || self.supertype_of(lhs, r_and)
}
(lhs, And(ands)) => ands.iter().any(|and| self.supertype_of(lhs, and)),
// Not(Eq) :> Float == !(Eq :> Float) == true
(Not(_), Obj) => false,
(Not(l), rhs) => !self.supertype_of(l, rhs),
@ -923,18 +917,18 @@ impl Context {
Type::NamedTuple(fields) => fields.iter().cloned().collect(),
Type::Refinement(refine) => self.fields(&refine.t),
Type::Structural(t) => self.fields(t),
Type::Or(l, r) => {
let l_fields = self.fields(l);
let r_fields = self.fields(r);
let l_field_names = l_fields.keys().collect::<Set<_>>();
let r_field_names = r_fields.keys().collect::<Set<_>>();
let field_names = l_field_names.intersection(&r_field_names);
let mut fields = Dict::new();
for (name, l_t, r_t) in field_names
Type::Or(tys) => {
let or_fields = tys.iter().map(|t| self.fields(t)).collect::<Set<_>>();
let field_names = or_fields
.iter()
.map(|&name| (name, &l_fields[name], &r_fields[name]))
.flat_map(|fs| fs.keys())
.collect::<Set<_>>();
let mut fields = Dict::new();
for (name, tys) in field_names
.iter()
.map(|&name| (name, or_fields.iter().filter_map(|fields| fields.get(name))))
{
let union = self.union(l_t, r_t);
let union = tys.fold(Never, |acc, ty| self.union(&acc, ty));
fields.insert(name.clone(), union);
}
fields
@ -1417,6 +1411,8 @@ impl Context {
/// union({ .a = Int }, { .a = Str }) == { .a = Int or Str }
/// union({ .a = Int }, { .a = Int; .b = Int }) == { .a = Int } or { .a = Int; .b = Int } # not to lost `b` information
/// union((A and B) or C) == (A or C) and (B or C)
/// union(Never, Int) == Int
/// union(Obj, Int) == Obj
/// ```
pub(crate) fn union(&self, lhs: &Type, rhs: &Type) -> Type {
if lhs == rhs {
@ -1479,10 +1475,9 @@ impl Context {
(Some(sub), Some(sup)) => bounded(sub.clone(), sup.clone()),
_ => self.simple_union(lhs, rhs),
},
(other, or @ Or(_, _)) | (or @ Or(_, _), other) => self.union_add(or, other),
(other, or @ Or(_)) | (or @ Or(_), other) => self.union_add(or, other),
// (A and B) or C ==> (A or C) and (B or C)
(and_t @ And(_, _), other) | (other, and_t @ And(_, _)) => {
let ands = and_t.ands();
(And(ands), other) | (other, And(ands)) => {
let mut t = Type::Obj;
for branch in ands.iter() {
let union = self.union(branch, other);
@ -1666,6 +1661,12 @@ impl Context {
/// Returns intersection of two types (`A and B`).
/// If `A` and `B` have a subtype relationship, it is equal to `min(A, B)`.
/// ```erg
/// intersection(Nat, Int) == Nat
/// intersection(Int, Str) == Never
/// intersection(Obj, Int) == Int
/// intersection(Never, Int) == Never
/// ```
pub(crate) fn intersection(&self, lhs: &Type, rhs: &Type) -> Type {
if lhs == rhs {
return lhs.clone();
@ -1696,12 +1697,9 @@ impl Context {
(_, Not(r)) => self.diff(lhs, r),
(Not(l), _) => self.diff(rhs, l),
// A and B and A == A and B
(other, and @ And(_, _)) | (and @ And(_, _), other) => {
self.intersection_add(and, other)
}
(other, and @ And(_)) | (and @ And(_), other) => self.intersection_add(and, other),
// (A or B) and C == (A and C) or (B and C)
(or_t @ Or(_, _), other) | (other, or_t @ Or(_, _)) => {
let ors = or_t.ors();
(Or(ors), other) | (other, Or(ors)) => {
if ors.iter().any(|t| t.has_unbound_var()) {
return self.simple_intersection(lhs, rhs);
}
@ -1797,13 +1795,15 @@ impl Context {
/// intersection_add(Int and ?T(:> NoneType), Str) == Never
/// ```
fn intersection_add(&self, intersection: &Type, elem: &Type) -> Type {
let ands = intersection.ands();
let mut ands = intersection.ands();
let bounded = ands.iter().map(|t| t.lower_bounded());
for t in bounded {
if self.subtype_of(&t, elem) {
return intersection.clone();
} else if self.supertype_of(&t, elem) {
return constructors::ands(ands.linear_exclude(&t).include(elem.clone()));
ands.retain(|ty| ty != &t);
ands.push(elem.clone());
return constructors::ands(ands);
}
}
and(intersection.clone(), elem.clone())
@ -1836,21 +1836,21 @@ impl Context {
fn narrow_type_by_pred(&self, t: Type, pred: &Predicate) -> Type {
match (t, pred) {
(
Type::Or(l, r),
Type::Or(tys),
Predicate::NotEqual {
rhs: TyParam::Value(v),
..
},
) if v.is_none() => {
let l = self.narrow_type_by_pred(*l, pred);
let r = self.narrow_type_by_pred(*r, pred);
if l.is_nonetype() {
r
} else if r.is_nonetype() {
l
} else {
or(l, r)
let mut new_tys = Set::new();
for ty in tys {
let ty = self.narrow_type_by_pred(ty, pred);
if ty.is_nonelike() {
continue;
}
new_tys.insert(ty);
}
Type::checked_or(new_tys)
}
(Type::Refinement(refine), _) => {
let t = self.narrow_type_by_pred(*refine.t, pred);
@ -1992,8 +1992,12 @@ impl Context {
guard.target.clone(),
self.complement(&guard.to),
)),
Or(l, r) => self.intersection(&self.complement(l), &self.complement(r)),
And(l, r) => self.union(&self.complement(l), &self.complement(r)),
Or(ors) => ors
.iter()
.fold(Obj, |l, r| self.intersection(&l, &self.complement(r))),
And(ands) => ands
.iter()
.fold(Never, |l, r| self.union(&l, &self.complement(r))),
other => not(other.clone()),
}
}
@ -2011,7 +2015,14 @@ impl Context {
match lhs {
Type::FreeVar(fv) if fv.is_linked() => self.diff(&fv.crack(), rhs),
// Type::And(l, r) => self.intersection(&self.diff(l, rhs), &self.diff(r, rhs)),
Type::Or(l, r) => self.union(&self.diff(l, rhs), &self.diff(r, rhs)),
Type::Or(tys) => {
let mut new_tys = vec![];
for ty in tys {
let diff = self.diff(ty, rhs);
new_tys.push(diff);
}
new_tys.into_iter().fold(Never, |l, r| self.union(&l, &r))
}
_ => lhs.clone(),
}
}

View file

@ -2285,44 +2285,42 @@ impl Context {
Err((t, errs))
}
}
Type::And(l, r) => {
let l = match self.eval_t_params(*l, level, t_loc) {
Ok(l) => l,
Err((l, es)) => {
errs.extend(es);
l
Type::And(ands) => {
let mut new_ands = set! {};
for and in ands.into_iter() {
match self.eval_t_params(and, level, t_loc) {
Ok(and) => {
new_ands.insert(and);
}
Err((and, es)) => {
new_ands.insert(and);
errs.extend(es);
}
}
};
let r = match self.eval_t_params(*r, level, t_loc) {
Ok(r) => r,
Err((r, es)) => {
errs.extend(es);
r
}
};
let intersec = self.intersection(&l, &r);
}
let intersec = new_ands
.into_iter()
.fold(Type::Obj, |l, r| self.intersection(&l, &r));
if errs.is_empty() {
Ok(intersec)
} else {
Err((intersec, errs))
}
}
Type::Or(l, r) => {
let l = match self.eval_t_params(*l, level, t_loc) {
Ok(l) => l,
Err((l, es)) => {
errs.extend(es);
l
Type::Or(ors) => {
let mut new_ors = set! {};
for or in ors.into_iter() {
match self.eval_t_params(or, level, t_loc) {
Ok(or) => {
new_ors.insert(or);
}
Err((or, es)) => {
new_ors.insert(or);
errs.extend(es);
}
}
};
let r = match self.eval_t_params(*r, level, t_loc) {
Ok(r) => r,
Err((r, es)) => {
errs.extend(es);
r
}
};
let union = self.union(&l, &r);
}
let union = new_ors.into_iter().fold(Never, |l, r| self.union(&l, &r));
if errs.is_empty() {
Ok(union)
} else {

View file

@ -289,17 +289,21 @@ impl Generalizer {
}
proj_call(lhs, attr_name, args)
}
And(l, r) => {
let l = self.generalize_t(*l, uninit);
let r = self.generalize_t(*r, uninit);
And(ands) => {
// not `self.intersection` because types are generalized
and(l, r)
let ands = ands
.into_iter()
.map(|t| self.generalize_t(t, uninit))
.collect();
Type::checked_and(ands)
}
Or(l, r) => {
let l = self.generalize_t(*l, uninit);
let r = self.generalize_t(*r, uninit);
Or(ors) => {
// not `self.union` because types are generalized
or(l, r)
let ors = ors
.into_iter()
.map(|t| self.generalize_t(t, uninit))
.collect();
Type::checked_or(ors)
}
Not(l) => not(self.generalize_t(*l, uninit)),
Structural(ty) => {
@ -1045,15 +1049,23 @@ impl<'c, 'q, 'l, L: Locational> Dereferencer<'c, 'q, 'l, L> {
let pred = self.deref_pred(*refine.pred)?;
Ok(refinement(refine.var, t, pred))
}
And(l, r) => {
let l = self.deref_tyvar(*l)?;
let r = self.deref_tyvar(*r)?;
Ok(self.ctx.intersection(&l, &r))
And(ands) => {
let mut new_ands = vec![];
for t in ands.into_iter() {
new_ands.push(self.deref_tyvar(t)?);
}
Ok(new_ands
.into_iter()
.fold(Type::Obj, |acc, t| self.ctx.intersection(&acc, &t)))
}
Or(l, r) => {
let l = self.deref_tyvar(*l)?;
let r = self.deref_tyvar(*r)?;
Ok(self.ctx.union(&l, &r))
Or(ors) => {
let mut new_ors = vec![];
for t in ors.into_iter() {
new_ors.push(self.deref_tyvar(t)?);
}
Ok(new_ors
.into_iter()
.fold(Type::Never, |acc, t| self.ctx.union(&acc, &t)))
}
Not(ty) => {
let ty = self.deref_tyvar(*ty)?;
@ -1733,22 +1745,33 @@ impl Context {
/// ```
pub(crate) fn squash_tyvar(&self, typ: Type) -> Type {
match typ {
Or(l, r) => {
let l = self.squash_tyvar(*l);
let r = self.squash_tyvar(*r);
Or(tys) => {
let new_tys = tys
.into_iter()
.map(|t| self.squash_tyvar(t))
.collect::<Vec<_>>();
let mut union = Never;
// REVIEW:
if l.is_unnamed_unbound_var() && r.is_unnamed_unbound_var() {
match (self.subtype_of(&l, &r), self.subtype_of(&r, &l)) {
(true, true) | (true, false) => {
let _ = self.sub_unify(&l, &r, &(), None);
if new_tys.iter().all(|t| t.is_unnamed_unbound_var()) {
for ty in new_tys.iter() {
if union == Never {
union = ty.clone();
continue;
}
(false, true) => {
let _ = self.sub_unify(&r, &l, &(), None);
match (self.subtype_of(&union, ty), self.subtype_of(&union, ty)) {
(true, true) | (true, false) => {
let _ = self.sub_unify(&union, ty, &(), None);
}
(false, true) => {
let _ = self.sub_unify(ty, &union, &(), None);
}
_ => {}
}
_ => {}
}
}
self.union(&l, &r)
new_tys
.into_iter()
.fold(Never, |acc, t| self.union(&acc, &t))
}
FreeVar(ref fv) if fv.constraint_is_sandwiched() => {
let (sub_t, super_t) = fv.get_subsup().unwrap();

View file

@ -116,9 +116,12 @@ impl Context {
return Some(hint);
}
}
(Type::And(l, r), found) => {
let left = self.readable_type(l.as_ref().clone());
let right = self.readable_type(r.as_ref().clone());
(Type::And(tys), found) if tys.len() == 2 => {
let mut iter = tys.iter();
let l = iter.next().unwrap();
let r = iter.next().unwrap();
let left = self.readable_type(l.clone());
let right = self.readable_type(r.clone());
if self.supertype_of(l, found) {
let msg = switch_lang!(
"japanese" => format!("{found}{left}のサブタイプですが、{right}のサブタイプではありません"),

View file

@ -16,6 +16,9 @@ use crate::varinfo::Mutability;
use Mutability::*;
impl Context {
// NOTE: Registering traits that a class implements requires type checking,
// which means that registering a class requires that the preceding types have already been registered,
// so `register_builtin_type` should be called as early as possible.
pub(super) fn init_builtin_classes(&mut self) {
let vis = if PYTHON_MODE {
Visibility::BUILTIN_PUBLIC
@ -29,6 +32,7 @@ impl Context {
let N = mono_q_tp(TY_N, instanceof(Nat));
let M = mono_q_tp(TY_M, instanceof(Nat));
let never = Self::builtin_mono_class(NEVER, 1);
self.register_builtin_type(Never, never, vis.clone(), Const, Some(NEVER));
/* Obj */
let mut obj = Self::builtin_mono_class(OBJ, 2);
obj.register_py_builtin(
@ -2965,6 +2969,21 @@ impl Context {
None,
union,
);
self.register_builtin_type(
mono(GENERIC_TUPLE),
generic_tuple,
vis.clone(),
Const,
Some(FUNC_TUPLE),
);
self.register_builtin_type(
homo_tuple_t,
homo_tuple,
vis.clone(),
Const,
Some(FUNC_TUPLE),
);
self.register_builtin_type(_tuple_t, tuple_, vis.clone(), Const, Some(FUNC_TUPLE));
/* Or (true or type) */
let or_t = poly(OR, vec![ty_tp(L), ty_tp(R)]);
let mut or = Self::builtin_poly_class(OR, vec![PS::t_nd(TY_L), PS::t_nd(TY_R)], 2);
@ -3673,6 +3692,8 @@ impl Context {
Some(FUNC_UPDATE),
);
list_mut_.register_trait_methods(list_mut_t.clone(), list_mut_mutable);
self.register_builtin_type(lis_t, list_, vis.clone(), Const, Some(LIST));
self.register_builtin_type(list_mut_t, list_mut_, vis.clone(), Const, Some(LIST));
/* ByteArray! */
let bytearray_mut_t = mono(MUT_BYTEARRAY);
let mut bytearray_mut = Self::builtin_mono_class(MUT_BYTEARRAY, 2);
@ -4213,7 +4234,6 @@ impl Context {
let mut qfunc_meta_type = Self::builtin_mono_class(QUANTIFIED_FUNC_META_TYPE, 2);
qfunc_meta_type.register_superclass(mono(QUANTIFIED_PROC_META_TYPE), &qproc_meta_type);
qfunc_meta_type.register_superclass(mono(QUANTIFIED_FUNC), &qfunc);
self.register_builtin_type(Never, never, vis.clone(), Const, Some(NEVER));
self.register_builtin_type(Obj, obj, vis.clone(), Const, Some(FUNC_OBJECT));
// self.register_type(mono(RECORD), vec![], record, Visibility::BUILTIN_PRIVATE, Const);
let name = if PYTHON_MODE { FUNC_INT } else { INT };
@ -4261,7 +4281,6 @@ impl Context {
Const,
Some(UNSIZED_LIST),
);
self.register_builtin_type(lis_t, list_, vis.clone(), Const, Some(LIST));
self.register_builtin_type(mono(SLICE), slice, vis.clone(), Const, Some(FUNC_SLICE));
self.register_builtin_type(
mono(GENERIC_SET),
@ -4274,21 +4293,6 @@ impl Context {
self.register_builtin_type(g_dict_t, generic_dict, vis.clone(), Const, Some(DICT));
self.register_builtin_type(dict_t, dict_, vis.clone(), Const, Some(DICT));
self.register_builtin_type(mono(BYTES), bytes, vis.clone(), Const, Some(BYTES));
self.register_builtin_type(
mono(GENERIC_TUPLE),
generic_tuple,
vis.clone(),
Const,
Some(FUNC_TUPLE),
);
self.register_builtin_type(
homo_tuple_t,
homo_tuple,
vis.clone(),
Const,
Some(FUNC_TUPLE),
);
self.register_builtin_type(_tuple_t, tuple_, vis.clone(), Const, Some(FUNC_TUPLE));
self.register_builtin_type(mono(RECORD), record, vis.clone(), Const, Some(RECORD));
self.register_builtin_type(
mono(RECORD_META_TYPE),
@ -4411,7 +4415,6 @@ impl Context {
Some(MEMORYVIEW),
);
self.register_builtin_type(mono(MUT_FILE), file_mut, vis.clone(), Const, Some(FILE));
self.register_builtin_type(list_mut_t, list_mut_, vis.clone(), Const, Some(LIST));
self.register_builtin_type(
bytearray_mut_t,
bytearray_mut,

View file

@ -588,10 +588,10 @@ impl Context {
neg.register_builtin_erg_decl(OP_NEG, op_t, Visibility::BUILTIN_PUBLIC);
neg.register_builtin_erg_decl(OUTPUT, Type, Visibility::BUILTIN_PUBLIC);
/* Num */
let mut num = Self::builtin_mono_trait(NUM, 2);
num.register_superclass(poly(ADD, vec![]), &add);
num.register_superclass(poly(SUB, vec![]), &sub);
num.register_superclass(poly(MUL, vec![]), &mul);
let num = Self::builtin_mono_trait(NUM, 2);
// num.register_superclass(poly(ADD, vec![]), &add);
// num.register_superclass(poly(SUB, vec![]), &sub);
// num.register_superclass(poly(MUL, vec![]), &mul);
/* ToBool */
let mut to_bool = Self::builtin_mono_trait(TO_BOOL, 2);
let _Slf = mono_q(SELF, subtypeof(mono(TO_BOOL)));

View file

@ -1046,35 +1046,35 @@ impl Context {
}
Type::Structural(t) => self.get_attr_info_from_attributive(t, ident, namespace),
// TODO: And
Type::Or(l, r) => {
let l_info = self.get_attr_info_from_attributive(l, ident, namespace);
let r_info = self.get_attr_info_from_attributive(r, ident, namespace);
match (l_info, r_info) {
(Triple::Ok(l), Triple::Ok(r)) => {
let res = self.union(&l.t, &r.t);
let vis = if l.vis.is_public() && r.vis.is_public() {
Visibility::DUMMY_PUBLIC
} else {
Visibility::DUMMY_PRIVATE
};
let vi = VarInfo::new(
res,
l.muty,
vis,
l.kind,
l.comptime_decos,
l.ctx,
l.py_name,
l.def_loc,
);
Triple::Ok(vi)
Type::Or(tys) => {
let mut info = Triple::<VarInfo, _>::None;
for ty in tys {
match (
self.get_attr_info_from_attributive(ty, ident, namespace),
&info,
) {
(Triple::Ok(vi), Triple::Ok(vi_)) => {
let res = self.union(&vi.t, &vi_.t);
let vis = if vi.vis.is_public() && vi_.vis.is_public() {
Visibility::DUMMY_PUBLIC
} else {
Visibility::DUMMY_PRIVATE
};
let vi = VarInfo { t: res, vis, ..vi };
info = Triple::Ok(vi);
}
(Triple::Ok(vi), Triple::None) => {
info = Triple::Ok(vi);
}
(Triple::Err(err), _) => {
info = Triple::Err(err);
break;
}
(Triple::None, _) => {}
(_, Triple::Err(_)) => unreachable!(),
}
(Triple::Ok(_), Triple::Err(e)) | (Triple::Err(e), Triple::Ok(_)) => {
Triple::Err(e)
}
(Triple::Err(e1), Triple::Err(_e2)) => Triple::Err(e1),
_ => Triple::None,
}
info
}
_other => Triple::None,
}
@ -1952,7 +1952,7 @@ impl Context {
res
}
}
Type::And(_, _) => {
Type::And(_) => {
let instance = self.resolve_overload(
obj,
instance.clone(),
@ -3012,32 +3012,30 @@ impl Context {
self.get_nominal_super_type_ctxs(&Type)
}
}
Type::And(l, r) => {
match (
self.get_nominal_super_type_ctxs(l),
self.get_nominal_super_type_ctxs(r),
) {
// TODO: sort
(Some(l), Some(r)) => Some([l, r].concat()),
(Some(l), None) => Some(l),
(None, Some(r)) => Some(r),
(None, None) => None,
Type::And(tys) => {
let mut acc = vec![];
for ctxs in tys
.iter()
.filter_map(|t| self.get_nominal_super_type_ctxs(t))
{
acc.extend(ctxs);
}
if acc.is_empty() {
None
} else {
Some(acc)
}
}
// TODO
Type::Or(l, r) => match (l.as_ref(), r.as_ref()) {
(Type::FreeVar(l), Type::FreeVar(r))
if l.is_unbound_and_sandwiched() && r.is_unbound_and_sandwiched() =>
{
let (_lsub, lsup) = l.get_subsup().unwrap();
let (_rsub, rsup) = r.get_subsup().unwrap();
self.get_nominal_super_type_ctxs(&self.union(&lsup, &rsup))
Type::Or(tys) => {
let union = tys
.iter()
.fold(Never, |l, r| self.union(&l, &r.upper_bounded()));
if union.is_union_type() {
self.get_nominal_super_type_ctxs(&Obj)
} else {
self.get_nominal_super_type_ctxs(&union)
}
(Type::Refinement(l), Type::Refinement(r)) if l.t == r.t => {
self.get_nominal_super_type_ctxs(&l.t)
}
_ => self.get_nominal_type_ctx(&Obj).map(|ctx| vec![ctx]),
},
}
_ => self
.get_simple_nominal_super_type_ctxs(t)
.map(|ctxs| ctxs.collect()),
@ -3231,7 +3229,7 @@ impl Context {
.unwrap_or(self)
.rec_local_get_mono_type("GenericNamedTuple");
}
Type::Or(_l, _r) => {
Type::Or(_) => {
if let Some(ctx) = self.get_nominal_type_ctx(&poly("Or", vec![])) {
return Some(ctx);
}
@ -3366,26 +3364,27 @@ impl Context {
match trait_ {
// And(Add, Sub) == intersection({Int <: Add(Int), Bool <: Add(Bool) ...}, {Int <: Sub(Int), ...})
// == {Int <: Add(Int) and Sub(Int), ...}
Type::And(l, r) => {
let l_impls = self.get_trait_impls(l);
let l_base = Set::from_iter(l_impls.iter().map(|ti| &ti.sub_type));
let r_impls = self.get_trait_impls(r);
let r_base = Set::from_iter(r_impls.iter().map(|ti| &ti.sub_type));
let bases = l_base.intersection(&r_base);
Type::And(tys) => {
let impls = tys
.iter()
.flat_map(|ty| self.get_trait_impls(ty))
.collect::<Set<_>>();
let bases = impls.iter().map(|ti| &ti.sub_type);
let mut isec = set! {};
for base in bases.into_iter() {
let lti = l_impls.iter().find(|ti| &ti.sub_type == base).unwrap();
let rti = r_impls.iter().find(|ti| &ti.sub_type == base).unwrap();
let sup_trait = self.intersection(&lti.sup_trait, &rti.sup_trait);
isec.insert(TraitImpl::new(lti.sub_type.clone(), sup_trait, None));
for base in bases {
let base_impls = impls.iter().filter(|ti| ti.sub_type == *base);
let sup_trait =
base_impls.fold(Obj, |l, r| self.intersection(&l, &r.sup_trait));
if sup_trait != Obj {
isec.insert(TraitImpl::new(base.clone(), sup_trait, None));
}
}
isec
}
Type::Or(l, r) => {
let l_impls = self.get_trait_impls(l);
let r_impls = self.get_trait_impls(r);
Type::Or(tys) => {
// FIXME:
l_impls.union(&r_impls)
tys.iter()
.fold(set! {}, |acc, ty| acc.union(&self.get_trait_impls(ty)))
}
_ => self.get_simple_trait_impls(trait_),
}
@ -3955,11 +3954,11 @@ impl Context {
pub fn is_class(&self, typ: &Type) -> bool {
match typ {
Type::And(_l, _r) => false,
Type::And(_) => false,
Type::Never => true,
Type::FreeVar(fv) if fv.is_linked() => self.is_class(&fv.crack()),
Type::FreeVar(_) => false,
Type::Or(l, r) => self.is_class(l) && self.is_class(r),
Type::Or(tys) => tys.iter().all(|t| self.is_class(t)),
Type::Proj { lhs, rhs } => self
.get_proj_candidates(lhs, rhs)
.iter()
@ -3982,7 +3981,8 @@ impl Context {
Type::Never => false,
Type::FreeVar(fv) if fv.is_linked() => self.is_class(&fv.crack()),
Type::FreeVar(_) => false,
Type::And(l, r) | Type::Or(l, r) => self.is_trait(l) && self.is_trait(r),
Type::And(tys) => tys.iter().any(|t| self.is_trait(t)),
Type::Or(tys) => tys.iter().all(|t| self.is_trait(t)),
Type::Proj { lhs, rhs } => self
.get_proj_candidates(lhs, rhs)
.iter()

View file

@ -953,15 +953,21 @@ impl Context {
let t = self.instantiate_t_inner(*t, tmp_tv_cache, loc)?;
Ok(t.structuralize())
}
And(l, r) => {
let l = self.instantiate_t_inner(*l, tmp_tv_cache, loc)?;
let r = self.instantiate_t_inner(*r, tmp_tv_cache, loc)?;
Ok(self.intersection(&l, &r))
And(tys) => {
let mut new_tys = vec![];
for ty in tys.iter().cloned() {
new_tys.push(self.instantiate_t_inner(ty, tmp_tv_cache, loc)?);
}
Ok(new_tys
.into_iter()
.fold(Obj, |l, r| self.intersection(&l, &r)))
}
Or(l, r) => {
let l = self.instantiate_t_inner(*l, tmp_tv_cache, loc)?;
let r = self.instantiate_t_inner(*r, tmp_tv_cache, loc)?;
Ok(self.union(&l, &r))
Or(tys) => {
let mut new_tys = vec![];
for ty in tys.iter().cloned() {
new_tys.push(self.instantiate_t_inner(ty, tmp_tv_cache, loc)?);
}
Ok(new_tys.into_iter().fold(Never, |l, r| self.union(&l, &r)))
}
Not(ty) => {
let ty = self.instantiate_t_inner(*ty, tmp_tv_cache, loc)?;
@ -998,10 +1004,12 @@ impl Context {
let t = fv.crack().clone();
self.instantiate(t, callee)
}
And(lhs, rhs) => {
let lhs = self.instantiate(*lhs, callee)?;
let rhs = self.instantiate(*rhs, callee)?;
Ok(lhs & rhs)
And(tys) => {
let tys = tys
.into_iter()
.map(|t| self.instantiate(t, callee))
.collect::<TyCheckResult<Vec<_>>>()?;
Ok(tys.into_iter().fold(Obj, |l, r| l & r))
}
Quantified(quant) => {
let mut tmp_tv_cache = TyVarCache::new(self.level, self);
@ -1028,22 +1036,16 @@ impl Context {
)?;
}
}
Type::And(l, r) => {
if let Some(self_t) = l.self_t() {
self.sub_unify(
callee.ref_t(),
self_t,
callee,
Some(&Str::ever("self")),
)?;
}
if let Some(self_t) = r.self_t() {
self.sub_unify(
callee.ref_t(),
self_t,
callee,
Some(&Str::ever("self")),
)?;
Type::And(tys) => {
for ty in tys {
if let Some(self_t) = ty.self_t() {
self.sub_unify(
callee.ref_t(),
self_t,
callee,
Some(&Str::ever("self")),
)?;
}
}
}
other => unreachable!("{other}"),
@ -1066,10 +1068,12 @@ impl Context {
let t = fv.crack().clone();
self.instantiate_dummy(t)
}
And(lhs, rhs) => {
let lhs = self.instantiate_dummy(*lhs)?;
let rhs = self.instantiate_dummy(*rhs)?;
Ok(lhs & rhs)
And(tys) => {
let tys = tys
.into_iter()
.map(|t| self.instantiate_dummy(t))
.collect::<TyCheckResult<Vec<_>>>()?;
Ok(tys.into_iter().fold(Obj, |l, r| l & r))
}
Quantified(quant) => {
let mut tmp_tv_cache = TyVarCache::new(self.level, self);

View file

@ -70,6 +70,7 @@ impl<'c, 'l, 'u, L: Locational> Unifier<'c, 'l, 'u, L> {
/// occur(?T(<: Str) or ?U(<: Int), ?T(<: Str)) ==> Error
/// occur(?T(<: ?U or Y), ?U) ==> OK
/// occur(?T, ?T.Output) ==> OK
/// occur(?T, ?T or Int) ==> Error
/// ```
fn occur(&self, maybe_sub: &Type, maybe_sup: &Type) -> TyCheckResult<()> {
if maybe_sub == maybe_sup {
@ -155,17 +156,71 @@ impl<'c, 'l, 'u, L: Locational> Unifier<'c, 'l, 'u, L> {
}
Ok(())
}
(Or(l, r), Or(l2, r2)) | (And(l, r), And(l2, r2)) => self
.occur(l, l2)
.and(self.occur(r, r2))
.or(self.occur(l, r2).and(self.occur(r, l2))),
(lhs, Or(l, r)) | (lhs, And(l, r)) => {
self.occur_inner(lhs, l)?;
self.occur_inner(lhs, r)
// FIXME: This is not correct, we must visit all permutations of the types
(And(l), And(r)) if l.len() == r.len() => {
let mut r = r.clone();
for _ in 0..r.len() {
if l.iter()
.zip(r.iter())
.all(|(l, r)| self.occur_inner(l, r).is_ok())
{
return Ok(());
}
r.rotate_left(1);
}
Err(TyCheckErrors::from(TyCheckError::subtyping_error(
self.ctx.cfg.input.clone(),
line!() as usize,
maybe_sub,
maybe_sup,
self.loc.loc(),
self.ctx.caused_by(),
)))
}
(Or(l, r), rhs) | (And(l, r), rhs) => {
self.occur_inner(l, rhs)?;
self.occur_inner(r, rhs)
(Or(l), Or(r)) if l.len() == r.len() => {
let l = l.to_vec();
let mut r = r.to_vec();
for _ in 0..r.len() {
if l.iter()
.zip(r.iter())
.all(|(l, r)| self.occur_inner(l, r).is_ok())
{
return Ok(());
}
r.rotate_left(1);
}
Err(TyCheckErrors::from(TyCheckError::subtyping_error(
self.ctx.cfg.input.clone(),
line!() as usize,
maybe_sub,
maybe_sup,
self.loc.loc(),
self.ctx.caused_by(),
)))
}
(lhs, And(tys)) => {
for ty in tys.iter() {
self.occur_inner(lhs, ty)?;
}
Ok(())
}
(lhs, Or(tys)) => {
for ty in tys.iter() {
self.occur_inner(lhs, ty)?;
}
Ok(())
}
(And(tys), rhs) => {
for ty in tys.iter() {
self.occur_inner(ty, rhs)?;
}
Ok(())
}
(Or(tys), rhs) => {
for ty in tys.iter() {
self.occur_inner(ty, rhs)?;
}
Ok(())
}
_ => Ok(()),
}
@ -266,13 +321,29 @@ impl<'c, 'l, 'u, L: Locational> Unifier<'c, 'l, 'u, L> {
}
Ok(())
}
(lhs, Or(l, r)) | (lhs, And(l, r)) => {
self.occur_inner(lhs, l)?;
self.occur_inner(lhs, r)
(lhs, And(tys)) => {
for ty in tys.iter() {
self.occur_inner(lhs, ty)?;
}
Ok(())
}
(Or(l, r), rhs) | (And(l, r), rhs) => {
self.occur_inner(l, rhs)?;
self.occur_inner(r, rhs)
(lhs, Or(tys)) => {
for ty in tys.iter() {
self.occur_inner(lhs, ty)?;
}
Ok(())
}
(And(tys), rhs) => {
for ty in tys.iter() {
self.occur_inner(ty, rhs)?;
}
Ok(())
}
(Or(tys), rhs) => {
for ty in tys.iter() {
self.occur_inner(ty, rhs)?;
}
Ok(())
}
_ => Ok(()),
}
@ -1227,38 +1298,66 @@ impl<'c, 'l, 'u, L: Locational> Unifier<'c, 'l, 'u, L> {
// self.sub_unify(&lsub, &union, loc, param_name)?;
maybe_sup.update_tyvar(union, intersec, self.undoable, false);
}
// TODO: Preferentially compare same-structure types (e.g. K(?T) <: K(?U))
(And(ltys), And(rtys)) => {
let mut ltys_ = ltys.clone();
let mut rtys_ = rtys.clone();
// Show and EqHash and T <: Eq and Show and Ord
// => EqHash and T <: Eq and Ord
for lty in ltys.iter() {
if let Some(idx) = rtys_.iter().position(|r| r == lty) {
rtys_.remove(idx);
let idx = ltys_.iter().position(|l| l == lty).unwrap();
ltys_.remove(idx);
}
}
// EqHash and T <: Eq and Ord
for lty in ltys_.iter() {
// lty: EqHash
// rty: Eq, Ord
for rty in rtys_.iter() {
if self.ctx.subtype_of(lty, rty) {
self.sub_unify(lty, rty)?;
continue;
}
}
}
}
// TODO: Preferentially compare same-structure types (e.g. K(?T) <: K(?U))
// Nat or Str or NoneType <: NoneType or ?T or Int
// => Str <: ?T
// (Int or ?T) <: (?U or Int)
// OK: (Int <: Int); (?T <: ?U)
// NG: (Int <: ?U); (?T <: Int)
(Or(l1, r1), Or(l2, r2)) | (And(l1, r1), And(l2, r2)) => {
if self.ctx.subtype_of(l1, l2) && self.ctx.subtype_of(r1, r2) {
let (l_sup, r_sup) = if !l1.is_unbound_var()
&& !r2.is_unbound_var()
&& self.ctx.subtype_of(l1, r2)
{
(r2, l2)
} else {
(l2, r2)
};
self.sub_unify(l1, l_sup)?;
self.sub_unify(r1, r_sup)?;
} else {
self.sub_unify(l1, r2)?;
self.sub_unify(r1, l2)?;
(Or(ltys), Or(rtys)) => {
let mut ltys_ = ltys.clone();
let mut rtys_ = rtys.clone();
// Nat or T or Str <: Str or Int or NoneType
// => Nat or T <: Int or NoneType
for lty in ltys {
if rtys_.linear_remove(lty) {
ltys_.linear_remove(lty);
}
}
// Nat or T <: Int or NoneType
for lty in ltys_.iter() {
// lty: Nat
// rty: Int, NoneType
for rty in rtys_.iter() {
if self.ctx.subtype_of(lty, rty) {
self.sub_unify(lty, rty)?;
continue;
}
}
}
}
// NG: Nat <: ?T or Int ==> Nat or Int (?T = Nat)
// OK: Nat <: ?T or Int ==> ?T or Int
(sub, Or(l, r))
if l.is_unbound_var()
&& !sub.is_unbound_var()
&& !r.is_unbound_var()
&& self.ctx.subtype_of(sub, r) => {}
(sub, Or(l, r))
if r.is_unbound_var()
&& !sub.is_unbound_var()
&& !l.is_unbound_var()
&& self.ctx.subtype_of(sub, l) => {}
(sub, Or(tys))
if !sub.is_unbound_var()
&& tys
.iter()
.any(|ty| !ty.is_unbound_var() && self.ctx.subtype_of(sub, ty)) => {}
// e.g. Structural({ .method = (self: T) -> Int })/T
(Structural(sub), FreeVar(sup_fv))
if sup_fv.is_unbound() && sub.contains_tvar(sup_fv) => {}
@ -1622,30 +1721,34 @@ impl<'c, 'l, 'u, L: Locational> Unifier<'c, 'l, 'u, L> {
}
}
// (X or Y) <: Z is valid when X <: Z and Y <: Z
(Or(l, r), _) => {
self.sub_unify(l, maybe_sup)?;
self.sub_unify(r, maybe_sup)?;
(Or(tys), _) => {
for ty in tys {
self.sub_unify(ty, maybe_sup)?;
}
}
// X <: (Y and Z) is valid when X <: Y and X <: Z
(_, And(l, r)) => {
self.sub_unify(maybe_sub, l)?;
self.sub_unify(maybe_sub, r)?;
(_, And(tys)) => {
for ty in tys {
self.sub_unify(maybe_sub, ty)?;
}
}
// (X and Y) <: Z is valid when X <: Z or Y <: Z
(And(l, r), _) => {
if self.ctx.subtype_of(l, maybe_sup) {
self.sub_unify(l, maybe_sup)?;
} else {
self.sub_unify(r, maybe_sup)?;
(And(tys), _) => {
for ty in tys {
if self.ctx.subtype_of(ty, maybe_sup) {
return self.sub_unify(ty, maybe_sup);
}
}
self.sub_unify(tys.iter().next().unwrap(), maybe_sup)?;
}
// X <: (Y or Z) is valid when X <: Y or X <: Z
(_, Or(l, r)) => {
if self.ctx.subtype_of(maybe_sub, l) {
self.sub_unify(maybe_sub, l)?;
} else {
self.sub_unify(maybe_sub, r)?;
(_, Or(tys)) => {
for ty in tys {
if self.ctx.subtype_of(maybe_sub, ty) {
return self.sub_unify(maybe_sub, ty);
}
}
self.sub_unify(maybe_sub, tys.iter().next().unwrap())?;
}
(Ref(sub), Ref(sup)) => {
self.sub_unify(sub, sup)?;
@ -1887,27 +1990,35 @@ impl<'c, 'l, 'u, L: Locational> Unifier<'c, 'l, 'u, L> {
/// ```
fn unify(&self, lhs: &Type, rhs: &Type) -> Option<Type> {
match (lhs, rhs) {
(Type::Or(l, r), other) | (other, Type::Or(l, r)) => {
if let Some(t) = self.unify(l, other) {
return self.unify(&t, l);
} else if let Some(t) = self.unify(r, other) {
return self.unify(&t, l);
}
return None;
(Never, other) | (other, Never) => {
return Some(other.clone());
}
(Type::FreeVar(fv), _) if fv.is_linked() => return self.unify(&fv.crack(), rhs),
(_, Type::FreeVar(fv)) if fv.is_linked() => return self.unify(lhs, &fv.crack()),
(Or(tys), other) | (other, Or(tys)) => {
let mut unified = Never;
for ty in tys {
if let Some(t) = self.unify(ty, other) {
unified = self.ctx.union(&unified, &t);
}
}
if unified != Never {
return Some(unified);
} else {
return None;
}
}
(FreeVar(fv), _) if fv.is_linked() => return self.unify(&fv.crack(), rhs),
(_, FreeVar(fv)) if fv.is_linked() => return self.unify(lhs, &fv.crack()),
// TODO: unify(?T, ?U) ?
(Type::FreeVar(_), Type::FreeVar(_)) => {}
(Type::FreeVar(fv), _) if fv.constraint_is_sandwiched() => {
(FreeVar(_), FreeVar(_)) => {}
(FreeVar(fv), _) if fv.constraint_is_sandwiched() => {
let sub = fv.get_sub()?;
return self.unify(&sub, rhs);
}
(_, Type::FreeVar(fv)) if fv.constraint_is_sandwiched() => {
(_, FreeVar(fv)) if fv.constraint_is_sandwiched() => {
let sub = fv.get_sub()?;
return self.unify(lhs, &sub);
}
(Type::Refinement(lhs), Type::Refinement(rhs)) => {
(Refinement(lhs), Refinement(rhs)) => {
if let Some(_union) = self.unify(&lhs.t, &rhs.t) {
return Some(self.ctx.union_refinement(lhs, rhs).into());
}
@ -1917,11 +2028,11 @@ impl<'c, 'l, 'u, L: Locational> Unifier<'c, 'l, 'u, L> {
let l_sups = self.ctx.get_super_classes(lhs)?;
let r_sups = self.ctx.get_super_classes(rhs)?;
for l_sup in l_sups {
if self.ctx.supertype_of(&l_sup, &Obj) {
if l_sup == Obj || self.ctx.is_trait(&l_sup) {
continue;
}
for r_sup in r_sups.clone() {
if self.ctx.supertype_of(&r_sup, &Obj) {
if r_sup == Obj || self.ctx.is_trait(&r_sup) {
continue;
}
if let Some(t) = self.ctx.max(&l_sup, &r_sup).either() {

View file

@ -362,10 +362,9 @@ impl<A: ASTBuildable> GenericASTLowerer<A> {
}
}
fn elem_err(&self, l: &Type, r: &Type, elem: &hir::Expr) -> LowerErrors {
fn elem_err(&self, union: Type, elem: &hir::Expr) -> LowerErrors {
let elem_disp_notype = elem.to_string_notype();
let l = self.module.context.readable_type(l.clone());
let r = self.module.context.readable_type(r.clone());
let union = self.module.context.readable_type(union);
LowerErrors::from(LowerError::syntax_error(
self.cfg.input.clone(),
line!() as usize,
@ -379,10 +378,10 @@ impl<A: ASTBuildable> GenericASTLowerer<A> {
)
.to_owned(),
Some(switch_lang!(
"japanese" => format!("[..., {elem_disp_notype}: {l} or {r}]など明示的に型を指定してください"),
"simplified_chinese" => format!("请明确指定类型,例如: [..., {elem_disp_notype}: {l} or {r}]"),
"traditional_chinese" => format!("請明確指定類型,例如: [..., {elem_disp_notype}: {l} or {r}]"),
"english" => format!("please specify the type explicitly, e.g. [..., {elem_disp_notype}: {l} or {r}]"),
"japanese" => format!("[..., {elem_disp_notype}: {union}]など明示的に型を指定してください"),
"simplified_chinese" => format!("请明确指定类型,例如: [..., {elem_disp_notype}: {union}]"),
"traditional_chinese" => format!("請明確指定類型,例如: [..., {elem_disp_notype}: {union}]"),
"english" => format!("please specify the type explicitly, e.g. [..., {elem_disp_notype}: {union}]"),
)),
))
}
@ -453,36 +452,25 @@ impl<A: ASTBuildable> GenericASTLowerer<A> {
union: &Type,
elem: &hir::Expr,
) -> LowerResult<()> {
if ERG_MODE && expect_elem.is_none() {
if let Some((l, r)) = union_.union_pair() {
match (l.is_unbound_var(), r.is_unbound_var()) {
// e.g. [1, "a"]
(false, false) => {
if let hir::Expr::TypeAsc(type_asc) = elem {
// e.g. [1, "a": Str or NoneType]
if !self
.module
.context
.supertype_of(&type_asc.spec.spec_t, union)
{
return Err(self.elem_err(&l, &r, elem));
} // else(OK): e.g. [1, "a": Str or Int]
}
// OK: ?T(:> {"a"}) or ?U(:> {"b"}) or {"c", "d"} => {"a", "b", "c", "d"} <: Str
else if self
.module
.context
.coerce(union_.derefine(), &())
.map_or(true, |coerced| coerced.union_pair().is_some())
{
return Err(self.elem_err(&l, &r, elem));
}
}
// TODO: check if the type is compatible with the other type
(true, false) => {}
(false, true) => {}
(true, true) => {}
}
if ERG_MODE && expect_elem.is_none() && union_.union_size() > 1 {
if let hir::Expr::TypeAsc(type_asc) = elem {
// e.g. [1, "a": Str or NoneType]
if !self
.module
.context
.supertype_of(&type_asc.spec.spec_t, union)
{
return Err(self.elem_err(union_.clone(), elem));
} // else(OK): e.g. [1, "a": Str or Int]
}
// OK: ?T(:> {"a"}) or ?U(:> {"b"}) or {"c", "d"} => {"a", "b", "c", "d"} <: Str
else if self
.module
.context
.coerce(union_.derefine(), &())
.map_or(true, |coerced| coerced.union_pair().is_some())
{
return Err(self.elem_err(union_.clone(), elem));
}
}
Ok(())
@ -1502,9 +1490,10 @@ impl<A: ASTBuildable> GenericASTLowerer<A> {
}
_ => {}
},
Type::And(lhs, rhs) => {
self.push_guard(nth, kind, lhs);
self.push_guard(nth, kind, rhs);
Type::And(tys) => {
for ty in tys {
self.push_guard(nth, kind, ty);
}
}
_ => {}
}

View file

@ -1,7 +1,7 @@
use std::fmt;
use std::thread::{current, JoinHandle, ThreadId};
use erg_common::consts::DEBUG_MODE;
use erg_common::consts::{DEBUG_MODE, SINGLE_THREAD};
use erg_common::dict::Dict;
use erg_common::pathutil::NormalizedPathBuf;
use erg_common::shared::Shared;
@ -169,12 +169,19 @@ impl SharedPromises {
}
pub fn join(&self, path: &NormalizedPathBuf) -> std::thread::Result<()> {
if !self.graph.entries().contains(path) {
return Err(Box::new(format!("not registered: {path}")));
}
if self.graph.ancestors(path).contains(&self.root) {
// cycle detected, `self.path` must not in the dependencies
// Erg analysis processes never join ancestor threads (although joining ancestors itself is allowed in Rust)
// self.wait_until_finished(path);
return Ok(());
}
if SINGLE_THREAD {
assert!(self.is_joined(path));
return Ok(());
}
// Suppose A depends on B and C, and B depends on C.
// In this case, B must join C before A joins C. Otherwise, a deadlock will occur.
let children = self.graph.children(path);

View file

@ -593,35 +593,11 @@ pub fn refinement(var: Str, t: Type, pred: Predicate) -> Type {
}
pub fn and(lhs: Type, rhs: Type) -> Type {
match (lhs, rhs) {
(Type::And(l, r), other) | (other, Type::And(l, r)) => {
if l.as_ref() == &other {
and(*r, other)
} else if r.as_ref() == &other {
and(*l, other)
} else {
Type::And(Box::new(Type::And(l, r)), Box::new(other))
}
}
(Type::Obj, other) | (other, Type::Obj) => other,
(lhs, rhs) => Type::And(Box::new(lhs), Box::new(rhs)),
}
lhs & rhs
}
pub fn or(lhs: Type, rhs: Type) -> Type {
match (lhs, rhs) {
(Type::Or(l, r), other) | (other, Type::Or(l, r)) => {
if l.as_ref() == &other {
or(*r, other)
} else if r.as_ref() == &other {
or(*l, other)
} else {
Type::Or(Box::new(Type::Or(l, r)), Box::new(other))
}
}
(Type::Never, other) | (other, Type::Never) => other,
(lhs, rhs) => Type::Or(Box::new(lhs), Box::new(rhs)),
}
lhs | rhs
}
pub fn ors(tys: impl IntoIterator<Item = Type>) -> Type {

View file

@ -774,7 +774,12 @@ impl Free<Type> {
let placeholder = placeholder.unwrap_or(&Type::Failure);
let is_recursive = self.is_recursive();
if is_recursive {
self.undoable_link(placeholder);
let target = Type::FreeVar(self.clone());
let placeholder_ = placeholder
.clone()
.eliminate_subsup(&target)
.eliminate_and_or_recursion(&target);
self.undoable_link(&placeholder_);
}
let res = f();
if is_recursive {
@ -884,7 +889,9 @@ impl Free<TyParam> {
let placeholder = placeholder.unwrap_or(&TyParam::Failure);
let is_recursive = self.is_recursive();
if is_recursive {
self.undoable_link(placeholder);
let target = TyParam::FreeVar(self.clone());
let placeholder_ = placeholder.clone().eliminate_recursion(&target);
self.undoable_link(&placeholder_);
}
let res = f();
if is_recursive {

File diff suppressed because it is too large Load diff

View file

@ -656,7 +656,8 @@ impl Predicate {
pub fn qvars(&self) -> Set<(Str, Constraint)> {
match self {
Self::Value(_) | Self::Const(_) | Self::Failure => set! {},
Self::Const(_) | Self::Failure => set! {},
Self::Value(val) => val.qvars(),
Self::Call { receiver, args, .. } => {
let mut set = receiver.qvars();
for arg in args {
@ -680,9 +681,35 @@ impl Predicate {
}
}
pub fn has_type_satisfies(&self, f: impl Fn(&Type) -> bool + Copy) -> bool {
match self {
Self::Const(_) | Self::Failure => false,
Self::Value(val) => val.has_type_satisfies(f),
Self::Call { receiver, args, .. } => {
receiver.has_type_satisfies(f) || args.iter().any(|a| a.has_type_satisfies(f))
}
Self::Attr { receiver, .. } => receiver.has_type_satisfies(f),
Self::Equal { rhs, .. }
| Self::GreaterEqual { rhs, .. }
| Self::LessEqual { rhs, .. }
| Self::NotEqual { rhs, .. } => rhs.has_type_satisfies(f),
Self::GeneralEqual { lhs, rhs }
| Self::GeneralLessEqual { lhs, rhs }
| Self::GeneralGreaterEqual { lhs, rhs }
| Self::GeneralNotEqual { lhs, rhs } => {
lhs.has_type_satisfies(f) || rhs.has_type_satisfies(f)
}
Self::Or(lhs, rhs) | Self::And(lhs, rhs) => {
lhs.has_type_satisfies(f) || rhs.has_type_satisfies(f)
}
Self::Not(pred) => pred.has_type_satisfies(f),
}
}
pub fn has_qvar(&self) -> bool {
match self {
Self::Value(_) | Self::Const(_) | Self::Failure => false,
Self::Const(_) | Self::Failure => false,
Self::Value(val) => val.has_qvar(),
Self::Call { receiver, args, .. } => {
receiver.has_qvar() || args.iter().any(|a| a.has_qvar())
}
@ -702,7 +729,8 @@ impl Predicate {
pub fn has_unbound_var(&self) -> bool {
match self {
Self::Value(_) | Self::Const(_) | Self::Failure => false,
Self::Const(_) | Self::Failure => false,
Self::Value(val) => val.has_unbound_var(),
Self::Call { receiver, args, .. } => {
receiver.has_unbound_var() || args.iter().any(|a| a.has_unbound_var())
}
@ -724,7 +752,8 @@ impl Predicate {
pub fn has_undoable_linked_var(&self) -> bool {
match self {
Self::Value(_) | Self::Const(_) | Self::Failure => false,
Self::Const(_) | Self::Failure => false,
Self::Value(val) => val.has_undoable_linked_var(),
Self::Call { receiver, args, .. } => {
receiver.has_undoable_linked_var()
|| args.iter().any(|a| a.has_undoable_linked_var())

View file

@ -1268,21 +1268,21 @@ impl TyParam {
pub fn has_type_satisfies(&self, f: impl Fn(&Type) -> bool + Copy) -> bool {
match self {
Self::FreeVar(fv) if fv.is_linked() => fv.crack().has_type_satisfies(f),
Self::FreeVar(fv) => fv.get_type().map_or(false, |t| t.has_type_satisfies(f)),
Self::Type(t) => t.has_type_satisfies(f),
Self::Erased(t) => t.has_type_satisfies(f),
Self::FreeVar(fv) => fv.get_type().map_or(false, |t| f(&t)),
Self::Type(t) => f(t),
Self::Erased(t) => f(t),
Self::Proj { obj, .. } => obj.has_type_satisfies(f),
Self::ProjCall { obj, args, .. } => {
obj.has_type_satisfies(f) || args.iter().any(|t| t.has_type_satisfies(f))
obj.has_type_satisfies(f) || args.iter().any(|tp| tp.has_type_satisfies(f))
}
Self::List(ts) | Self::Tuple(ts) => ts.iter().any(|t| t.has_type_satisfies(f)),
Self::List(ts) | Self::Tuple(ts) => ts.iter().any(|tp| tp.has_type_satisfies(f)),
Self::UnsizedList(elem) => elem.has_type_satisfies(f),
Self::Set(ts) => ts.iter().any(|t| t.has_type_satisfies(f)),
Self::Set(ts) => ts.iter().any(|tp| tp.has_type_satisfies(f)),
Self::Dict(ts) => ts
.iter()
.any(|(k, v)| k.has_type_satisfies(f) || v.has_type_satisfies(f)),
Self::Record(rec) | Self::DataClass { fields: rec, .. } => {
rec.iter().any(|(_, tp)| tp.has_type_satisfies(f))
rec.values().any(|tp| tp.has_type_satisfies(f))
}
Self::Lambda(lambda) => lambda.body.iter().any(|tp| tp.has_type_satisfies(f)),
Self::UnaryOp { val, .. } => val.has_type_satisfies(f),

View file

@ -2080,7 +2080,7 @@ impl ValueObj {
pub fn has_type_satisfies(&self, f: impl Fn(&Type) -> bool + Copy) -> bool {
match self {
Self::Type(t) => t.typ().has_type_satisfies(f),
Self::Type(t) => f(t.typ()),
Self::List(ts) | Self::Tuple(ts) => ts.iter().any(|t| t.has_type_satisfies(f)),
Self::UnsizedList(elem) => elem.has_type_satisfies(f),
Self::Set(ts) => ts.iter().any(|t| t.has_type_satisfies(f)),