mirror of
https://github.com/erg-lang/erg.git
synced 2025-08-03 18:29:00 +00:00
fix: Type::{And, Or}(Set<Type>)
This commit is contained in:
parent
82bc710827
commit
b0c31370c5
14 changed files with 661 additions and 466 deletions
|
@ -754,9 +754,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
|
||||
|
@ -808,41 +806,20 @@ 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
|
||||
(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) {
|
||||
return true;
|
||||
}
|
||||
if l_2.is_intersection_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))
|
||||
}
|
||||
(lhs, Or(ors)) => ors.iter().all(|or| self.supertype_of(lhs, or)),
|
||||
(And(l), And(r)) => r.iter().any(|r| l.iter().all(|l| self.supertype_of(l, r))),
|
||||
// (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),
|
||||
|
@ -914,18 +891,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
|
||||
|
@ -1408,6 +1385,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 {
|
||||
|
@ -1470,10 +1449,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);
|
||||
|
@ -1657,6 +1635,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();
|
||||
|
@ -1687,12 +1671,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);
|
||||
}
|
||||
|
@ -1827,21 +1808,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);
|
||||
|
@ -1983,8 +1964,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()),
|
||||
}
|
||||
}
|
||||
|
@ -2002,7 +1987,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(),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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}のサブタイプではありません"),
|
||||
|
|
|
@ -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(<i.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()
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -155,17 +155,38 @@ 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)
|
||||
(Or(l), Or(r)) | (And(l), And(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(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)
|
||||
(lhs, Or(tys)) | (lhs, And(tys)) => {
|
||||
for ty in tys.iter() {
|
||||
self.occur(lhs, ty)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
(Or(tys), rhs) | (And(tys), rhs) => {
|
||||
for ty in tys.iter() {
|
||||
self.occur(ty, rhs)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
_ => Ok(()),
|
||||
}
|
||||
|
@ -266,13 +287,17 @@ 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, Or(tys)) | (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)
|
||||
(Or(tys), rhs) | (And(tys), rhs) => {
|
||||
for ty in tys.iter() {
|
||||
self.occur_inner(ty, rhs)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
_ => Ok(()),
|
||||
}
|
||||
|
@ -1186,35 +1211,42 @@ impl<'c, 'l, 'u, L: Locational> Unifier<'c, 'l, 'u, L> {
|
|||
// (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)
|
||||
(Or(ltys), Or(rtys)) | (And(ltys), And(rtys)) => {
|
||||
let lvars = ltys.to_vec();
|
||||
let mut rvars = rtys.to_vec();
|
||||
for _ in 0..rvars.len() {
|
||||
if lvars
|
||||
.iter()
|
||||
.zip(rvars.iter())
|
||||
.all(|(l, r)| self.ctx.subtype_of(l, r))
|
||||
{
|
||||
(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)?;
|
||||
for (l, r) in ltys.iter().zip(rtys.iter()) {
|
||||
self.sub_unify(l, r)?;
|
||||
}
|
||||
break;
|
||||
}
|
||||
rvars.rotate_left(1);
|
||||
}
|
||||
return Err(TyCheckErrors::from(TyCheckError::type_mismatch_error(
|
||||
self.ctx.cfg.input.clone(),
|
||||
line!() as usize,
|
||||
self.loc.loc(),
|
||||
self.ctx.caused_by(),
|
||||
self.param_name.as_ref().unwrap_or(&Str::ever("_")),
|
||||
None,
|
||||
maybe_sup,
|
||||
maybe_sub,
|
||||
self.ctx.get_candidates(maybe_sub),
|
||||
self.ctx.get_simple_type_mismatch_hint(maybe_sup, maybe_sub),
|
||||
)));
|
||||
}
|
||||
// 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) => {}
|
||||
|
@ -1578,30 +1610,36 @@ 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) {
|
||||
self.sub_unify(ty, maybe_sup)?;
|
||||
break;
|
||||
}
|
||||
}
|
||||
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) {
|
||||
self.sub_unify(maybe_sub, ty)?;
|
||||
break;
|
||||
}
|
||||
}
|
||||
self.sub_unify(maybe_sub, tys.iter().next().unwrap())?;
|
||||
}
|
||||
(Ref(sub), Ref(sup)) => {
|
||||
self.sub_unify(sub, sup)?;
|
||||
|
@ -1843,27 +1881,27 @@ 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);
|
||||
(Or(tys), other) | (other, Or(tys)) => {
|
||||
for ty in tys {
|
||||
if let Some(t) = self.unify(ty, other) {
|
||||
return self.unify(&t, ty);
|
||||
}
|
||||
}
|
||||
return None;
|
||||
}
|
||||
(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()),
|
||||
(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());
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue