mirror of
https://github.com/erg-lang/erg.git
synced 2025-08-04 18:58:30 +00:00
Merge pull request #521 from erg-lang/perf_or_type
Change And/Or-type structures
This commit is contained in:
commit
040811744e
28 changed files with 1036 additions and 765 deletions
|
@ -42,24 +42,30 @@ fn comp_item_kind(t: &Type, muty: Mutability) -> CompletionItemKind {
|
|||
Type::Subr(_) | Type::Quantified(_) => CompletionItemKind::FUNCTION,
|
||||
Type::ClassType => CompletionItemKind::CLASS,
|
||||
Type::TraitType => CompletionItemKind::INTERFACE,
|
||||
Type::Or(l, r) => {
|
||||
let l = comp_item_kind(l, muty);
|
||||
let r = comp_item_kind(r, muty);
|
||||
if l == r {
|
||||
l
|
||||
Type::Or(tys) => {
|
||||
let fst = comp_item_kind(tys.iter().next().unwrap(), muty);
|
||||
if tys
|
||||
.iter()
|
||||
.map(|t| comp_item_kind(t, muty))
|
||||
.all(|k| k == fst)
|
||||
{
|
||||
fst
|
||||
} else if muty.is_const() {
|
||||
CompletionItemKind::CONSTANT
|
||||
} else {
|
||||
CompletionItemKind::VARIABLE
|
||||
}
|
||||
}
|
||||
Type::And(l, r) => {
|
||||
let l = comp_item_kind(l, muty);
|
||||
let r = comp_item_kind(r, muty);
|
||||
if l == CompletionItemKind::VARIABLE {
|
||||
r
|
||||
Type::And(tys) => {
|
||||
for k in tys.iter().map(|t| comp_item_kind(t, muty)) {
|
||||
if k != CompletionItemKind::VARIABLE {
|
||||
return k;
|
||||
}
|
||||
}
|
||||
if muty.is_const() {
|
||||
CompletionItemKind::CONSTANT
|
||||
} else {
|
||||
l
|
||||
CompletionItemKind::VARIABLE
|
||||
}
|
||||
}
|
||||
Type::Refinement(r) => comp_item_kind(&r.t, muty),
|
||||
|
|
|
@ -129,6 +129,18 @@ impl<K, V> Dict<K, V> {
|
|||
}
|
||||
}
|
||||
|
||||
/// ```
|
||||
/// # use erg_common::dict;
|
||||
/// # use erg_common::dict::Dict;
|
||||
/// let mut dict = Dict::with_capacity(3);
|
||||
/// assert_eq!(dict.capacity(), 3);
|
||||
/// dict.insert("a", 1);
|
||||
/// assert_eq!(dict.capacity(), 3);
|
||||
/// dict.insert("b", 2);
|
||||
/// dict.insert("c", 3);
|
||||
/// dict.insert("d", 4);
|
||||
/// assert_ne!(dict.capacity(), 3);
|
||||
/// ```
|
||||
pub fn with_capacity(capacity: usize) -> Self {
|
||||
Self {
|
||||
dict: FxHashMap::with_capacity_and_hasher(capacity, Default::default()),
|
||||
|
|
|
@ -627,6 +627,17 @@ impl RecursionCounter {
|
|||
|
||||
#[macro_export]
|
||||
macro_rules! set_recursion_limit {
|
||||
(panic, $msg:expr, $limit:expr) => {
|
||||
use std::sync::atomic::AtomicU32;
|
||||
|
||||
static COUNTER: AtomicU32 = AtomicU32::new($limit);
|
||||
|
||||
let counter = $crate::macros::RecursionCounter::new(&COUNTER);
|
||||
if counter.limit_reached() {
|
||||
$crate::log!(err "Recursion limit reached");
|
||||
panic!($msg);
|
||||
}
|
||||
};
|
||||
($returns:expr, $limit:expr) => {
|
||||
use std::sync::atomic::AtomicU32;
|
||||
|
||||
|
|
|
@ -382,6 +382,20 @@ impl<T: Hash + Eq + Clone> Set<T> {
|
|||
self.insert(other);
|
||||
self
|
||||
}
|
||||
|
||||
/// ```
|
||||
/// # use erg_common::set;
|
||||
/// assert_eq!(set!{1, 2}.product(&set!{3, 4}), set!{(&1, &3), (&1, &4), (&2, &3), (&2, &4)});
|
||||
/// ```
|
||||
pub fn product<'l, 'r, U: Hash + Eq>(&'l self, other: &'r Set<U>) -> Set<(&'l T, &'r U)> {
|
||||
let mut res = set! {};
|
||||
for x in self.iter() {
|
||||
for y in other.iter() {
|
||||
res.insert((x, y));
|
||||
}
|
||||
}
|
||||
res
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Hash + Ord> Set<T> {
|
||||
|
|
|
@ -1407,6 +1407,8 @@ impl<T: Immutable + ?Sized> Immutable for &T {}
|
|||
impl<T: Immutable> Immutable for Option<T> {}
|
||||
impl<T: Immutable> Immutable for Vec<T> {}
|
||||
impl<T: Immutable> Immutable for [T] {}
|
||||
impl<T: Immutable, U: Immutable> Immutable for (T, U) {}
|
||||
impl<T: Immutable, U: Immutable, V: Immutable> Immutable for (T, U, V) {}
|
||||
impl<T: Immutable + ?Sized> Immutable for Box<T> {}
|
||||
impl<T: Immutable + ?Sized> Immutable for std::rc::Rc<T> {}
|
||||
impl<T: Immutable + ?Sized> Immutable for std::sync::Arc<T> {}
|
||||
|
|
|
@ -18,6 +18,16 @@ impl<T: fmt::Display, E: fmt::Display> fmt::Display for Triple<T, E> {
|
|||
}
|
||||
|
||||
impl<T, E> Triple<T, E> {
|
||||
pub const fn is_ok(&self) -> bool {
|
||||
matches!(self, Triple::Ok(_))
|
||||
}
|
||||
pub const fn is_err(&self) -> bool {
|
||||
matches!(self, Triple::Err(_))
|
||||
}
|
||||
pub const fn is_none(&self) -> bool {
|
||||
matches!(self, Triple::None)
|
||||
}
|
||||
|
||||
pub fn none_then(self, err: E) -> Result<T, E> {
|
||||
match self {
|
||||
Triple::None => Err(err),
|
||||
|
|
|
@ -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(),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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}のサブタイプではありません"),
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)));
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
@ -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())
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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)),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue