fix: Type::{And, Or}(Set<Type>)

This commit is contained in:
Shunsuke Shibayama 2024-09-14 21:20:05 +09:00
parent 82bc710827
commit b0c31370c5
14 changed files with 661 additions and 466 deletions

View file

@ -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(),
}
}

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

@ -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

@ -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());
}