Merge pull request #518 from erg-lang/fix_inf_rec

Fix infinite recursion bugs
This commit is contained in:
Shunsuke Shibayama 2024-09-01 18:23:58 +09:00 committed by GitHub
commit b5092e7890
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
17 changed files with 1886 additions and 535 deletions

View file

@ -13,7 +13,7 @@ use std::time::{Duration, SystemTime};
use erg_common::config::ErgMode;
use erg_common::config::ErgConfig;
use erg_common::consts::{DEBUG_MODE, ELS, ERG_MODE};
use erg_common::consts::{ELS, ERG_MODE};
use erg_common::debug_power_assert;
use erg_common::dict::Dict;
use erg_common::env::is_std_decl_path;
@ -155,6 +155,18 @@ pub struct ResolveError {
pub type ResolveResult<T> = Result<T, Vec<ResolveError>>;
#[derive(Debug, Clone)]
pub struct ASTEntry {
name: Str,
ast: AST,
}
impl ASTEntry {
pub const fn new(name: Str, ast: AST) -> Self {
Self { name, ast }
}
}
/// Resolve dependencies and build a package.
/// This object should be a singleton.
///
@ -171,7 +183,7 @@ pub struct GenericPackageBuilder<
cyclic: Vec<NormalizedPathBuf>,
// key: inlined module, value: inliner module (child)
inlines: Dict<NormalizedPathBuf, NormalizedPathBuf>,
asts: Dict<NormalizedPathBuf, (Str, AST)>,
asts: Dict<NormalizedPathBuf, ASTEntry>,
parse_errors: ErrorArtifact,
_parser: PhantomData<fn() -> ASTBuilder>,
}
@ -725,9 +737,10 @@ impl<ASTBuilder: ASTBuildable, HIRBuilder: Buildable>
|| self.asts.contains_key(&root_import_path)
{
// pass
} else if let Ok(mut ast) = self.parse(&root_import_path) {
} else if let Some(mut ast) = self.parse(&root_import_path) {
let _ = self.resolve(&mut ast, &root_import_cfg);
let prev = self.asts.insert(root_import_path, (__name__.clone(), ast));
let entry = ASTEntry::new(__name__.clone(), ast);
let prev = self.asts.insert(root_import_path, entry);
debug_assert!(prev.is_none());
}
}
@ -746,7 +759,7 @@ impl<ASTBuilder: ASTBuildable, HIRBuilder: Buildable>
{
return Ok(());
}
let Ok(mut ast) = self.parse(&import_path) else {
let Some(mut ast) = self.parse(&import_path) else {
return Ok(());
};
if let Err(mut errs) = self.resolve(&mut ast, &import_cfg) {
@ -764,14 +777,16 @@ impl<ASTBuilder: ASTBuildable, HIRBuilder: Buildable>
return Err(errs);
}
}
let prev = self.asts.insert(import_path, (__name__.clone(), ast));
let entry = ASTEntry::new(__name__.clone(), ast);
let prev = self.asts.insert(import_path, entry);
debug_assert!(prev.is_none());
Ok(())
}
fn parse(&mut self, import_path: &NormalizedPathBuf) -> Result<AST, ()> {
/// Parse the file and build the AST. It may return `Some()` even if there are errors.
fn parse(&mut self, import_path: &NormalizedPathBuf) -> Option<AST> {
let Ok(src) = import_path.try_read() else {
return Err(());
return None;
};
let cfg = self.cfg.inherit(import_path.to_path_buf());
let result = if import_path.extension() == Some(OsStr::new("er")) {
@ -786,7 +801,7 @@ impl<ASTBuilder: ASTBuildable, HIRBuilder: Buildable>
self.parse_errors
.warns
.extend(CompileErrors::from(art.warns));
Ok(art.ast)
Some(art.ast)
}
Err(iart) => {
self.parse_errors
@ -795,11 +810,7 @@ impl<ASTBuilder: ASTBuildable, HIRBuilder: Buildable>
self.parse_errors
.warns
.extend(CompileErrors::from(iart.warns));
if let Some(ast) = iart.ast {
Ok(ast)
} else {
Err(())
}
iart.ast
}
}
}
@ -821,8 +832,8 @@ impl<ASTBuilder: ASTBuildable, HIRBuilder: Buildable>
while let Some(ancestor) = ancestors.pop() {
if graph.ancestors(&ancestor).is_empty() {
graph.remove(&ancestor);
if let Some((__name__, ancestor_ast)) = self.asts.remove(&ancestor) {
self.start_analysis_process(ancestor_ast, __name__, ancestor);
if let Some(entry) = self.asts.remove(&ancestor) {
self.start_analysis_process(entry.ast, entry.name, ancestor);
} else {
self.build_inlined_module(&ancestor, graph);
}
@ -835,10 +846,12 @@ impl<ASTBuilder: ASTBuildable, HIRBuilder: Buildable>
fn build_inlined_module(&mut self, path: &NormalizedPathBuf, graph: &mut ModuleGraph) {
if self.shared.get_module(path).is_some() {
// do nothing
} else if self.shared.promises.is_registered(path) {
self.shared.promises.wait_until_finished(path);
} else if let Some(inliner) = self.inlines.get(path).cloned() {
self.build_deps_and_module(&inliner, graph);
} else if DEBUG_MODE {
todo!("{path} is not found in self.inlines and self.asts");
} else {
unreachable!("{path} is not found in self.inlines and self.asts");
}
}

View file

@ -7,7 +7,7 @@ use erg_common::dict::Dict;
use erg_common::set::Set;
use erg_common::style::colors::DEBUG_ERROR;
use erg_common::traits::StructuralEq;
use erg_common::{assume_unreachable, log};
use erg_common::{assume_unreachable, log, set_recursion_limit};
use erg_common::{Str, Triple};
use crate::context::eval::UndoableLinkedList;
@ -126,6 +126,7 @@ impl Context {
/// lhs :> rhs ?
pub(crate) fn supertype_of(&self, lhs: &Type, rhs: &Type) -> bool {
set_recursion_limit!(false, 128);
let res = match Self::cheap_supertype_of(lhs, rhs) {
(Absolutely, judge) => judge,
(Maybe, judge) => {
@ -1072,6 +1073,23 @@ impl Context {
(TyParam::UnsizedList(sup), TyParam::UnsizedList(sub)) => {
self.supertype_of_tp(sup, sub, variance)
}
(
TyParam::DataClass { name, fields },
TyParam::DataClass {
name: sub_name,
fields: sub_fields,
},
) => {
if name != sub_name || fields.len() != sub_fields.len() {
return false;
}
for (sup_tp, sub_tp) in fields.values().zip(sub_fields.values()) {
if !self.supertype_of_tp(sup_tp, sub_tp, variance) {
return false;
}
}
true
}
(TyParam::Type(sup), TyParam::Type(sub)) => match variance {
Variance::Contravariant => self.subtype_of(sup, sub),
Variance::Covariant => self.supertype_of(sup, sub),
@ -1465,6 +1483,7 @@ impl Context {
t
}
(t, Type::Never) | (Type::Never, t) => t.clone(),
// REVIEW: variance?
// List({1, 2}, 2), List({3, 4}, 2) ==> List({1, 2, 3, 4}, 2)
(
Type::Poly {
@ -1566,19 +1585,27 @@ impl Context {
/// ```
fn simple_union(&self, lhs: &Type, rhs: &Type) -> Type {
if let Ok(free) = <&FreeTyVar>::try_from(lhs) {
if !rhs.is_totally_unbound() && self.supertype_of(&free.get_sub().unwrap_or(Never), rhs)
free.dummy_link();
let res = if !rhs.is_totally_unbound()
&& self.supertype_of(&free.get_sub().unwrap_or(Never), rhs)
{
lhs.clone()
} else {
or(lhs.clone(), rhs.clone())
}
};
free.undo();
res
} else if let Ok(free) = <&FreeTyVar>::try_from(rhs) {
if !lhs.is_totally_unbound() && self.supertype_of(&free.get_sub().unwrap_or(Never), lhs)
free.dummy_link();
let res = if !lhs.is_totally_unbound()
&& self.supertype_of(&free.get_sub().unwrap_or(Never), lhs)
{
rhs.clone()
} else {
or(lhs.clone(), rhs.clone())
}
};
free.undo();
res
} else {
if lhs.is_totally_unbound() || rhs.is_totally_unbound() {
return or(lhs.clone(), rhs.clone());
@ -1677,6 +1704,29 @@ impl Context {
}
t
}
// REVIEW: variance?
// Array({1, 2, 3}) and Array({2, 3, 4}) == Array({2, 3})
(
Poly {
name: ln,
params: lps,
},
Poly {
name: rn,
params: rps,
},
) if ln == rn && self.is_class(lhs) => {
debug_assert_eq!(lps.len(), rps.len());
let mut new_params = vec![];
for (lp, rp) in lps.iter().zip(rps.iter()) {
if let Some(intersec) = self.intersection_tp(lp, rp) {
new_params.push(intersec);
} else {
return self.simple_intersection(lhs, rhs);
}
}
poly(ln.clone(), new_params)
}
(other, Refinement(refine)) | (Refinement(refine), other) => {
let other = other.clone().into_refinement();
let intersec = self.intersection_refinement(&other, refine);
@ -1689,6 +1739,50 @@ impl Context {
}
}
pub(crate) fn intersection_tp(&self, lhs: &TyParam, rhs: &TyParam) -> Option<TyParam> {
match (lhs, rhs) {
(TyParam::Value(ValueObj::Type(l)), TyParam::Value(ValueObj::Type(r))) => {
Some(TyParam::t(self.intersection(l.typ(), r.typ())))
}
(TyParam::Value(ValueObj::Type(l)), TyParam::Type(r)) => {
Some(TyParam::t(self.intersection(l.typ(), r)))
}
(TyParam::Type(l), TyParam::Value(ValueObj::Type(r))) => {
Some(TyParam::t(self.intersection(l, r.typ())))
}
(TyParam::Type(l), TyParam::Type(r)) => Some(TyParam::t(self.intersection(l, r))),
(TyParam::List(l), TyParam::List(r)) => {
let mut tps = vec![];
for (l, r) in l.iter().zip(r.iter()) {
if let Some(tp) = self.intersection_tp(l, r) {
tps.push(tp);
} else {
return None;
}
}
Some(TyParam::List(tps))
}
(fv @ TyParam::FreeVar(f), other) | (other, fv @ TyParam::FreeVar(f))
if f.is_unbound() =>
{
let fv_t = self.get_tp_t(fv).ok()?.derefine();
let other_t = self.get_tp_t(other).ok()?.derefine();
if self.same_type_of(&fv_t, &other_t) {
Some(other.clone())
} else {
None
}
}
(_, _) => {
if self.eq_tp(lhs, rhs) {
Some(lhs.clone())
} else {
None
}
}
}
}
/// ```erg
/// intersection_add(Nat and ?T(:> NoneType), Int) == Nat and ?T
/// intersection_add(Int and ?T(:> NoneType), Nat) == Nat and ?T

View file

@ -9,7 +9,7 @@ use erg_common::log;
use erg_common::set::Set;
use erg_common::shared::Shared;
use erg_common::traits::{Locational, Stream};
use erg_common::{dict, fmt_vec, fn_name, option_enum_unwrap, set, Triple};
use erg_common::{dict, fmt_vec, fn_name, option_enum_unwrap, set, set_recursion_limit, Triple};
use erg_common::{ArcArray, Str};
use OpKind::*;
@ -37,7 +37,7 @@ use crate::error::{EvalError, EvalErrors, EvalResult, Failable, SingleEvalResult
use crate::varinfo::{AbsLocation, VarInfo};
use super::instantiate::TyVarCache;
use Type::{Failure, Never, Subr};
use Type::{Failure, Never};
macro_rules! feature_error {
($ctx: expr, $loc: expr, $name: expr) => {
@ -406,11 +406,17 @@ impl<'c> Substituter<'c> {
/// -> Iterable(Int)
/// ```
pub(crate) fn substitute_self(qt: &Type, subtype: &Type, ctx: &'c Context) -> Option<Self> {
#[allow(clippy::blocks_in_conditions)]
for t in qt.contained_ts() {
if t.is_qvar()
&& &t.qual_name()[..] == "Self"
&& t.get_super()
.is_some_and(|sup| ctx.supertype_of(&sup, subtype))
&& t.get_super().is_some_and(|sup| {
let fv = t.as_free().unwrap();
fv.dummy_link();
let res = ctx.supertype_of(&sup, subtype);
fv.undo();
res
})
{
let mut _self = Self::new(ctx);
t.undoable_link(subtype, &_self.undoable_linked);
@ -633,7 +639,7 @@ impl Context {
Ok(tp) => (tp, EvalErrors::empty()),
Err((tp, errs)) => (tp, errs),
};
match ValueObj::try_from(tp) {
match self.convert_tp_into_value(tp) {
Ok(val) => {
if errs.is_empty() {
Ok(val)
@ -641,7 +647,7 @@ impl Context {
Err((val, errs))
}
}
Err(()) => {
Err(_) => {
if errs.is_empty() {
Err((
ValueObj::Failure,
@ -1748,21 +1754,38 @@ impl Context {
fn eval_unary_val(&self, op: OpKind, val: ValueObj) -> EvalResult<ValueObj> {
match op {
Pos => Err(EvalErrors::from(EvalError::unreachable(
self.cfg.input.clone(),
fn_name!(),
line!(),
))),
Neg => Err(EvalErrors::from(EvalError::unreachable(
self.cfg.input.clone(),
fn_name!(),
line!(),
))),
Invert => Err(EvalErrors::from(EvalError::unreachable(
self.cfg.input.clone(),
fn_name!(),
line!(),
))),
Pos => match val {
ValueObj::Nat(_)
| ValueObj::Int(_)
| ValueObj::Float(_)
| ValueObj::Inf
| ValueObj::NegInf => Ok(val),
_ => Err(EvalErrors::from(EvalError::unreachable(
self.cfg.input.clone(),
fn_name!(),
line!(),
))),
},
Neg => match val {
ValueObj::Nat(n) => Ok(ValueObj::Int(-(n as i32))),
ValueObj::Int(i) => Ok(ValueObj::Int(-i)),
ValueObj::Float(f) => Ok(ValueObj::Float(-f)),
ValueObj::Inf => Ok(ValueObj::NegInf),
ValueObj::NegInf => Ok(ValueObj::Inf),
_ => Err(EvalErrors::from(EvalError::unreachable(
self.cfg.input.clone(),
fn_name!(),
line!(),
))),
},
Invert => match val {
ValueObj::Bool(b) => Ok(ValueObj::Bool(!b)),
_ => Err(EvalErrors::from(EvalError::unreachable(
self.cfg.input.clone(),
fn_name!(),
line!(),
))),
},
Not => match val {
ValueObj::Bool(b) => Ok(ValueObj::Bool(!b)),
ValueObj::Type(lhs) => Ok(self.eval_not_type(lhs)),
@ -1815,16 +1838,13 @@ impl Context {
pub(crate) fn eval_tp(&self, p: TyParam) -> Failable<TyParam> {
let mut errs = EvalErrors::empty();
let tp = match p {
TyParam::FreeVar(fv) if fv.is_linked() => {
let tp = fv.crack().clone();
match self.eval_tp(tp) {
Ok(tp) => tp,
Err((tp, es)) => {
errs.extend(es);
tp
}
TyParam::FreeVar(fv) if fv.is_linked() => match self.eval_tp(fv.unwrap_linked()) {
Ok(tp) => tp,
Err((tp, es)) => {
errs.extend(es);
tp
}
}
},
TyParam::FreeVar(_) => p,
TyParam::Mono(name) => match self
.rec_get_const_obj(&name)
@ -1968,15 +1988,17 @@ impl Context {
TyParam::erased(t)
}
},
TyParam::Value(ValueObj::Type(mut t)) => {
match t.try_map_t(|t| self.eval_t_params(t, self.level, &())) {
Ok(_) => {}
TyParam::Value(val) => {
match val
.clone()
.try_map_t(&mut |t| self.eval_t_params(t, self.level, &()))
{
Ok(val) => TyParam::Value(val),
Err((_t, es)) => {
errs.extend(es);
*t.typ_mut() = _t;
TyParam::Value(val)
}
}
TyParam::Value(ValueObj::Type(t))
}
TyParam::ProjCall { obj, attr, args } => {
match self.eval_proj_call(*obj, attr, args, &()) {
@ -1994,7 +2016,6 @@ impl Context {
return Err((TyParam::Failure, errs));
}
},
TyParam::Value(_) => p.clone(),
other => {
errs.push(EvalError::feature_error(
self.cfg.input.clone(),
@ -2046,11 +2067,11 @@ impl Context {
level: usize,
t_loc: &impl Locational,
) -> Failable<Type> {
set_recursion_limit!(Ok(Failure), 128);
let mut errs = EvalErrors::empty();
match substituted {
Type::FreeVar(fv) if fv.is_linked() => {
let t = fv.crack().clone();
self.eval_t_params(t, level, t_loc)
self.eval_t_params(fv.unwrap_linked(), level, t_loc)
}
Type::FreeVar(fv) if fv.constraint_is_sandwiched() => {
let (sub, sup) = fv.get_subsup().unwrap();
@ -2073,9 +2094,9 @@ impl Context {
*pt.typ_mut() = match self.eval_t_params(mem::take(pt.typ_mut()), level, t_loc)
{
Ok(t) => t,
Err((_, errs)) => {
// `mem::take` replaces the type with `Type::Failure`, so it can return as is
return Err((Subr(subr), errs));
Err((t, es)) => {
errs.extend(es);
t
}
};
}
@ -2083,19 +2104,28 @@ impl Context {
*var_args.typ_mut() =
match self.eval_t_params(mem::take(var_args.typ_mut()), level, t_loc) {
Ok(t) => t,
Err((_, errs)) => return Err((Subr(subr), errs)),
Err((t, es)) => {
errs.extend(es);
t
}
};
}
for pt in subr.default_params.iter_mut() {
*pt.typ_mut() = match self.eval_t_params(mem::take(pt.typ_mut()), level, t_loc)
{
Ok(t) => t,
Err((_, errs)) => return Err((Subr(subr), errs)),
Err((t, es)) => {
errs.extend(es);
t
}
};
if let Some(default) = pt.default_typ_mut() {
*default = match self.eval_t_params(mem::take(default), level, t_loc) {
Ok(t) => t,
Err((_, errs)) => return Err((Subr(subr), errs)),
Err((t, es)) => {
errs.extend(es);
t
}
};
}
}
@ -2103,31 +2133,37 @@ impl Context {
*kw_var_args.typ_mut() =
match self.eval_t_params(mem::take(kw_var_args.typ_mut()), level, t_loc) {
Ok(t) => t,
Err((_, errs)) => return Err((Subr(subr), errs)),
Err((t, es)) => {
errs.extend(es);
t
}
};
}
match self.eval_t_params(*subr.return_t, level, t_loc) {
Ok(return_t) => Ok(subr_t(
subr.kind,
subr.non_default_params,
subr.var_params.map(|v| *v),
subr.default_params,
subr.kw_var_params.map(|v| *v),
return_t,
)),
Err((_, errs)) => {
let subr = subr_t(
subr.kind,
subr.non_default_params,
subr.var_params.map(|v| *v),
subr.default_params,
subr.kw_var_params.map(|v| *v),
Failure,
);
Err((subr, errs))
let return_t = match self.eval_t_params(*subr.return_t, level, t_loc) {
Ok(return_t) => return_t,
Err((return_t, es)) => {
errs.extend(es);
return_t
}
};
let subr = subr_t(
subr.kind,
subr.non_default_params,
subr.var_params.map(|v| *v),
subr.default_params,
subr.kw_var_params.map(|v| *v),
return_t,
);
if errs.is_empty() {
Ok(subr)
} else {
Err((subr, errs))
}
}
Type::Quantified(quant) => match self.eval_t_params(*quant, level, t_loc) {
Ok(t) => Ok(t.quantify()),
Err((t, es)) => Err((t.quantify(), es)),
},
Type::Refinement(refine) => {
if refine.pred.variables().is_empty() {
let pred = match self.eval_pred(*refine.pred) {
@ -2157,27 +2193,33 @@ impl Context {
.map_err(|errs| (Failure, errs)),
Type::Ref(l) => match self.eval_t_params(*l, level, t_loc) {
Ok(t) => Ok(ref_(t)),
Err((_, errs)) => Err((ref_(Failure), errs)),
Err((t, errs)) => Err((ref_(t), errs)),
},
Type::RefMut { before, after } => {
let before = match self.eval_t_params(*before, level, t_loc) {
Ok(before) => before,
Err((_, errs)) => {
return Err((ref_mut(Failure, after.map(|x| *x)), errs));
Err((before, es)) => {
errs.extend(es);
before
}
};
let after = if let Some(after) = after {
let aft = match self.eval_t_params(*after, level, t_loc) {
Ok(aft) => aft,
Err((_, errs)) => {
return Err((ref_mut(before, Some(Failure)), errs));
Err((aft, es)) => {
errs.extend(es);
aft
}
};
Some(aft)
} else {
None
};
Ok(ref_mut(before, after))
if errs.is_empty() {
Ok(ref_mut(before, after))
} else {
Err((ref_mut(before, after), errs))
}
}
Type::Poly { name, mut params } => {
for p in params.iter_mut() {
@ -2208,82 +2250,115 @@ impl Context {
Type::And(l, r) => {
let l = match self.eval_t_params(*l, level, t_loc) {
Ok(l) => l,
Err((_, errs)) => {
return Err((Failure, errs));
Err((l, es)) => {
errs.extend(es);
l
}
};
let r = match self.eval_t_params(*r, level, t_loc) {
Ok(r) => r,
Err((_, errs)) => {
// L and Never == Never
return Err((Failure, errs));
Err((r, es)) => {
errs.extend(es);
r
}
};
Ok(self.intersection(&l, &r))
let intersec = 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((_, errs)) => {
return Err((Failure, errs));
Err((l, es)) => {
errs.extend(es);
l
}
};
let r = match self.eval_t_params(*r, level, t_loc) {
Ok(r) => r,
Err((_, errs)) => {
// L or Never == L
return Err((l, errs));
Err((r, es)) => {
errs.extend(es);
r
}
};
Ok(self.union(&l, &r))
let union = self.union(&l, &r);
if errs.is_empty() {
Ok(union)
} else {
Err((union, errs))
}
}
Type::Not(ty) => match self.eval_t_params(*ty, level, t_loc) {
Ok(ty) => Ok(self.complement(&ty)),
Err((_, errs)) => Err((Failure, errs)),
Err((ty, errs)) => Err((self.complement(&ty), errs)),
},
Type::Structural(typ) => match self.eval_t_params(*typ, level, t_loc) {
Ok(typ) => Ok(typ.structuralize()),
Err((t, errs)) => Err((t.structuralize(), errs)),
},
Type::Structural(typ) => {
let typ = self.eval_t_params(*typ, level, t_loc)?;
Ok(typ.structuralize())
}
Type::Record(rec) => {
let mut fields = dict! {};
for (name, tp) in rec.into_iter() {
fields.insert(name, self.eval_t_params(tp, level, t_loc)?);
for (name, ty) in rec.into_iter() {
match self.eval_t_params(ty, level, t_loc) {
Ok(ty) => {
fields.insert(name, ty);
}
Err((tp, es)) => {
fields.insert(name, tp);
errs.extend(es);
}
}
}
Ok(Type::Record(fields))
}
Type::NamedTuple(tuple) => {
let mut new_tuple = vec![];
for (name, tp) in tuple.into_iter() {
new_tuple.push((name, self.eval_t_params(tp, level, t_loc)?));
for (name, ty) in tuple.into_iter() {
match self.eval_t_params(ty, level, t_loc) {
Ok(ty) => new_tuple.push((name, ty)),
Err((ty, es)) => {
new_tuple.push((name, ty));
errs.extend(es);
}
}
}
Ok(Type::NamedTuple(new_tuple))
}
Type::Bounded { sub, sup } => {
let sub = match self.eval_t_params(*sub, level, t_loc) {
Ok(sub) => sub,
Err((_, errs)) => {
return Err((Failure, errs));
Err((sub, es)) => {
errs.extend(es);
sub
}
};
let sup = match self.eval_t_params(*sup, level, t_loc) {
Ok(sup) => sup,
Err((_, errs)) => {
return Err((Failure, errs));
Err((sup, es)) => {
errs.extend(es);
sup
}
};
Ok(bounded(sub, sup))
}
Type::Guard(grd) => {
let to = self.eval_t_params(*grd.to, level, t_loc)?;
Ok(guard(grd.namespace, grd.target, to))
if errs.is_empty() {
Ok(bounded(sub, sup))
} else {
Err((bounded(sub, sup), errs))
}
}
Type::Guard(grd) => match self.eval_t_params(*grd.to, level, t_loc) {
Ok(to) => Ok(guard(grd.namespace, grd.target, to)),
Err((to, es)) => Err((guard(grd.namespace, grd.target, to), es)),
},
other if other.is_monomorphic() => Ok(other),
other => feature_error!(self, t_loc.loc(), &format!("eval {other}"))
.map_err(|errs| (other, errs)),
}
}
/// This may do nothing (be careful with recursive calls).
/// lhs: mainly class
pub(crate) fn eval_proj(
&self,
@ -2476,6 +2551,7 @@ impl Context {
/// {x = Int; y = Int} => Type::Record({x = Int, y = Int})
/// {Str: Int} => Dict({Str: Int})
/// {1, 2} => {I: Int | I == 1 or I == 2 } (== {1, 2})
/// foo.T => Ok(foo.T) if T: Type else Err(foo.T)
/// ```
pub(crate) fn convert_tp_into_type(&self, tp: TyParam) -> Result<Type, TyParam> {
match tp {
@ -2544,22 +2620,46 @@ impl Context {
}
TyParam::Type(t) => Ok(t.as_ref().clone()),
TyParam::Mono(name) => Ok(Type::Mono(name)),
// REVIEW: should be checked?
TyParam::App { name, args } => Ok(Type::Poly { name, params: args }),
TyParam::Proj { obj, attr } => {
let lhs = self.convert_tp_into_type(*obj)?;
Ok(lhs.proj(attr))
TyParam::App { name, args } => {
if self.get_type_ctx(&name).is_none() {
Err(TyParam::App { name, args })
} else {
Ok(Type::Poly { name, params: args })
}
}
TyParam::Proj { obj, attr } => {
let lhs = self.convert_tp_into_type(*obj.clone())?;
let Some(ty_ctx) = self.get_nominal_type_ctx(&lhs) else {
return Err(TyParam::Proj { obj, attr });
};
if ty_ctx.rec_get_const_obj(&attr).is_some() {
Ok(lhs.proj(attr))
} else {
Err(TyParam::Proj { obj, attr })
}
}
TyParam::ProjCall { obj, attr, args } => {
let Some(ty_ctx) = self
.get_tp_t(&obj)
.ok()
.and_then(|t| self.get_nominal_type_ctx(&t))
else {
return Err(TyParam::ProjCall { obj, attr, args });
};
if ty_ctx.rec_get_const_obj(&attr).is_some() {
Ok(proj_call(*obj, attr, args))
} else {
Err(TyParam::ProjCall { obj, attr, args })
}
}
TyParam::ProjCall { obj, attr, args } => Ok(proj_call(*obj, attr, args)),
// TyParam::Erased(_t) => Ok(Type::Obj),
TyParam::Value(v) => self.convert_value_into_type(v).map_err(TyParam::Value),
TyParam::Erased(t) if t.is_type() => Ok(Type::Obj),
// TODO: Dict, Set
// TODO: DataClass, ...
other => Err(other),
}
}
#[allow(clippy::only_used_in_recursion)]
pub(crate) fn convert_tp_into_value(&self, tp: TyParam) -> Result<ValueObj, TyParam> {
match tp {
TyParam::FreeVar(fv) if fv.is_linked() => {
@ -2595,6 +2695,16 @@ impl Context {
}
Ok(ValueObj::Record(new))
}
TyParam::Dict(tps) => {
let mut vals = dict! {};
for (k, v) in tps {
vals.insert(
self.convert_tp_into_value(k)?,
self.convert_tp_into_value(v)?,
);
}
Ok(ValueObj::Dict(vals))
}
TyParam::Set(set) => {
let mut new = set! {};
for elem in set {
@ -2657,10 +2767,12 @@ impl Context {
}
}
// FIXME: Failable<Type>
pub(crate) fn convert_value_into_type(&self, val: ValueObj) -> Result<Type, ValueObj> {
match val {
ValueObj::Failure => Ok(Type::Failure),
ValueObj::Ellipsis => Ok(Type::Ellipsis),
ValueObj::NotImplemented => Ok(Type::NotImplementedType),
ValueObj::Type(t) => Ok(t.into_typ()),
ValueObj::Record(rec) => {
let mut fields = dict! {};
@ -2812,6 +2924,30 @@ impl Context {
}
Ok(new_dict)
}
Type::Proj { lhs, rhs } => {
let old = proj(*lhs.clone(), rhs.clone());
let eval = self.eval_proj(*lhs, rhs, self.level, &()).map_err(|_| ())?;
if eval != old {
self.convert_type_to_dict_type(eval)
} else {
Err(())
}
}
Type::ProjCall {
lhs,
attr_name,
args,
} => {
let old = proj_call(*lhs.clone(), attr_name.clone(), args.clone());
let eval = self
.eval_proj_call_t(*lhs, attr_name, args, self.level, &())
.map_err(|_| ())?;
if eval != old {
self.convert_type_to_dict_type(eval)
} else {
Err(())
}
}
_ => Err(()),
}
}
@ -2832,6 +2968,31 @@ impl Context {
}
Ok(tys)
}
Type::NamedTuple(tuple) => Ok(tuple.into_iter().map(|(_, ty)| ty).collect()),
Type::Proj { lhs, rhs } => {
let old = proj(*lhs.clone(), rhs.clone());
let eval = self.eval_proj(*lhs, rhs, self.level, &()).map_err(|_| ())?;
if eval != old {
self.convert_type_to_tuple_type(eval)
} else {
Err(())
}
}
Type::ProjCall {
lhs,
attr_name,
args,
} => {
let old = proj_call(*lhs.clone(), attr_name.clone(), args.clone());
let eval = self
.eval_proj_call_t(*lhs, attr_name, args, self.level, &())
.map_err(|_| ())?;
if eval != old {
self.convert_type_to_tuple_type(eval)
} else {
Err(())
}
}
_ => Err(()),
}
}
@ -2857,6 +3018,24 @@ impl Context {
};
Ok(vec![ValueObj::builtin_type(t); len])
}
Type::Proj { lhs, rhs } => {
let old = proj(*lhs.clone(), rhs.clone());
match self.eval_proj(*lhs, rhs, self.level, &()) {
Ok(eval) if eval != old => self.convert_type_to_list(eval),
_ => Err(old),
}
}
Type::ProjCall {
lhs,
attr_name,
args,
} => {
let old = proj_call(*lhs.clone(), attr_name.clone(), args.clone());
match self.eval_proj_call_t(*lhs, attr_name, args, self.level, &()) {
Ok(eval) if eval != old => self.convert_type_to_list(eval),
_ => Err(old),
}
}
_ => Err(ty),
}
}
@ -3018,7 +3197,7 @@ impl Context {
let Some(lhs) = lhs else {
return feature_error!(self, t_loc.loc(), "??");
};
if let Ok(value) = ValueObj::try_from(lhs.clone()) {
if let Ok(value) = self.convert_tp_into_value(lhs.clone()) {
pos_args.push(value);
} else if let Ok(value) = self.eval_tp_into_value(lhs.clone()) {
pos_args.push(value);
@ -3027,7 +3206,7 @@ impl Context {
}
}
for pos_arg in args.into_iter() {
if let Ok(value) = ValueObj::try_from(pos_arg.clone()) {
if let Ok(value) = self.convert_tp_into_value(pos_arg.clone()) {
pos_args.push(value);
} else if let Ok(value) = self.eval_tp_into_value(pos_arg.clone()) {
pos_args.push(value);
@ -3074,6 +3253,7 @@ impl Context {
})
}
/// This may do nothing (be careful with recursive calls)
pub(crate) fn eval_proj_call_t(
&self,
lhs: TyParam,

View file

@ -18,7 +18,7 @@ use crate::ty::{HasType, Predicate, SubrType, Type};
use crate::context::{Context, Variance};
use crate::error::{TyCheckError, TyCheckErrors, TyCheckResult};
use crate::{feature_error, hir, unreachable_error};
use crate::{feature_error, hir, mono_type_pattern, mono_value_pattern, unreachable_error};
use Type::*;
use Variance::*;
@ -45,9 +45,10 @@ impl Generalizer {
fn generalize_tp(&mut self, free: TyParam, uninit: bool) -> TyParam {
match free {
TyParam::Type(t) => TyParam::t(self.generalize_t(*t, uninit)),
TyParam::Value(ValueObj::Type(t)) => {
TyParam::t(self.generalize_t(t.into_typ(), uninit))
}
TyParam::Value(val) => TyParam::Value(
val.map_t(&mut |t| self.generalize_t(t, uninit))
.map_tp(&mut |tp| self.generalize_tp(tp, uninit)),
),
TyParam::FreeVar(fv) if fv.is_generalized() => TyParam::FreeVar(fv),
TyParam::FreeVar(fv) if fv.is_linked() => {
let tp = fv.crack().clone();
@ -65,6 +66,9 @@ impl Generalizer {
.map(|tp| self.generalize_tp(tp, uninit))
.collect(),
),
TyParam::UnsizedList(tp) => {
TyParam::UnsizedList(Box::new(self.generalize_tp(*tp, uninit)))
}
TyParam::Tuple(tps) => TyParam::Tuple(
tps.into_iter()
.map(|tp| self.generalize_tp(tp, uninit))
@ -128,6 +132,14 @@ impl Generalizer {
let obj = self.generalize_tp(*obj, uninit);
TyParam::proj(obj, attr)
}
TyParam::ProjCall { obj, attr, args } => {
let obj = self.generalize_tp(*obj, uninit);
let args = args
.into_iter()
.map(|tp| self.generalize_tp(tp, uninit))
.collect();
TyParam::proj_call(obj, attr, args)
}
TyParam::Erased(t) => TyParam::erased(self.generalize_t(*t, uninit)),
TyParam::App { name, args } => {
let args = args
@ -145,13 +157,7 @@ impl Generalizer {
let val = self.generalize_tp(*val, uninit);
TyParam::unary(op, val)
}
other if other.has_no_unbound_var() => other,
other => {
if DEBUG_MODE {
todo!("{other:?}");
}
other
}
TyParam::Mono(_) | TyParam::Failure => free,
}
}
@ -203,6 +209,7 @@ impl Generalizer {
Type::FreeVar(fv)
}
}
FreeVar(_) => free_type,
Subr(mut subr) => {
self.variance = Contravariant;
let qnames = subr.essential_qnames();
@ -231,6 +238,10 @@ impl Generalizer {
return_t,
)
}
Quantified(quant) => {
log!(err "{quant}");
quant.quantify()
}
Record(rec) => {
let fields = rec
.into_iter()
@ -307,8 +318,14 @@ impl Generalizer {
let to = self.generalize_t(*grd.to, uninit);
guard(grd.namespace, grd.target, to)
}
// REVIEW: その他何でもそのまま通していいのか?
other => other,
Bounded { sub, sup } => {
let sub = self.generalize_t(*sub, uninit);
let sup = self.generalize_t(*sup, uninit);
bounded(sub, sup)
}
Int | Nat | Float | Ratio | Complex | Bool | Str | Never | Obj | Type | Error
| Code | Frame | NoneType | Inf | NegInf | NotImplementedType | Ellipsis
| ClassType | TraitType | Patch | Failure | Uninited | Mono(_) => free_type,
}
}
@ -328,9 +345,8 @@ impl Generalizer {
fn generalize_pred(&mut self, pred: Predicate, uninit: bool) -> Predicate {
match pred {
Predicate::Const(_) | Predicate::Failure => pred,
Predicate::Value(ValueObj::Type(mut typ)) => {
*typ.typ_mut() = self.generalize_t(mem::take(typ.typ_mut()), uninit);
Predicate::Value(ValueObj::Type(typ))
Predicate::Value(val) => {
Predicate::Value(val.map_t(&mut |t| self.generalize_t(t, uninit)))
}
Predicate::Call {
receiver,
@ -348,7 +364,6 @@ impl Generalizer {
let receiver = self.generalize_tp(receiver, uninit);
Predicate::attr(receiver, name)
}
Predicate::Value(_) => pred,
Predicate::GeneralEqual { lhs, rhs } => {
let lhs = self.generalize_pred(*lhs, uninit);
let rhs = self.generalize_pred(*rhs, uninit);
@ -454,7 +469,7 @@ impl<'c, 'q, 'l, L: Locational> Dereferencer<'c, 'q, 'l, L> {
fn deref_value(&mut self, val: ValueObj) -> TyCheckResult<ValueObj> {
match val {
ValueObj::Type(mut t) => {
t.try_map_t(|t| self.deref_tyvar(t.clone()))?;
t.try_map_t(&mut |t| self.deref_tyvar(t.clone()))?;
Ok(ValueObj::Type(t))
}
ValueObj::List(vs) => {
@ -505,7 +520,8 @@ impl<'c, 'q, 'l, L: Locational> Dereferencer<'c, 'q, 'l, L> {
})
}
ValueObj::UnsizedList(v) => Ok(ValueObj::UnsizedList(Box::new(self.deref_value(*v)?))),
_ => Ok(val),
ValueObj::Subr(subr) => Ok(ValueObj::Subr(subr)),
mono_value_pattern!() => Ok(val),
}
}
@ -530,6 +546,7 @@ impl<'c, 'q, 'l, L: Locational> Dereferencer<'c, 'q, 'l, L> {
fv.update_type(t);
Ok(TyParam::FreeVar(fv))
}
TyParam::FreeVar(_) => Ok(tp),
TyParam::Type(t) => Ok(TyParam::t(self.deref_tyvar(*t)?)),
TyParam::Value(val) => self.deref_value(val).map(TyParam::Value),
TyParam::Erased(t) => Ok(TyParam::erased(self.deref_tyvar(*t)?)),
@ -562,6 +579,7 @@ impl<'c, 'q, 'l, L: Locational> Dereferencer<'c, 'q, 'l, L> {
}
Ok(TyParam::List(new_tps))
}
TyParam::UnsizedList(tp) => Ok(TyParam::UnsizedList(Box::new(self.deref_tp(*tp)?))),
TyParam::Tuple(tps) => {
let mut new_tps = vec![];
for tp in tps {
@ -613,20 +631,20 @@ impl<'c, 'q, 'l, L: Locational> Dereferencer<'c, 'q, 'l, L> {
let nd_params = lambda
.nd_params
.into_iter()
.map(|pt| pt.try_map_type(|t| self.deref_tyvar(t)))
.map(|pt| pt.try_map_type(&mut |t| self.deref_tyvar(t)))
.collect::<TyCheckResult<_>>()?;
let var_params = lambda
.var_params
.map(|pt| pt.try_map_type(|t| self.deref_tyvar(t)))
.map(|pt| pt.try_map_type(&mut |t| self.deref_tyvar(t)))
.transpose()?;
let d_params = lambda
.d_params
.into_iter()
.map(|pt| pt.try_map_type(|t| self.deref_tyvar(t)))
.map(|pt| pt.try_map_type(&mut |t| self.deref_tyvar(t)))
.collect::<TyCheckResult<_>>()?;
let kw_var_params = lambda
.kw_var_params
.map(|pt| pt.try_map_type(|t| self.deref_tyvar(t)))
.map(|pt| pt.try_map_type(&mut |t| self.deref_tyvar(t)))
.transpose()?;
let body = lambda
.body
@ -649,10 +667,22 @@ impl<'c, 'q, 'l, L: Locational> Dereferencer<'c, 'q, 'l, L> {
attr,
})
}
TyParam::ProjCall { obj, attr, args } => {
let obj = self.deref_tp(*obj)?;
let mut new_args = vec![];
for arg in args.into_iter() {
new_args.push(self.deref_tp(arg)?);
}
Ok(TyParam::ProjCall {
obj: Box::new(obj),
attr,
args: new_args,
})
}
TyParam::Failure if self.level == 0 => Err(TyCheckErrors::from(
TyCheckError::dummy_infer_error(self.ctx.cfg.input.clone(), fn_name!(), line!()),
)),
t => Ok(t),
TyParam::Mono(_) | TyParam::Failure => Ok(tp),
}
}
@ -769,8 +799,12 @@ impl<'c, 'q, 'l, L: Locational> Dereferencer<'c, 'q, 'l, L> {
let pred = self.deref_pred(*pred)?;
Ok(!pred)
}
Predicate::Attr { receiver, name } => {
let receiver = self.deref_tp(receiver)?;
Ok(Predicate::attr(receiver, name))
}
Predicate::Value(v) => self.deref_value(v).map(Predicate::Value),
_ => Ok(pred),
Predicate::Const(_) | Predicate::Failure => Ok(pred),
}
}
@ -895,6 +929,7 @@ impl<'c, 'q, 'l, L: Locational> Dereferencer<'c, 'q, 'l, L> {
Ok(Type::FreeVar(fv))
}
}
FreeVar(_) => Ok(t),
Poly { name, mut params } => {
let typ = poly(&name, params.clone());
let ctx = self.ctx.get_nominal_type_ctx(&typ).ok_or_else(|| {
@ -1059,7 +1094,12 @@ impl<'c, 'q, 'l, L: Locational> Dereferencer<'c, 'q, 'l, L> {
let to = self.deref_tyvar(*grd.to)?;
Ok(guard(grd.namespace, grd.target, to))
}
t => Ok(t),
Bounded { sub, sup } => {
let sub = self.deref_tyvar(*sub)?;
let sup = self.deref_tyvar(*sup)?;
Ok(bounded(sub, sup))
}
mono_type_pattern!() => Ok(t),
}
}

View file

@ -348,8 +348,7 @@ pub(crate) fn __dict_getitem__(mut args: ValueArgs, ctx: &Context) -> EvalValueR
Ok(v.into())
} else {
let index = if let ValueObj::Type(t) = &index {
let derefed = ctx.coerce(t.typ().clone(), &()).unwrap_or(t.typ().clone());
ValueObj::builtin_type(derefed)
ValueObj::builtin_type(ctx.readable_type(t.typ().clone()))
} else {
index
};

View file

@ -1854,7 +1854,10 @@ impl Context {
),
Type::FreeVar(fv) => {
if let Some(sub) = fv.get_sub() {
if !self.subtype_of(&sub, &mono("GenericCallable")) {
fv.dummy_link();
let subtype_of = self.subtype_of(&sub, &mono("GenericCallable"));
fv.undo();
if !subtype_of {
return Err(self.not_callable_error(obj, attr_name, instance, None));
}
if sub != Never {

View file

@ -4,12 +4,12 @@ use std::option::Option; // conflicting to Type::Option
use erg_common::consts::DEBUG_MODE;
use erg_common::dict::Dict;
use erg_common::enum_unwrap;
#[allow(unused)]
use erg_common::log;
use erg_common::set::Set;
use erg_common::traits::Locational;
use erg_common::Str;
use erg_common::{enum_unwrap, set_recursion_limit};
use erg_parser::ast::VarName;
use crate::ty::constructors::*;
@ -19,7 +19,7 @@ use crate::ty::ConstSubr;
use crate::ty::GuardType;
use crate::ty::ValueObj;
use crate::ty::{HasType, Predicate, Type};
use crate::{type_feature_error, unreachable_error};
use crate::{mono_type_pattern, unreachable_error};
use Type::*;
use crate::context::{Context, VarInfo};
@ -40,7 +40,6 @@ pub struct TyVarCache {
pub(crate) tyvar_instances: Dict<VarName, Type>,
pub(crate) typaram_instances: Dict<VarName, TyParam>,
pub(crate) var_infos: Dict<VarName, VarInfo>,
pub(crate) structural_inner: bool,
}
impl fmt::Display for TyVarCache {
@ -61,7 +60,6 @@ impl TyVarCache {
tyvar_instances: Dict::new(),
typaram_instances: Dict::new(),
var_infos: Dict::new(),
structural_inner: false,
}
}
@ -419,6 +417,8 @@ impl Context {
tmp_tv_cache.instantiate_constraint(constr, self, loc)?;
fv.update_constraint(new_constr, true);
}
} else {
todo!("{tp}");
}
Ok(tp)
} else if let Some(t) = tmp_tv_cache.get_tyvar(&name) {
@ -433,6 +433,8 @@ impl Context {
tmp_tv_cache.instantiate_constraint(constr, self, loc)?;
fv.update_constraint(new_constr, true);
}
} else {
todo!("{t}");
}
Ok(TyParam::t(t))
} else {
@ -517,20 +519,28 @@ impl Context {
let nd_params = lambda
.nd_params
.into_iter()
.map(|pt| pt.try_map_type(|t| self.instantiate_t_inner(t, tmp_tv_cache, loc)))
.map(|pt| {
pt.try_map_type(&mut |t| self.instantiate_t_inner(t, tmp_tv_cache, loc))
})
.collect::<TyCheckResult<_>>()?;
let var_params = lambda
.var_params
.map(|pt| pt.try_map_type(|t| self.instantiate_t_inner(t, tmp_tv_cache, loc)))
.map(|pt| {
pt.try_map_type(&mut |t| self.instantiate_t_inner(t, tmp_tv_cache, loc))
})
.transpose()?;
let d_params = lambda
.d_params
.into_iter()
.map(|pt| pt.try_map_type(|t| self.instantiate_t_inner(t, tmp_tv_cache, loc)))
.map(|pt| {
pt.try_map_type(&mut |t| self.instantiate_t_inner(t, tmp_tv_cache, loc))
})
.collect::<TyCheckResult<_>>()?;
let kw_var_params = lambda
.kw_var_params
.map(|pt| pt.try_map_type(|t| self.instantiate_t_inner(t, tmp_tv_cache, loc)))
.map(|pt| {
pt.try_map_type(&mut |t| self.instantiate_t_inner(t, tmp_tv_cache, loc))
})
.transpose()?;
let body = lambda
.body
@ -578,22 +588,18 @@ impl Context {
let t = self.instantiate_t_inner(*t, tmp_tv_cache, loc)?;
Ok(TyParam::t(t))
}
TyParam::Value(ValueObj::Type(t)) => {
let t = self.instantiate_t_inner(t.into_typ(), tmp_tv_cache, loc)?;
Ok(TyParam::t(t))
TyParam::Value(val) => {
// println!("592: {val} / {tmp_tv_cache}");
let val = val.try_map_t(&mut |t| self.instantiate_t_inner(t, tmp_tv_cache, loc))?;
// .try_map_tp(&mut |tp| self.instantiate_tp(tp, tmp_tv_cache, loc))?;
// println!("596: {val} / {tmp_tv_cache}");
Ok(TyParam::Value(val))
}
TyParam::Erased(t) => {
let t = self.instantiate_t_inner(*t, tmp_tv_cache, loc)?;
Ok(TyParam::Erased(Box::new(t)))
}
p @ (TyParam::Value(_) | TyParam::Mono(_) | TyParam::FreeVar(_)) => Ok(p),
other => {
type_feature_error!(
self,
loc.loc(),
&format!("instantiating type-parameter {other}")
)
}
p @ (TyParam::Mono(_) | TyParam::FreeVar(_) | TyParam::Failure) => Ok(p),
}
}
@ -670,7 +676,11 @@ impl Context {
let rhs = self.instantiate_pred(*rhs, tmp_tv_cache, loc)?;
Ok(Predicate::general_ne(lhs, rhs))
}
_ => Ok(pred),
Predicate::Attr { receiver, name } => {
let receiver = self.instantiate_tp(receiver, tmp_tv_cache, loc)?;
Ok(Predicate::attr(receiver, name))
}
Predicate::Const(_) | Predicate::Failure => Ok(pred),
}
}
@ -714,6 +724,10 @@ impl Context {
}
Ok(ValueObj::List(new.into()))
}
ValueObj::UnsizedList(lis) => {
let lis = self.instantiate_value(*lis, tmp_tv_cache, loc)?;
Ok(ValueObj::UnsizedList(Box::new(lis)))
}
ValueObj::Tuple(tup) => {
let mut new = vec![];
for v in tup.iter().cloned() {
@ -754,7 +768,18 @@ impl Context {
}
Ok(ValueObj::DataClass { name, fields: new })
}
_ => Ok(value),
ValueObj::Int(_)
| ValueObj::Nat(_)
| ValueObj::Float(_)
| ValueObj::Str(_)
| ValueObj::Bool(_)
| ValueObj::Code(_)
| ValueObj::None
| ValueObj::Ellipsis
| ValueObj::Inf
| ValueObj::NegInf
| ValueObj::NotImplemented
| ValueObj::Failure => Ok(value),
}
}
@ -765,6 +790,8 @@ impl Context {
tmp_tv_cache: &mut TyVarCache,
loc: &impl Locational,
) -> TyCheckResult<Type> {
// Structural types may have recursive structures
set_recursion_limit!(Ok(unbound), 128);
match unbound {
FreeVar(fv) if fv.is_linked() => {
let t = fv.crack().clone();
@ -776,8 +803,7 @@ impl Context {
let t = t.clone();
Ok(t)
} else if let Some(tp) = tmp_tv_cache.get_typaram(&name) {
if let TyParam::Type(t) = tp {
let t = *t.clone();
if let Ok(t) = self.convert_tp_into_type(tp.clone()) {
Ok(t)
} else {
todo!(
@ -797,8 +823,8 @@ impl Context {
if let Some(t) = tv_ctx.get_tyvar(&name) {
return Ok(t.clone());
} else if let Some(tp) = tv_ctx.get_typaram(&name) {
if let TyParam::Type(t) = tp {
return Ok(*t.clone());
if let Ok(t) = self.convert_tp_into_type(tp.clone()) {
return Ok(t);
} else {
todo!(
"typaram_insts: {}\ntyvar_insts:{}\n{tp}",
@ -902,16 +928,8 @@ impl Context {
Ok(poly(name, params))
}
Structural(t) => {
// avoid infinite recursion
if tmp_tv_cache.structural_inner {
Ok(t.structuralize())
} else {
if t.is_recursive() {
tmp_tv_cache.structural_inner = true;
}
let t = self.instantiate_t_inner(*t, tmp_tv_cache, loc)?;
Ok(t.structuralize())
}
let t = self.instantiate_t_inner(*t, tmp_tv_cache, loc)?;
Ok(t.structuralize())
}
FreeVar(fv) => {
if let Some((sub, sup)) = fv.get_subsup() {
@ -961,8 +979,15 @@ impl Context {
let sup = self.instantiate_t_inner(*sup, tmp_tv_cache, loc)?;
Ok(bounded(sub, sup))
}
other if other.is_monomorphic() => Ok(other),
other => type_feature_error!(self, loc.loc(), &format!("instantiating type {other}")),
Callable { param_ts, return_t } => {
let param_ts = param_ts
.into_iter()
.map(|t| self.instantiate_t_inner(t, tmp_tv_cache, loc))
.collect::<TyCheckResult<_>>()?;
let return_t = self.instantiate_t_inner(*return_t, tmp_tv_cache, loc)?;
Ok(callable(param_ts, return_t))
}
mono_type_pattern!() => Ok(unbound),
}
}
@ -983,7 +1008,7 @@ impl Context {
if let Some(self_t) = ty.self_t() {
self.sub_unify(callee.ref_t(), self_t, callee, Some(&Str::ever("self")))?;
}
if cfg!(feature = "debug") && ty.has_qvar() {
if DEBUG_MODE && ty.has_qvar() {
panic!("{ty} has qvar")
}
Ok(ty)
@ -1028,6 +1053,7 @@ impl Context {
log!(err "{subr} has qvar");
self.instantiate(Type::Subr(subr).quantify(), callee)
}
// There are no quantified types inside normal types (rank-0 types) due to the rank-1 restriction
// rank-1制限により、通常の型(rank-0型)の内側に量化型は存在しない
other => Ok(other),
}
@ -1047,7 +1073,7 @@ impl Context {
Quantified(quant) => {
let mut tmp_tv_cache = TyVarCache::new(self.level, self);
let ty = self.instantiate_t_inner(*quant, &mut tmp_tv_cache, &())?;
if cfg!(feature = "debug") && ty.has_qvar() {
if DEBUG_MODE && ty.has_qvar() {
panic!("{ty} has qvar")
}
Ok(ty)

View file

@ -1945,7 +1945,7 @@ impl Context {
TyParam::App { name, args } => Ok(poly(name, args)),
TyParam::Type(t) => Ok(*t),
TyParam::Value(value) => self.convert_value_into_type(value).or_else(|value| {
type_feature_error!(self, loc.loc(), &format!("instantiate `{value}` as type"))
type_feature_error!(self, loc.loc(), &format!("instantiate `{value}` as a type"))
.map_err(|e| (Type::Failure, e))
}),
TyParam::List(lis) => {
@ -2038,7 +2038,7 @@ impl Context {
_ => type_feature_error!(
self,
loc.loc(),
&format!("instantiate `{lhs} {op} {rhs}` as type")
&format!("instantiate `{lhs} {op} {rhs}` as a type")
)
.map_err(|es| {
errs.extend(es);
@ -2049,7 +2049,7 @@ impl Context {
{
#[allow(clippy::bind_instead_of_map)]
self.convert_tp_into_type(other).or_else(|tp| {
type_feature_error!(self, loc.loc(), &format!("instantiate `{tp}` as type"))
type_feature_error!(self, loc.loc(), &format!("instantiate `{tp}` as a type"))
.map_err(|e| (Type::Failure, e))
})
}
@ -2927,7 +2927,7 @@ impl Context {
})?;
let mut dummy = TyVarCache::new(self.level, self);
match self.instantiate_const_expr(&const_expr, None, &mut dummy, false) {
Ok(tp) => ValueObj::try_from(tp).map_err(|_| {
Ok(tp) => self.convert_tp_into_value(tp).map_err(|_| {
let err = TyCheckError::not_const_expr(
self.cfg.input.clone(),
line!() as usize,
@ -2936,7 +2936,7 @@ impl Context {
);
(ValueObj::Failure, TyCheckErrors::from(err))
}),
Err((tp, mut errs)) => match ValueObj::try_from(tp) {
Err((tp, mut errs)) => match self.convert_tp_into_value(tp) {
Ok(value) => Err((value, errs)),
Err(_) => {
let err = TyCheckError::not_const_expr(

View file

@ -292,6 +292,15 @@ impl<'c, 'l, 'u, L: Locational> Unifier<'c, 'l, 'u, L> {
Ok(())
}
(ValueObj::Dict(sub), ValueObj::Dict(sup)) => {
if sub.len() == 1 && sup.len() == 1 {
let sub_key = sub.keys().next().unwrap();
let sup_key = sup.keys().next().unwrap();
self.sub_unify_value(sub_key, sup_key)?;
let sub_value = sub.values().next().unwrap();
let sup_value = sup.values().next().unwrap();
self.sub_unify_value(sub_value, sup_value)?;
return Ok(());
}
for (sub_k, sub_v) in sub.iter() {
if let Some(sup_v) = sup.get(sub_k) {
self.sub_unify_value(sub_v, sup_v)?;
@ -308,6 +317,22 @@ impl<'c, 'l, 'u, L: Locational> Unifier<'c, 'l, 'u, L> {
}
Ok(())
}
(ValueObj::Set(sub), ValueObj::Set(sup)) => {
if sub.len() == 1 && sup.len() == 1 {
let sub = sub.iter().next().unwrap();
let sup = sup.iter().next().unwrap();
self.sub_unify_value(sub, sup)?;
Ok(())
} else {
Err(TyCheckErrors::from(TyCheckError::feature_error(
self.ctx.cfg.input.clone(),
line!() as usize,
self.loc.loc(),
&format!("unifying {sub} and {sup}"),
self.ctx.caused_by(),
)))
}
}
(ValueObj::Record(sub), ValueObj::Record(sup)) => {
for (sub_k, sub_v) in sub.iter() {
if let Some(sup_v) = sup.get(sub_k) {
@ -929,8 +954,8 @@ impl<'c, 'l, 'u, L: Locational> Unifier<'c, 'l, 'u, L> {
/// ```
fn sub_unify(&self, maybe_sub: &Type, maybe_sup: &Type) -> TyCheckResult<()> {
log!(info "trying {}sub_unify:\nmaybe_sub: {maybe_sub}\nmaybe_sup: {maybe_sup}", self.undoable.map_or("", |_| "undoable_"));
self.recursion_limit.fetch_sub(1, Ordering::SeqCst);
if self.recursion_limit.load(Ordering::SeqCst) == 0 {
if self.recursion_limit.fetch_sub(1, Ordering::SeqCst) == 0 {
self.recursion_limit.store(128, Ordering::SeqCst);
log!(err "recursion limit exceeded: {maybe_sub} / {maybe_sup}");
return Err(TyCheckError::recursion_limit(
self.ctx.cfg.input.clone(),
@ -1268,23 +1293,33 @@ impl<'c, 'l, 'u, L: Locational> Unifier<'c, 'l, 'u, L> {
}
}
}
(FreeVar(sub_fv), Structural(sup)) if sub_fv.is_unbound() => {
if sub_fv.get_sub().is_none() {
(FreeVar(sub_fv), Structural(struct_sup)) if sub_fv.is_unbound() => {
let Some((sub, sup)) = sub_fv.get_subsup() else {
log!(err "{sub_fv} is not a type variable");
return Ok(());
}
};
sub_fv.dummy_link();
let sub_fields = self.ctx.fields(maybe_sub);
for (sup_field, sup_ty) in self.ctx.fields(sup) {
for (sup_field, sup_ty) in self.ctx.fields(struct_sup) {
if let Some((_, sub_ty)) = sub_fields.get_key_value(&sup_field) {
self.sub_unify(sub_ty, &sup_ty)?;
} else if !self.ctx.subtype_of(&sub_fv.get_sub().unwrap(), &Never) {
self.sub_unify(sub_ty, &sup_ty).map_err(|errs| {
sub_fv.undo();
errs
})?;
} else if !self.ctx.subtype_of(&sub, &Never) {
maybe_sub.coerce(self.undoable);
sub_fv.dummy_link();
return self.sub_unify(maybe_sub, maybe_sup);
} else {
// e.g. ?T / Structural({ .method = (self: ?T) -> Int })
sub_fv.update_super(|sup| self.ctx.intersection(&sup, maybe_sup));
let constr = Constraint::new_sandwiched(
sub.clone(),
self.ctx.intersection(&sup, maybe_sup),
);
sub_fv.update_constraint(constr, false);
}
}
sub_fv.undo();
}
(FreeVar(sub_fv), Ref(sup)) if sub_fv.is_unbound() => {
self.sub_unify(maybe_sub, sup)?;

View file

@ -59,7 +59,7 @@ impl SharedCompilerResource {
pub fn inherit<P: Into<NormalizedPathBuf>>(&self, path: P) -> Self {
let mut _self = self.clone();
_self.promises.path = path.into();
_self.promises.root = path.into();
_self
}

View file

@ -83,7 +83,7 @@ pub struct Progress {
#[derive(Debug, Clone, Default)]
pub struct SharedPromises {
graph: SharedModuleGraph,
pub(crate) path: NormalizedPathBuf,
pub(crate) root: NormalizedPathBuf,
promises: Shared<Dict<NormalizedPathBuf, Promise>>,
}
@ -98,10 +98,10 @@ impl fmt::Display for SharedPromises {
}
impl SharedPromises {
pub fn new(graph: SharedModuleGraph, path: NormalizedPathBuf) -> Self {
pub fn new(graph: SharedModuleGraph, root: NormalizedPathBuf) -> Self {
Self {
graph,
path,
root,
promises: Shared::new(Dict::new()),
}
}
@ -152,25 +152,30 @@ impl SharedPromises {
.is_some_and(|promise| promise.is_finished())
}
pub fn wait_until_finished(&self, path: &NormalizedPathBuf) {
if self.promises.borrow().get(path).is_none() {
panic!("not registered: {path}");
}
while !self.is_finished(path) {
safe_yield();
}
}
pub fn join(&self, path: &NormalizedPathBuf) -> std::thread::Result<()> {
if self.graph.ancestors(path).contains(&self.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)
while !self.is_finished(path) {
safe_yield();
}
// self.wait_until_finished(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);
for child in children.iter() {
if child == &self.path {
if child == &self.root {
continue;
} else if self.graph.depends_on(&self.path, child) {
while !self.is_finished(path) {
safe_yield();
}
} else if self.graph.depends_on(&self.root, child) {
self.wait_until_finished(path);
return Ok(());
}
}
@ -183,9 +188,7 @@ impl SharedPromises {
let promise = self.promises.borrow_mut().get_mut(path).unwrap().take();
let Promise::Running { handle, .. } = promise else {
*self.promises.borrow_mut().get_mut(path).unwrap() = promise;
while !self.is_finished(path) {
safe_yield();
}
self.wait_until_finished(path);
return Ok(());
};
if handle.thread().id() == current().id() {

View file

@ -245,8 +245,8 @@ impl Constraint {
} else if sup.addr_eq(target) {
Self::new_supertype_of(sub)
} else {
let sub = sub.eliminate_sub(target);
let sup = sup.eliminate_sub(target);
let sub = sub.eliminate_subsup(target);
let sup = sup.eliminate_subsup(target);
Self::new_sandwiched(sub, sup)
}
}
@ -1143,7 +1143,7 @@ impl<T: CanbeFree + Send + Clone> Free<T> {
/// if `in_inst_or_gen` is true, constraint will be updated forcibly
pub fn update_constraint(&self, new_constraint: Constraint, in_inst_or_gen: bool) {
if new_constraint.get_type() == Some(&Type::Never) {
panic!();
panic!("{new_constraint}");
}
match &mut *self.borrow_mut() {
FreeKind::Unbound {
@ -1168,20 +1168,14 @@ impl<T: CanbeFree + Send + Clone> Free<T> {
}
/// interior-mut
pub fn update_sub<F>(&self, f: F)
where
F: FnOnce(Type) -> Type,
{
pub fn update_sub(&self, f: impl FnOnce(Type) -> Type) {
let (sub, sup) = self.get_subsup().unwrap();
let new_constraint = Constraint::new_sandwiched(f(sub), sup);
self.update_constraint(new_constraint, true);
}
/// interior-mut
pub fn update_super<F>(&self, f: F)
where
F: FnOnce(Type) -> Type,
{
pub fn update_super(&self, f: impl FnOnce(Type) -> Type) {
let (sub, sup) = self.get_subsup().unwrap();
let new_constraint = Constraint::new_sandwiched(sub, f(sup));
self.update_constraint(new_constraint, true);
@ -1195,10 +1189,7 @@ impl<T: CanbeFree + Send + Clone> Free<T> {
}
impl Free<TyParam> {
pub fn map<F>(&self, f: F)
where
F: Fn(TyParam) -> TyParam,
{
pub fn map(&self, f: impl Fn(TyParam) -> TyParam) {
if let Some(mut linked) = self.get_linked_refmut() {
let mapped = f(mem::take(&mut *linked));
*linked = mapped;

View file

@ -31,13 +31,13 @@ use erg_common::fresh::FRESH_GEN;
use erg_common::log;
use erg_common::set::Set;
use erg_common::traits::{LimitedDisplay, Locational, StructuralEq};
use erg_common::{enum_unwrap, fmt_option, ref_addr_eq, set, Str};
use erg_common::{enum_unwrap, fmt_option, ref_addr_eq, set, set_recursion_limit, Str};
use erg_parser::ast::Expr;
use erg_parser::token::TokenKind;
pub use const_subr::*;
use constructors::{dict_t, int_interval, mono};
use constructors::{callable, dict_t, int_interval, mono};
use free::{CanbeFree, Constraint, Free, FreeKind, FreeTyVar, HasLevel, Level, GENERIC_LEVEL};
pub use predicate::Predicate;
pub use typaram::{IntervalOp, TyParam};
@ -54,6 +54,36 @@ pub const STR_OMIT_THRESHOLD: usize = if DEBUG_MODE { 100 } else { 16 };
pub const CONTAINER_OMIT_THRESHOLD: usize = if DEBUG_MODE { 100 } else { 8 };
pub const DEFAULT_PARAMS_THRESHOLD: usize = if DEBUG_MODE { 100 } else { 5 };
#[macro_export]
macro_rules! mono_type_pattern {
() => {
$crate::ty::Type::Int
| $crate::ty::Type::Nat
| $crate::ty::Type::Float
| $crate::ty::Type::Ratio
| $crate::ty::Type::Complex
| $crate::ty::Type::Inf
| $crate::ty::Type::NegInf
| $crate::ty::Type::Bool
| $crate::ty::Type::Str
| $crate::ty::Type::Code
| $crate::ty::Type::Frame
| $crate::ty::Type::Type
| $crate::ty::Type::TraitType
| $crate::ty::Type::ClassType
| $crate::ty::Type::Patch
| $crate::ty::Type::NoneType
| $crate::ty::Type::NotImplementedType
| $crate::ty::Type::Ellipsis
| $crate::ty::Type::Error
| $crate::ty::Type::Obj
| $crate::ty::Type::Never
| $crate::ty::Type::Failure
| $crate::ty::Type::Mono(_)
| $crate::ty::Type::Uninited
};
}
/// cloneのコストがあるためなるべく.ref_tを使うようにすること
/// いくつかの構造体は直接Typeを保持していないので、その場合は.tを使う
#[allow(unused_variables)]
@ -233,10 +263,7 @@ impl ParamTy {
}
}
pub fn map_type<F>(self, f: F) -> Self
where
F: FnOnce(Type) -> Type,
{
pub fn map_type(self, f: impl FnOnce(Type) -> Type) -> Self {
match self {
Self::Pos(ty) => Self::Pos(f(ty)),
Self::Kw { name, ty } => Self::Kw { name, ty: f(ty) },
@ -248,10 +275,7 @@ impl ParamTy {
}
}
pub fn map_default_type<F>(self, f: F) -> Self
where
F: FnOnce(Type) -> Type,
{
pub fn map_default_type(self, f: impl FnOnce(Type) -> Type) -> Self {
match self {
Self::KwWithDefault { name, ty, default } => Self::KwWithDefault {
name,
@ -262,10 +286,7 @@ impl ParamTy {
}
}
pub fn try_map_type<F, E>(self, f: F) -> Result<Self, E>
where
F: FnOnce(Type) -> Result<Type, E>,
{
pub fn try_map_type<E>(self, f: &mut impl FnMut(Type) -> Result<Type, E>) -> Result<Self, E> {
match self {
Self::Pos(ty) => Ok(Self::Pos(f(ty)?)),
Self::Kw { name, ty } => Ok(Self::Kw { name, ty: f(ty)? }),
@ -277,6 +298,20 @@ impl ParamTy {
}
}
pub fn try_map_default_type<E>(
self,
f: &mut impl FnMut(Type) -> Result<Type, E>,
) -> Result<Self, E> {
match self {
Self::KwWithDefault { name, ty, default } => Ok(Self::KwWithDefault {
name,
ty,
default: f(default)?,
}),
_ => Ok(self),
}
}
pub fn deconstruct(self) -> (Option<Str>, Type, Option<Type>) {
match self {
Self::Pos(ty) => (None, ty, None),
@ -309,7 +344,7 @@ impl TryFrom<Type> for SubrType {
type Error = ();
fn try_from(t: Type) -> Result<Self, ()> {
match t {
Type::FreeVar(fv) if fv.is_linked() => Self::try_from(fv.crack().clone()),
Type::FreeVar(fv) if fv.is_linked() => Self::try_from(fv.unwrap_linked()),
Type::Subr(st) => Ok(st),
Type::Quantified(quant) => SubrType::try_from(*quant),
Type::Refinement(refine) => Self::try_from(*refine.t),
@ -521,23 +556,72 @@ impl SubrType {
|| self.return_t.contains_tp(target)
}
pub fn map(self, f: impl Fn(Type) -> Type) -> Self {
pub fn map(self, f: impl Fn(Type) -> Type + Copy) -> Self {
Self::new(
self.kind,
self.non_default_params
.into_iter()
.map(|pt| pt.map_type(&f))
.map(|pt| pt.map_type(f))
.collect(),
self.var_params.map(|pt| pt.map_type(&f)),
self.var_params.map(|pt| pt.map_type(f)),
self.default_params
.into_iter()
.map(|pt| pt.map_type(&f).map_default_type(&f))
.map(|pt| pt.map_type(f).map_default_type(f))
.collect(),
self.kw_var_params.map(|pt| pt.map_type(&f)),
self.kw_var_params.map(|pt| pt.map_type(f)),
f(*self.return_t),
)
}
pub fn map_tp(self, f: &mut impl FnMut(TyParam) -> TyParam) -> Self {
let mut f_ = |t: Type| t.map_tp(f);
Self::new(
self.kind,
self.non_default_params
.into_iter()
.map(|pt| pt.map_type(&mut f_))
.collect(),
self.var_params.map(|pt| pt.map_type(&mut f_)),
self.default_params
.into_iter()
.map(|pt| pt.map_type(&mut f_).map_default_type(&mut f_))
.collect(),
self.kw_var_params.map(|pt| pt.map_type(&mut f_)),
f_(*self.return_t),
)
}
pub fn try_map_tp<E>(
self,
f: &mut impl FnMut(TyParam) -> Result<TyParam, E>,
) -> Result<Self, E> {
let mut f_ = |t: Type| t.try_map_tp(f);
let var_params = if let Some(var_params) = self.var_params {
Some(var_params.try_map_type(&mut f_)?)
} else {
None
};
let kw_var_params = if let Some(kw_var_params) = self.kw_var_params {
Some(kw_var_params.try_map_type(&mut f_)?)
} else {
None
};
Ok(Self::new(
self.kind,
self.non_default_params
.into_iter()
.map(|pt| pt.try_map_type(&mut f_))
.collect::<Result<_, _>>()?,
var_params,
self.default_params
.into_iter()
.map(|pt| pt.try_map_type(&mut f_)?.try_map_default_type(&mut f_))
.collect::<Result<_, _>>()?,
kw_var_params,
self.return_t.try_map_tp(f)?,
))
}
pub fn contains_value(&self, target: &ValueObj) -> bool {
self.non_default_params
.iter()
@ -1923,7 +2007,7 @@ impl HasLevel for Type {
Some(min)
}
}
_ => None,
mono_type_pattern!() => None,
}
}
@ -2000,7 +2084,7 @@ impl HasLevel for Type {
sub.set_level(level);
sup.set_level(level);
}
_ => {}
mono_type_pattern!() => {} //_ => {}
}
}
}
@ -2744,6 +2828,14 @@ impl Type {
<&FreeTyVar>::try_from(self).ok()
}
pub fn into_free(self) -> Option<FreeTyVar> {
match self {
Type::FreeVar(fv) => Some(fv),
Type::Refinement(refine) => refine.t.into_free(),
_ => None,
}
}
pub fn contains_tvar(&self, target: &FreeTyVar) -> bool {
match self {
Self::FreeVar(fv) if fv.is_linked() => fv.crack().contains_tvar(target),
@ -2782,7 +2874,11 @@ impl Type {
|| after.as_ref().map_or(false, |t| t.contains_tvar(target))
}
Self::Bounded { sub, sup } => sub.contains_tvar(target) || sup.contains_tvar(target),
_ => false,
Self::Callable { param_ts, return_t } => {
param_ts.iter().any(|t| t.contains_tvar(target)) || return_t.contains_tvar(target)
}
Self::Guard(guard) => guard.to.contains_tvar(target),
mono_type_pattern!() => false,
}
}
@ -2828,8 +2924,9 @@ impl Type {
Self::Poly { params, .. } => params.iter().any(|tp| tp.contains_type(target)),
Self::Quantified(t) => t.contains_type(target),
Self::Subr(subr) => subr.contains_type(target),
// TODO: preds
Self::Refinement(refine) => refine.t.contains_type(target),
Self::Refinement(refine) => {
refine.t.contains_type(target) || refine.pred.contains_t(target)
}
Self::Structural(ty) => ty.contains_type(target),
Self::Proj { lhs, .. } => lhs.contains_type(target),
Self::ProjCall { lhs, args, .. } => {
@ -2844,7 +2941,11 @@ impl Type {
|| after.as_ref().map_or(false, |t| t.contains_type(target))
}
Self::Bounded { sub, sup } => sub.contains_type(target) || sup.contains_type(target),
_ => false,
Self::Callable { param_ts, return_t } => {
param_ts.iter().any(|t| t.contains_type(target)) || return_t.contains_type(target)
}
Self::Guard(guard) => guard.to.contains_type(target),
mono_type_pattern!() => false,
}
}
@ -2878,13 +2979,18 @@ impl Type {
|| after.as_ref().map_or(false, |t| t.contains_tp(target))
}
Self::Bounded { sub, sup } => sub.contains_tp(target) || sup.contains_tp(target),
_ => false,
Self::Callable { param_ts, return_t } => {
param_ts.iter().any(|t| t.contains_tp(target)) || return_t.contains_tp(target)
}
Self::Guard(guard) => guard.to.contains_tp(target),
mono_type_pattern!() => false,
}
}
pub fn contains_value(&self, target: &ValueObj) -> bool {
match self {
Self::FreeVar(fv) if fv.is_linked() => fv.crack().contains_value(target),
Self::FreeVar(_) => false,
Self::Record(rec) => rec.iter().any(|(_, t)| t.contains_value(target)),
Self::NamedTuple(rec) => rec.iter().any(|(_, t)| t.contains_value(target)),
Self::Poly { params, .. } => params.iter().any(|tp| tp.contains_value(target)),
@ -2907,7 +3013,11 @@ impl Type {
|| after.as_ref().map_or(false, |t| t.contains_value(target))
}
Self::Bounded { sub, sup } => sub.contains_value(target) || sup.contains_value(target),
_ => false,
Self::Callable { param_ts, return_t } => {
param_ts.iter().any(|t| t.contains_value(target)) || return_t.contains_value(target)
}
Self::Guard(guard) => guard.to.contains_value(target),
mono_type_pattern!() => false,
}
}
@ -2928,7 +3038,9 @@ impl Type {
Self::Poly { params, .. } => params.iter().any(|tp| tp.contains_type(self)),
Self::Quantified(t) => t.contains_type(self),
Self::Subr(subr) => subr.contains_type(self),
Self::Refinement(refine) => refine.t.contains_type(self),
Self::Refinement(refine) => {
refine.t.contains_type(self) || refine.pred.contains_t(self)
}
Self::Structural(ty) => ty.contains_type(self),
Self::Proj { lhs, .. } => lhs.contains_type(self),
Self::ProjCall { lhs, args, .. } => {
@ -2944,7 +3056,11 @@ impl Type {
|| after.as_ref().map_or(false, |t| t.contains_type(self))
}
Self::Bounded { sub, sup } => sub.contains_type(self) || sup.contains_type(self),
_ => false,
Self::Callable { param_ts, return_t } => {
param_ts.iter().any(|t| t.contains_type(self)) || return_t.contains_type(self)
}
Self::Guard(guard) => guard.to.contains_type(self),
mono_type_pattern!() => false,
}
}
@ -3234,7 +3350,7 @@ impl Type {
/// ```
pub fn into_refinement(self) -> RefinementType {
match self {
Type::FreeVar(fv) if fv.is_linked() => fv.crack().clone().into_refinement(),
Type::FreeVar(fv) if fv.is_linked() => fv.unwrap_linked().into_refinement(),
Type::Nat => {
let var = FRESH_GEN.fresh_varname();
RefinementType::new(
@ -3288,7 +3404,7 @@ impl Type {
pub fn deconstruct_refinement(self) -> Result<(Str, Type, Predicate), Type> {
match self {
Type::FreeVar(fv) if fv.is_linked() => fv.crack().clone().deconstruct_refinement(),
Type::FreeVar(fv) if fv.is_linked() => fv.unwrap_linked().deconstruct_refinement(),
Type::Refinement(r) => Ok(r.deconstruct()),
_ => Err(self),
}
@ -3310,6 +3426,8 @@ impl Type {
fv.crack().destructive_coerce();
}
Type::FreeVar(fv) if fv.is_unbound_and_sandwiched() => {
// TODO: other way to avoid infinite recursion
set_recursion_limit!({}, 128);
let (sub, _sup) = fv.get_subsup().unwrap();
sub.destructive_coerce();
self.destructive_link(&sub);
@ -3326,6 +3444,32 @@ impl Type {
}
}
}
Type::Bounded { sub, sup } => {
sub.destructive_coerce();
sup.destructive_coerce();
}
Type::Ref(t) => t.destructive_coerce(),
Type::RefMut { before, after } => {
before.destructive_coerce();
if let Some(after) = after {
after.destructive_coerce();
}
}
Type::Structural(ty) => ty.destructive_coerce(),
Type::Record(r) => {
for t in r.values() {
t.destructive_coerce();
}
}
Type::NamedTuple(r) => {
for (_, t) in r.iter() {
t.destructive_coerce();
}
}
Type::Refinement(refine) => {
refine.t.destructive_coerce();
// refine.pred.destructive_coerce();
}
Type::Subr(subr) => subr.destructive_coerce(),
// TODO:
_ => {}
@ -3338,6 +3482,7 @@ impl Type {
fv.crack().undoable_coerce(list);
}
Type::FreeVar(fv) if fv.is_unbound_and_sandwiched() => {
set_recursion_limit!({}, 128);
let (sub, _sup) = fv.get_subsup().unwrap();
sub.undoable_coerce(list);
self.undoable_link(&sub, list);
@ -3395,6 +3540,7 @@ impl Type {
base
}
}
Self::FreeVar(_) => set! {},
Self::Ref(ty) => ty.qvars_inner(),
Self::RefMut { before, after } => before.qvars_inner().concat(
after
@ -3418,6 +3564,7 @@ impl Type {
Self::Refinement(refine) => refine.t.qvars_inner().concat(refine.pred.qvars()),
// ((|T| T -> T) and U).qvars() == U.qvars()
// Self::Quantified(quant) => quant.qvars(),
Self::Quantified(_) => set! {},
Self::Poly { params, .. } => params
.iter()
.fold(set! {}, |acc, tp| acc.concat(tp.qvars())),
@ -3428,7 +3575,7 @@ impl Type {
Self::Structural(ty) => ty.qvars_inner(),
Self::Guard(guard) => guard.to.qvars_inner(),
Self::Bounded { sub, sup } => sub.qvars_inner().concat(sup.qvars_inner()),
_ => set! {},
mono_type_pattern!() => set! {},
}
}
@ -3475,6 +3622,7 @@ impl Type {
param_ts.iter().any(|t| t.has_qvar()) || return_t.has_qvar()
}
Self::Subr(subr) => subr.has_qvar(),
Self::Quantified(_) => false,
// Self::Quantified(quant) => quant.has_qvar(),
Self::Record(r) => r.values().any(|t| t.has_qvar()),
Self::NamedTuple(r) => r.iter().any(|(_, t)| t.has_qvar()),
@ -3487,7 +3635,7 @@ impl Type {
Self::Structural(ty) => ty.has_qvar(),
Self::Guard(guard) => guard.to.has_qvar(),
Self::Bounded { sub, sup } => sub.has_qvar() || sup.has_qvar(),
_ => false,
mono_type_pattern!() => false,
}
}
@ -3546,7 +3694,7 @@ impl Type {
Self::Bounded { sub, sup } => {
sub.has_undoable_linked_var() || sup.has_undoable_linked_var()
}
_ => false,
mono_type_pattern!() => false,
}
}
@ -3596,7 +3744,7 @@ impl Type {
Self::Structural(ty) => ty.has_unbound_var(),
Self::Guard(guard) => guard.to.has_unbound_var(),
Self::Bounded { sub, sup } => sub.has_unbound_var() || sup.has_unbound_var(),
_ => false,
mono_type_pattern!() => false,
}
}
@ -3808,7 +3956,7 @@ impl Type {
// At least in situations where this function is needed, self cannot be Quantified.
Self::Quantified(quant) => {
if quant.return_t()?.is_generalized() {
log!(err "quantified return type (recursive function type inference)");
log!(err "quantified return type (recursive function type inference?)");
}
quant.return_t()
}
@ -3942,41 +4090,41 @@ impl Type {
}
Self::Subr(subr) => Self::Subr(subr.derefine()),
Self::Quantified(quant) => quant.derefine().quantify(),
other => other.clone(),
mono_type_pattern!() => self.clone(),
}
}
/// ```erg
/// (T or U).eliminate_sub(T) == U
/// ?X(<: T or U).eliminate_sub(T) == ?X(<: U)
/// (T or U).eliminate_subsup(T) == U
/// ?X(<: T or U).eliminate_subsup(T) == ?X(<: U)
/// ```
pub fn eliminate_sub(self, target: &Type) -> Self {
pub fn eliminate_subsup(self, target: &Type) -> Self {
match self {
Self::FreeVar(fv) if fv.is_linked() => fv.unwrap_linked().eliminate_sub(target),
Self::FreeVar(fv) if fv.is_linked() => fv.unwrap_linked().eliminate_subsup(target),
Self::FreeVar(ref fv) if fv.constraint_is_sandwiched() => {
let (sub, sup) = fv.get_subsup().unwrap();
fv.do_avoiding_recursion(|| {
let sub = sub.eliminate_sub(target);
let sup = sup.eliminate_sub(target);
let sub = sub.eliminate_subsup(target);
let sup = sup.eliminate_subsup(target);
self.update_tyvar(sub, sup, None, false);
});
self
}
Self::And(l, r) => {
if l.addr_eq(target) {
return r.eliminate_sub(target);
return r.eliminate_subsup(target);
} else if r.addr_eq(target) {
return l.eliminate_sub(target);
return l.eliminate_subsup(target);
}
l.eliminate_sub(target) & r.eliminate_sub(target)
l.eliminate_subsup(target) & r.eliminate_subsup(target)
}
Self::Or(l, r) => {
if l.addr_eq(target) {
return r.eliminate_sub(target);
return r.eliminate_subsup(target);
} else if r.addr_eq(target) {
return l.eliminate_sub(target);
return l.eliminate_subsup(target);
}
l.eliminate_sub(target) | r.eliminate_sub(target)
l.eliminate_subsup(target) | r.eliminate_subsup(target)
}
other => other,
}
@ -3992,8 +4140,10 @@ impl Type {
}
match self {
Self::FreeVar(fv) if fv.is_linked() => fv.unwrap_linked().eliminate_recursion(target),
Self::FreeVar(_) => self,
Self::Refinement(mut refine) => {
refine.t = Box::new(refine.t.eliminate_recursion(target));
refine.pred = Box::new(refine.pred.map_t(&mut |t| t.eliminate_recursion(target)));
Self::Refinement(refine)
}
Self::Record(mut rec) => {
@ -4052,7 +4202,7 @@ impl Type {
sub: Box::new(sub.eliminate_recursion(target)),
sup: Box::new(sup.eliminate_recursion(target)),
},
other => other,
mono_type_pattern!() => self,
}
}
@ -4139,7 +4289,7 @@ impl Type {
self = to.clone();
}
match self {
Self::FreeVar(fv) if fv.is_linked() => fv.crack().clone()._replace(target, to),
Self::FreeVar(fv) if fv.is_linked() => fv.unwrap_linked()._replace(target, to),
Self::FreeVar(fv) => {
let fv_clone = fv.deep_clone();
if let Some((sub, sup)) = fv_clone.get_subsup() {
@ -4158,6 +4308,7 @@ impl Type {
}
Self::Refinement(mut refine) => {
refine.t = Box::new(refine.t._replace(target, to));
refine.pred = Box::new(refine.pred._replace_t(target, to));
Self::Refinement(refine)
}
Self::Record(mut rec) => {
@ -4219,13 +4370,13 @@ impl Type {
sub: Box::new(sub._replace(target, to)),
sup: Box::new(sup._replace(target, to)),
},
other => other,
mono_type_pattern!() => self,
}
}
fn _replace_tp(self, target: &TyParam, to: &TyParam) -> Type {
match self {
Self::FreeVar(fv) if fv.is_linked() => fv.crack().clone()._replace_tp(target, to),
Self::FreeVar(fv) if fv.is_linked() => fv.unwrap_linked()._replace_tp(target, to),
Self::FreeVar(fv) => {
let fv_clone = fv.deep_clone();
if let Some((sub, sup)) = fv_clone.get_subsup() {
@ -4246,7 +4397,7 @@ impl Type {
}
Self::Refinement(mut refine) => {
refine.t = Box::new(refine.t._replace_tp(target, to));
// refine.pred = refine.pred.replace_tp(target, to);
refine.pred = Box::new(refine.pred._replace_tp(target, to));
Self::Refinement(refine)
}
Self::Record(mut rec) => {
@ -4305,13 +4456,180 @@ impl Type {
sub: Box::new(sub._replace_tp(target, to)),
sup: Box::new(sup._replace_tp(target, to)),
},
other => other,
mono_type_pattern!() => self,
}
}
fn map_tp(self, f: &mut impl FnMut(TyParam) -> TyParam) -> Type {
match self {
Self::FreeVar(fv) if fv.is_linked() => fv.unwrap_linked().map_tp(f),
Self::FreeVar(fv) => {
let fv_clone = fv.deep_clone();
if let Some((sub, sup)) = fv_clone.get_subsup() {
fv.dummy_link();
fv_clone.dummy_link();
let sub = sub.map_tp(f);
let sup = sup.map_tp(f);
fv.undo();
fv_clone.undo();
fv_clone.update_constraint(Constraint::new_sandwiched(sub, sup), true);
} else if let Some(ty) = fv_clone.get_type() {
fv_clone.update_constraint(Constraint::new_type_of(ty.map_tp(f)), true);
}
Self::FreeVar(fv_clone)
}
Self::Refinement(mut refine) => {
refine.t = Box::new(refine.t.map_tp(f));
refine.pred = Box::new(refine.pred.map_tp(f));
Self::Refinement(refine)
}
Self::Record(mut rec) => {
for v in rec.values_mut() {
*v = std::mem::take(v).map_tp(f);
}
Self::Record(rec)
}
Self::NamedTuple(mut r) => {
for (_, v) in r.iter_mut() {
*v = std::mem::take(v).map_tp(f);
}
Self::NamedTuple(r)
}
Self::Subr(subr) => Self::Subr(subr.map_tp(f)),
Self::Callable { param_ts, return_t } => {
let param_ts = param_ts.into_iter().map(|t| t.map_tp(f)).collect();
let return_t = Box::new(return_t.map_tp(f));
Self::Callable { param_ts, return_t }
}
Self::Quantified(quant) => quant.map_tp(f).quantify(),
Self::Poly { name, params } => {
let params = params.into_iter().map(|tp| tp.map(f)).collect();
Self::Poly { name, params }
}
Self::Ref(t) => Self::Ref(Box::new(t.map_tp(f))),
Self::RefMut { before, after } => Self::RefMut {
before: Box::new(before.map_tp(f)),
after: after.map(|t| Box::new(t.map_tp(f))),
},
Self::And(l, r) => l.map_tp(f) & r.map_tp(f),
Self::Or(l, r) => l.map_tp(f) | r.map_tp(f),
Self::Not(ty) => !ty.map_tp(f),
Self::Proj { lhs, rhs } => lhs.map_tp(f).proj(rhs),
Self::ProjCall {
lhs,
attr_name,
args,
} => {
let args = args.into_iter().map(|tp| tp.map(f)).collect();
proj_call(lhs.map(f), attr_name, args)
}
Self::Structural(ty) => ty.map_tp(f).structuralize(),
Self::Guard(guard) => Self::Guard(GuardType::new(
guard.namespace,
guard.target.clone(),
guard.to.map_tp(f),
)),
Self::Bounded { sub, sup } => Self::Bounded {
sub: Box::new(sub.map_tp(f)),
sup: Box::new(sup.map_tp(f)),
},
mono_type_pattern!() => self,
}
}
pub fn try_map_tp<E>(
self,
f: &mut impl FnMut(TyParam) -> Result<TyParam, E>,
) -> Result<Type, E> {
match self {
Self::FreeVar(fv) if fv.is_linked() => fv.unwrap_linked().try_map_tp(f),
Self::FreeVar(fv) => {
let fv_clone = fv.deep_clone();
if let Some((sub, sup)) = fv_clone.get_subsup() {
fv.dummy_link();
fv_clone.dummy_link();
let sub = sub.try_map_tp(f)?;
let sup = sup.try_map_tp(f)?;
fv.undo();
fv_clone.undo();
fv_clone.update_constraint(Constraint::new_sandwiched(sub, sup), true);
} else if let Some(ty) = fv_clone.get_type() {
fv_clone.update_constraint(Constraint::new_type_of(ty.try_map_tp(f)?), true);
}
Ok(Self::FreeVar(fv_clone))
}
Self::Refinement(mut refine) => {
refine.t = Box::new(refine.t.try_map_tp(f)?);
refine.pred = Box::new(refine.pred.try_map_tp(f)?);
Ok(Self::Refinement(refine))
}
Self::Record(mut rec) => {
for v in rec.values_mut() {
*v = std::mem::take(v).try_map_tp(f)?;
}
Ok(Self::Record(rec))
}
Self::NamedTuple(mut r) => {
for (_, v) in r.iter_mut() {
*v = std::mem::take(v).try_map_tp(f)?;
}
Ok(Self::NamedTuple(r))
}
Self::Subr(subr) => Ok(Self::Subr(subr.try_map_tp(f)?)),
Self::Callable { param_ts, return_t } => {
let param_ts = param_ts
.into_iter()
.map(|t| t.try_map_tp(f))
.collect::<Result<_, _>>()?;
let return_t = Box::new(return_t.try_map_tp(f)?);
Ok(Self::Callable { param_ts, return_t })
}
Self::Quantified(quant) => Ok(quant.try_map_tp(f)?.quantify()),
Self::Poly { name, params } => {
let params = params.into_iter().map(f).collect::<Result<_, _>>()?;
Ok(Self::Poly { name, params })
}
Self::Ref(t) => Ok(Self::Ref(Box::new(t.try_map_tp(f)?))),
Self::RefMut { before, after } => {
let after = match after {
Some(t) => Some(Box::new(t.try_map_tp(f)?)),
None => None,
};
Ok(Self::RefMut {
before: Box::new(before.try_map_tp(f)?),
after,
})
}
Self::And(l, r) => Ok(l.try_map_tp(f)? & r.try_map_tp(f)?),
Self::Or(l, r) => Ok(l.try_map_tp(f)? | r.try_map_tp(f)?),
Self::Not(ty) => Ok(!ty.try_map_tp(f)?),
Self::Proj { lhs, rhs } => Ok(lhs.try_map_tp(f)?.proj(rhs)),
Self::ProjCall {
lhs,
attr_name,
args,
} => {
let lhs = f(*lhs)?;
let args = args.into_iter().map(f).collect::<Result<_, _>>()?;
Ok(proj_call(lhs, attr_name, args))
}
Self::Structural(ty) => Ok(ty.try_map_tp(f)?.structuralize()),
Self::Guard(guard) => Ok(Self::Guard(GuardType::new(
guard.namespace,
guard.target.clone(),
guard.to.try_map_tp(f)?,
))),
Self::Bounded { sub, sup } => Ok(Self::Bounded {
sub: Box::new(sub.try_map_tp(f)?),
sup: Box::new(sup.try_map_tp(f)?),
}),
mono_type_pattern!() => Ok(self),
}
}
fn replace_param(self, target: &str, to: &str) -> Self {
match self {
Self::FreeVar(fv) if fv.is_linked() => fv.crack().clone().replace_param(target, to),
Self::FreeVar(fv) if fv.is_linked() => fv.unwrap_linked().replace_param(target, to),
Self::Refinement(mut refine) => {
*refine.t = refine.t.replace_param(target, to);
Self::Refinement(refine)
@ -4336,11 +4654,17 @@ impl Type {
/// TyParam::Value(ValueObj::Type(_)) => TyParam::Type
pub fn normalize(self) -> Self {
match self {
Self::FreeVar(fv) if fv.is_linked() => fv.crack().clone().normalize(),
Self::FreeVar(fv) if fv.is_linked() => fv.unwrap_linked().normalize(),
Self::FreeVar(_) => self,
Self::Poly { name, params } => {
let params = params.into_iter().map(|tp| tp.normalize()).collect();
Self::Poly { name, params }
}
Self::Refinement(mut refine) => {
refine.t = Box::new(refine.t.normalize());
refine.pred = Box::new(refine.pred.map_t(&mut |t| t.normalize()));
Self::Refinement(refine)
}
Self::Subr(mut subr) => {
for nd in subr.non_default_params.iter_mut() {
*nd.typ_mut() = std::mem::take(nd.typ_mut()).normalize();
@ -4387,6 +4711,7 @@ impl Type {
Self::Or(l, r) => l.normalize() | r.normalize(),
Self::Not(ty) => !ty.normalize(),
Self::Structural(ty) => ty.normalize().structuralize(),
Self::Quantified(quant) => quant.normalize().quantify(),
Self::Guard(guard) => Self::Guard(GuardType::new(
guard.namespace,
guard.target,
@ -4396,7 +4721,12 @@ impl Type {
sub: Box::new(sub.normalize()),
sup: Box::new(sup.normalize()),
},
other => other,
Self::Callable { param_ts, return_t } => {
let param_ts = param_ts.into_iter().map(|t| t.normalize()).collect();
let return_t = return_t.normalize();
callable(param_ts, return_t)
}
mono_type_pattern!() => self,
}
}
@ -4438,11 +4768,17 @@ impl Type {
}
return;
}
let to = to.clone().eliminate_sub(self).eliminate_recursion(self);
match self {
Self::FreeVar(fv) => fv.link(&to),
Self::Refinement(refine) => refine.t.destructive_link(&to),
_ => panic!("{self} is not a free variable"),
Self::FreeVar(fv) => {
let to = to.clone().eliminate_subsup(self).eliminate_recursion(self);
fv.link(&to);
}
Self::Refinement(refine) => refine.t.destructive_link(to),
_ => {
if DEBUG_MODE {
panic!("{self} is not a free variable");
}
}
}
}
@ -4456,9 +4792,16 @@ impl Type {
return;
}
match self {
Self::FreeVar(fv) => fv.undoable_link(to),
Self::FreeVar(fv) => {
let to = to.clone().eliminate_subsup(self);
fv.undoable_link(&to);
}
Self::Refinement(refine) => refine.t.undoable_link(to, list),
_ => panic!("{self} is not a free variable"),
_ => {
if DEBUG_MODE {
panic!("{self} is not a free variable")
}
}
}
}
@ -4597,6 +4940,7 @@ impl Type {
.union(&sup.contained_ts())
})
}
Self::FreeVar(_) => set! { self.clone() },
Self::Refinement(refine) => refine.t.contained_ts(),
Self::Ref(t) => t.contained_ts(),
Self::RefMut { before, .. } => before.contained_ts(),
@ -4638,7 +4982,8 @@ impl Type {
ts.extend(params.iter().flat_map(|tp| tp.contained_ts()));
ts
}
_ => set! { self.clone() },
Self::Guard(guard) => guard.to.contained_ts(),
mono_type_pattern!() => set! { self.clone() },
}
}
@ -4652,8 +4997,12 @@ impl Type {
Self::FreeVar(fv) if fv.is_generalized() => {
fv.update_init();
}
Self::FreeVar(_) => {}
// TODO: T(:> X, <: Y).dereference()
Self::Refinement(refine) => refine.t.dereference(),
Self::Refinement(refine) => {
refine.t.dereference();
refine.pred.dereference();
}
Self::Ref(t) => {
t.dereference();
}
@ -4725,7 +5074,7 @@ impl Type {
Self::Guard(guard) => {
guard.to.dereference();
}
_ => {}
mono_type_pattern!() => {}
}
}

View file

@ -10,8 +10,9 @@ use erg_common::{fmt_option, set, Str};
use super::free::{Constraint, HasLevel};
use super::typaram::TyParam;
use super::value::ValueObj;
use super::Type;
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[derive(Debug, Clone, PartialEq, Eq, Hash, Default)]
pub enum Predicate {
Value(ValueObj), // True/False
Const(Str),
@ -63,6 +64,7 @@ pub enum Predicate {
Or(Box<Predicate>, Box<Predicate>),
And(Box<Predicate>, Box<Predicate>),
Not(Box<Predicate>),
#[default]
Failure,
}
@ -860,7 +862,7 @@ impl Predicate {
pub fn contains_value(&self, value: &ValueObj) -> bool {
match self {
Self::Value(v) => v == value,
Self::Value(v) => v.contains(value),
Self::Const(_) => false,
Self::Call { receiver, args, .. } => {
receiver.contains_value(value) || args.iter().any(|a| a.contains_value(value))
@ -886,8 +888,7 @@ impl Predicate {
pub fn contains_tp(&self, tp: &TyParam) -> bool {
match self {
Self::Value(_) | Self::Failure => false,
Self::Const(_) => false,
Self::Value(v) => v.contains_tp(tp),
Self::Call { receiver, args, .. } => {
receiver.contains_tp(tp) || args.iter().any(|a| a.contains_tp(tp))
}
@ -902,67 +903,211 @@ impl Predicate {
| Self::GeneralNotEqual { lhs, rhs } => lhs.contains_tp(tp) || rhs.contains_tp(tp),
Self::And(lhs, rhs) | Self::Or(lhs, rhs) => lhs.contains_tp(tp) || rhs.contains_tp(tp),
Self::Not(pred) => pred.contains_tp(tp),
_ => false,
}
}
pub fn replace_tp(self, target: &TyParam, to: &TyParam) -> Self {
pub fn contains_t(&self, t: &Type) -> bool {
match self {
Self::Value(_) | Self::Failure => self,
Self::Value(v) => v.contains_type(t),
Self::Call { receiver, args, .. } => {
receiver.contains_type(t) || args.iter().any(|a| a.contains_type(t))
}
Self::Attr { receiver, .. } => receiver.contains_type(t),
Self::Equal { rhs, .. }
| Self::GreaterEqual { rhs, .. }
| Self::LessEqual { rhs, .. }
| Self::NotEqual { rhs, .. } => rhs.contains_type(t),
Self::GeneralEqual { lhs, rhs }
| Self::GeneralLessEqual { lhs, rhs }
| Self::GeneralGreaterEqual { lhs, rhs }
| Self::GeneralNotEqual { lhs, rhs } => lhs.contains_t(t) || rhs.contains_t(t),
Self::And(lhs, rhs) | Self::Or(lhs, rhs) => lhs.contains_t(t) || rhs.contains_t(t),
Self::Not(pred) => pred.contains_t(t),
_ => false,
}
}
pub fn _replace_tp(self, target: &TyParam, to: &TyParam) -> Self {
self.map_tp(&mut |tp| tp._replace(target, to))
}
pub fn replace_tp(self, target: &TyParam, to: &TyParam) -> Self {
self.map_tp(&mut |tp| tp.replace(target, to))
}
pub fn _replace_t(self, target: &Type, to: &Type) -> Self {
self.map_t(&mut |t| t._replace(target, to))
}
pub fn dereference(&mut self) {
*self = std::mem::take(self).map_t(&mut |mut t| {
t.dereference();
t
});
}
pub fn map_t(self, f: &mut impl FnMut(Type) -> Type) -> Self {
match self {
Self::Value(val) => Self::Value(val.map_t(f)),
Self::Const(_) => self,
Self::Call {
receiver,
args,
name,
} => Self::Call {
receiver: receiver.replace(target, to),
args: args.into_iter().map(|a| a.replace(target, to)).collect(),
receiver: receiver.map_t(f),
args: args.into_iter().map(|a| a.map_t(f)).collect(),
name,
},
Self::Attr { receiver, name } => Self::Attr {
receiver: receiver.replace(target, to),
receiver: receiver.map_t(f),
name,
},
Self::Equal { lhs, rhs } => Self::Equal {
lhs,
rhs: rhs.replace(target, to),
rhs: rhs.map_t(f),
},
Self::GreaterEqual { lhs, rhs } => Self::GreaterEqual {
lhs,
rhs: rhs.replace(target, to),
rhs: rhs.map_t(f),
},
Self::LessEqual { lhs, rhs } => Self::LessEqual {
lhs,
rhs: rhs.replace(target, to),
rhs: rhs.map_t(f),
},
Self::NotEqual { lhs, rhs } => Self::NotEqual {
lhs,
rhs: rhs.replace(target, to),
rhs: rhs.map_t(f),
},
Self::GeneralEqual { lhs, rhs } => Self::GeneralEqual {
lhs: Box::new(lhs.replace_tp(target, to)),
rhs: Box::new(rhs.replace_tp(target, to)),
lhs: Box::new(lhs.map_t(f)),
rhs: Box::new(rhs.map_t(f)),
},
Self::GeneralLessEqual { lhs, rhs } => Self::GeneralLessEqual {
lhs: Box::new(lhs.replace_tp(target, to)),
rhs: Box::new(rhs.replace_tp(target, to)),
lhs: Box::new(lhs.map_t(f)),
rhs: Box::new(rhs.map_t(f)),
},
Self::GeneralGreaterEqual { lhs, rhs } => Self::GeneralGreaterEqual {
lhs: Box::new(lhs.replace_tp(target, to)),
rhs: Box::new(rhs.replace_tp(target, to)),
lhs: Box::new(lhs.map_t(f)),
rhs: Box::new(rhs.map_t(f)),
},
Self::GeneralNotEqual { lhs, rhs } => Self::GeneralNotEqual {
lhs: Box::new(lhs.replace_tp(target, to)),
rhs: Box::new(rhs.replace_tp(target, to)),
lhs: Box::new(lhs.map_t(f)),
rhs: Box::new(rhs.map_t(f)),
},
Self::And(lhs, rhs) => Self::And(
Box::new(lhs.replace_tp(target, to)),
Box::new(rhs.replace_tp(target, to)),
),
Self::Or(lhs, rhs) => Self::Or(
Box::new(lhs.replace_tp(target, to)),
Box::new(rhs.replace_tp(target, to)),
),
Self::Not(pred) => Self::Not(Box::new(pred.replace_tp(target, to))),
Self::And(lhs, rhs) => Self::And(Box::new(lhs.map_t(f)), Box::new(rhs.map_t(f))),
Self::Or(lhs, rhs) => Self::Or(Box::new(lhs.map_t(f)), Box::new(rhs.map_t(f))),
Self::Not(pred) => Self::Not(Box::new(pred.map_t(f))),
_ => self,
}
}
pub fn map_tp(self, f: &mut impl FnMut(TyParam) -> TyParam) -> Self {
match self {
Self::Value(val) => Self::Value(val.map_tp(f)),
Self::Const(_) => self,
Self::Call {
receiver,
args,
name,
} => Self::Call {
receiver: receiver.map(f),
args: args.into_iter().map(|a| a.map(f)).collect(),
name,
},
Self::Attr { receiver, name } => Self::Attr {
receiver: receiver.map(f),
name,
},
Self::Equal { lhs, rhs } => Self::Equal {
lhs,
rhs: rhs.map(f),
},
Self::GreaterEqual { lhs, rhs } => Self::GreaterEqual {
lhs,
rhs: rhs.map(f),
},
Self::LessEqual { lhs, rhs } => Self::LessEqual {
lhs,
rhs: rhs.map(f),
},
Self::NotEqual { lhs, rhs } => Self::NotEqual {
lhs,
rhs: rhs.map(f),
},
Self::GeneralEqual { lhs, rhs } => Self::GeneralEqual {
lhs: Box::new(lhs.map_tp(f)),
rhs: Box::new(rhs.map_tp(f)),
},
Self::GeneralLessEqual { lhs, rhs } => Self::GeneralLessEqual {
lhs: Box::new(lhs.map_tp(f)),
rhs: Box::new(rhs.map_tp(f)),
},
Self::GeneralGreaterEqual { lhs, rhs } => Self::GeneralGreaterEqual {
lhs: Box::new(lhs.map_tp(f)),
rhs: Box::new(rhs.map_tp(f)),
},
Self::GeneralNotEqual { lhs, rhs } => Self::GeneralNotEqual {
lhs: Box::new(lhs.map_tp(f)),
rhs: Box::new(rhs.map_tp(f)),
},
Self::And(lhs, rhs) => Self::And(Box::new(lhs.map_tp(f)), Box::new(rhs.map_tp(f))),
Self::Or(lhs, rhs) => Self::Or(Box::new(lhs.map_tp(f)), Box::new(rhs.map_tp(f))),
Self::Not(pred) => Self::Not(Box::new(pred.map_tp(f))),
_ => self,
}
}
pub fn try_map_tp<E>(
self,
f: &mut impl FnMut(TyParam) -> Result<TyParam, E>,
) -> Result<Self, E> {
match self {
Self::Value(val) => Ok(Self::Value(val.try_map_tp(f)?)),
Self::Call {
receiver,
args,
name,
} => Ok(Self::Call {
receiver: f(receiver)?,
args: args.into_iter().map(f).collect::<Result<_, E>>()?,
name,
}),
Self::Attr { receiver, name } => Ok(Self::Attr {
receiver: f(receiver)?,
name,
}),
Self::Equal { lhs, rhs } => Ok(Self::Equal { lhs, rhs: f(rhs)? }),
Self::GreaterEqual { lhs, rhs } => Ok(Self::GreaterEqual { lhs, rhs: f(rhs)? }),
Self::LessEqual { lhs, rhs } => Ok(Self::LessEqual { lhs, rhs: f(rhs)? }),
Self::NotEqual { lhs, rhs } => Ok(Self::NotEqual { lhs, rhs: f(rhs)? }),
Self::GeneralEqual { lhs, rhs } => Ok(Self::GeneralEqual {
lhs: Box::new(lhs.try_map_tp(f)?),
rhs: Box::new(rhs.try_map_tp(f)?),
}),
Self::GeneralLessEqual { lhs, rhs } => Ok(Self::GeneralLessEqual {
lhs: Box::new(lhs.try_map_tp(f)?),
rhs: Box::new(rhs.try_map_tp(f)?),
}),
Self::GeneralGreaterEqual { lhs, rhs } => Ok(Self::GeneralGreaterEqual {
lhs: Box::new(lhs.try_map_tp(f)?),
rhs: Box::new(rhs.try_map_tp(f)?),
}),
Self::GeneralNotEqual { lhs, rhs } => Ok(Self::GeneralNotEqual {
lhs: Box::new(lhs.try_map_tp(f)?),
rhs: Box::new(rhs.try_map_tp(f)?),
}),
Self::And(lhs, rhs) => Ok(Self::And(
Box::new(lhs.try_map_tp(f)?),
Box::new(rhs.try_map_tp(f)?),
)),
Self::Or(lhs, rhs) => Ok(Self::Or(
Box::new(lhs.try_map_tp(f)?),
Box::new(rhs.try_map_tp(f)?),
)),
Self::Not(pred) => Ok(Self::Not(Box::new(pred.try_map_tp(f)?))),
_ => Ok(self),
}
}
}

View file

@ -1,13 +1,12 @@
use std::cmp::Ordering;
use std::fmt;
use std::ops::{Add, Div, Mul, Neg, Range, RangeInclusive, Sub};
use std::sync::Arc;
use erg_common::consts::DEBUG_MODE;
use erg_common::dict::Dict;
use erg_common::set::Set;
use erg_common::traits::{LimitedDisplay, StructuralEq};
use erg_common::{dict, log, ref_addr_eq, set, Str};
use erg_common::{dict, ref_addr_eq, set, Str};
use erg_parser::ast::ConstLambda;
use erg_parser::token::TokenKind;
@ -19,7 +18,7 @@ use super::free::{
CanbeFree, Constraint, FreeKind, FreeTyParam, FreeTyVar, HasLevel, Level, GENERIC_LEVEL,
};
use super::value::ValueObj;
use super::{ConstSubr, Field, ParamTy, ReplaceTable, UserConstSubr};
use super::{Field, ParamTy, ReplaceTable};
use super::{Type, CONTAINER_OMIT_THRESHOLD};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
@ -683,77 +682,6 @@ impl<'t> TryFrom<&'t TyParam> for &'t FreeTyVar {
}
}
impl TryFrom<TyParam> for ValueObj {
type Error = ();
fn try_from(tp: TyParam) -> Result<Self, ()> {
match tp {
TyParam::List(tps) => {
let mut vals = vec![];
for tp in tps {
vals.push(ValueObj::try_from(tp)?);
}
Ok(ValueObj::List(Arc::from(vals)))
}
TyParam::UnsizedList(elem) => {
let elem = ValueObj::try_from(*elem)?;
Ok(ValueObj::UnsizedList(Box::new(elem)))
}
TyParam::Tuple(tps) => {
let mut vals = vec![];
for tp in tps {
vals.push(ValueObj::try_from(tp)?);
}
Ok(ValueObj::Tuple(Arc::from(vals)))
}
TyParam::Dict(tps) => {
let mut vals = dict! {};
for (k, v) in tps {
vals.insert(ValueObj::try_from(k)?, ValueObj::try_from(v)?);
}
Ok(ValueObj::Dict(vals))
}
TyParam::Record(rec) => {
let mut vals = dict! {};
for (k, v) in rec {
vals.insert(k, ValueObj::try_from(v)?);
}
Ok(ValueObj::Record(vals))
}
TyParam::Set(tps) => {
let mut vals = set! {};
for tp in tps {
vals.insert(ValueObj::try_from(tp)?);
}
Ok(ValueObj::Set(vals))
}
TyParam::DataClass { name, fields } => {
let mut vals = dict! {};
for (k, v) in fields {
vals.insert(k, ValueObj::try_from(v)?);
}
Ok(ValueObj::DataClass { name, fields: vals })
}
TyParam::Lambda(lambda) => {
// TODO: sig_t
let lambda = UserConstSubr::new(
"<lambda>".into(),
lambda.const_.sig.params,
lambda.const_.body,
Type::Never,
);
Ok(ValueObj::Subr(ConstSubr::User(lambda)))
}
TyParam::FreeVar(fv) if fv.is_linked() => ValueObj::try_from(fv.crack().clone()),
TyParam::Type(t) => Ok(ValueObj::builtin_type(*t)),
TyParam::Value(v) => Ok(v),
_ => {
log!(err "Expected value, got {tp}");
Err(())
}
}
}
}
impl TryFrom<TyParam> for Dict<TyParam, TyParam> {
type Error = ();
fn try_from(tp: TyParam) -> Result<Self, ()> {
@ -1197,11 +1125,16 @@ impl TyParam {
base
}
}
Self::FreeVar(_) => set! {},
Self::Type(t) => t.qvars(),
Self::Proj { obj, .. } => obj.qvars(),
Self::ProjCall { obj, args, .. } => args
.iter()
.fold(obj.qvars(), |acc, arg| acc.concat(arg.qvars())),
Self::List(ts) | Self::Tuple(ts) => {
ts.iter().fold(set! {}, |acc, t| acc.concat(t.qvars()))
}
Self::UnsizedList(elem) => elem.qvars(),
Self::Set(ts) => ts.iter().fold(set! {}, |acc, t| acc.concat(t.qvars())),
Self::Dict(ts) => ts.iter().fold(set! {}, |acc, (k, v)| {
acc.concat(k.qvars().concat(v.qvars()))
@ -1217,8 +1150,8 @@ impl TyParam {
Self::BinOp { lhs, rhs, .. } => lhs.qvars().concat(rhs.qvars()),
Self::App { args, .. } => args.iter().fold(set! {}, |acc, p| acc.concat(p.qvars())),
Self::Erased(t) => t.qvars(),
Self::Value(ValueObj::Type(t)) => t.typ().qvars(),
_ => set! {},
Self::Value(val) => val.qvars(),
Self::Mono(_) | Self::Failure => set! {},
}
}
@ -1226,9 +1159,12 @@ impl TyParam {
match self {
Self::FreeVar(fv) if fv.is_unbound() && fv.is_generalized() => true,
Self::FreeVar(fv) if fv.is_linked() => fv.crack().has_qvar(),
Self::FreeVar(_) => false,
Self::Type(t) => t.has_qvar(),
Self::Proj { obj, .. } => obj.has_qvar(),
Self::ProjCall { obj, args, .. } => obj.has_qvar() || args.iter().any(|t| t.has_qvar()),
Self::List(tps) | Self::Tuple(tps) => tps.iter().any(|tp| tp.has_qvar()),
Self::UnsizedList(elem) => elem.has_qvar(),
Self::Set(tps) => tps.iter().any(|tp| tp.has_qvar()),
Self::Dict(tps) => tps.iter().any(|(k, v)| k.has_qvar() || v.has_qvar()),
Self::Record(rec) | Self::DataClass { fields: rec, .. } => {
@ -1239,8 +1175,8 @@ impl TyParam {
Self::BinOp { lhs, rhs, .. } => lhs.has_qvar() || rhs.has_qvar(),
Self::App { args, .. } => args.iter().any(|p| p.has_qvar()),
Self::Erased(t) => t.has_qvar(),
Self::Value(ValueObj::Type(t)) => t.typ().has_qvar(),
_ => false,
Self::Value(val) => val.has_qvar(),
Self::Mono(_) | Self::Failure => false,
}
}
@ -1250,7 +1186,11 @@ impl TyParam {
Self::Type(t) => t.contains_tvar(target),
Self::Erased(t) => t.contains_tvar(target),
Self::Proj { obj, .. } => obj.contains_tvar(target),
Self::ProjCall { obj, args, .. } => {
obj.contains_tvar(target) || args.iter().any(|t| t.contains_tvar(target))
}
Self::List(ts) | Self::Tuple(ts) => ts.iter().any(|t| t.contains_tvar(target)),
Self::UnsizedList(elem) => elem.contains_tvar(target),
Self::Set(ts) => ts.iter().any(|t| t.contains_tvar(target)),
Self::Dict(ts) => ts
.iter()
@ -1262,7 +1202,7 @@ impl TyParam {
Self::UnaryOp { val, .. } => val.contains_tvar(target),
Self::BinOp { lhs, rhs, .. } => lhs.contains_tvar(target) || rhs.contains_tvar(target),
Self::App { args, .. } => args.iter().any(|p| p.contains_tvar(target)),
Self::Value(ValueObj::Type(t)) => t.typ().contains_tvar(target),
Self::Value(val) => val.contains_tvar(target),
_ => false,
}
}
@ -1289,7 +1229,7 @@ impl TyParam {
Self::UnaryOp { val, .. } => val.contains_type(target),
Self::BinOp { lhs, rhs, .. } => lhs.contains_type(target) || rhs.contains_type(target),
Self::App { args, .. } => args.iter().any(|p| p.contains_type(target)),
Self::Value(ValueObj::Type(t)) => t.typ().contains_type(target),
Self::Value(val) => val.contains_type(target),
_ => false,
}
}
@ -1319,7 +1259,7 @@ impl TyParam {
Self::UnaryOp { val, .. } => val.contains_tp(target),
Self::BinOp { lhs, rhs, .. } => lhs.contains_tp(target) || rhs.contains_tp(target),
Self::App { args, .. } => args.iter().any(|p| p.contains_tp(target)),
Self::Value(ValueObj::Type(t)) => t.typ().contains_tp(target),
Self::Value(val) => val.contains_tp(target),
_ => false,
}
}
@ -1381,7 +1321,7 @@ impl TyParam {
.iter()
.any(|(k, v)| k.contains_tp(self) || v.contains_tp(self)),
Self::Type(t) => t.contains_tp(self),
Self::Value(ValueObj::Type(t)) => t.typ().contains_tp(self),
Self::Value(val) => val.contains_tp(self),
Self::Erased(t) => t.contains_tp(self),
_ => false,
}
@ -1418,7 +1358,7 @@ impl TyParam {
Self::BinOp { lhs, rhs, .. } => lhs.has_unbound_var() || rhs.has_unbound_var(),
Self::App { args, .. } => args.iter().any(|p| p.has_unbound_var()),
Self::Erased(t) => t.has_unbound_var(),
Self::Value(ValueObj::Type(t)) => t.typ().has_unbound_var(),
Self::Value(val) => val.has_unbound_var(),
_ => false,
}
}
@ -1451,7 +1391,7 @@ impl TyParam {
}
Self::App { args, .. } => args.iter().any(|p| p.has_undoable_linked_var()),
Self::Erased(t) => t.has_undoable_linked_var(),
Self::Value(ValueObj::Type(t)) => t.typ().has_undoable_linked_var(),
Self::Value(val) => val.has_undoable_linked_var(),
_ => false,
}
}
@ -1531,7 +1471,7 @@ impl TyParam {
if self.qual_name().is_some_and(|n| n == var) {
return to.clone();
}
self.map(|tp| tp.substitute(var, to))
self.map(&mut |tp| tp.substitute(var, to))
}
pub fn replace(self, target: &TyParam, to: &TyParam) -> TyParam {
@ -1546,7 +1486,7 @@ impl TyParam {
match self {
TyParam::Type(t) => TyParam::t(t._replace_tp(target, to)),
TyParam::Value(val) => TyParam::value(val.replace_tp(target, to)),
self_ => self_.map(|tp| tp._replace(target, to)),
self_ => self_.map(&mut |tp| tp._replace(target, to)),
}
}
@ -1560,10 +1500,8 @@ impl TyParam {
}
Self::Type(t) => Self::t(t._replace(target, to)),
Self::Erased(t) => Self::erased(t._replace(target, to)),
Self::Value(ValueObj::Type(t)) => {
Self::value(ValueObj::Type(t.mapped_t(|t| t._replace(target, to))))
}
_ => self.map(|tp| tp.replace_t(target, to)),
Self::Value(val) => Self::Value(val.replace_t(target, to)),
_ => self.map(&mut |tp| tp.replace_t(target, to)),
}
}
@ -1594,11 +1532,21 @@ impl TyParam {
if self.addr_eq(to) {
return;
}
if DEBUG_MODE && self.level() == Some(GENERIC_LEVEL) {
panic!("{self} is fixed");
if self.level() == Some(GENERIC_LEVEL) {
if DEBUG_MODE {
panic!("{self} is fixed");
}
return;
}
match self {
Self::FreeVar(fv) => fv.link(to),
Self::FreeVar(fv) => {
if to.contains_tp(self) {
let to = to.clone().eliminate_recursion(self);
fv.link(&to);
} else {
fv.link(to);
}
}
Self::Type(t) => {
if let Ok(to) = <&Type>::try_from(to) {
t.destructive_link(to);
@ -1625,7 +1573,28 @@ impl TyParam {
return;
}
match self {
Self::FreeVar(fv) => fv.undoable_link(to),
Self::FreeVar(fv) => {
if to.contains_tp(self) {
let to = to.clone().eliminate_recursion(self);
fv.undoable_link(&to);
} else {
fv.undoable_link(to);
}
}
Self::Type(t) => {
if let Ok(to) = <&Type>::try_from(to) {
t.undoable_link(to, list);
} else {
panic!("{to} is not a type");
}
}
Self::Value(ValueObj::Type(t)) => {
if let Ok(to) = <&Type>::try_from(to) {
t.typ().undoable_link(to, list);
} else {
panic!("{to} is not a type");
}
}
_ => panic!("{self} is not a free variable"),
}
}
@ -1695,7 +1664,7 @@ impl TyParam {
match self {
Self::FreeVar(fv) if fv.is_linked() => fv.crack().typarams(),
Self::Type(t) => t.typarams(),
Self::Value(ValueObj::Type(t)) => t.typ().typarams(),
Self::Value(val) => val.typarams(),
Self::App { args, .. } => args.clone(),
_ => vec![],
}
@ -1705,7 +1674,7 @@ impl TyParam {
match self {
Self::FreeVar(fv) if fv.is_linked() => fv.crack().contained_ts(),
Self::Type(t) => t.contained_ts(),
Self::Value(ValueObj::Type(t)) => t.typ().contained_ts(),
Self::Value(val) => val.contained_ts(),
Self::App { args, .. } => args
.iter()
.fold(set! {}, |acc, p| acc.concat(p.contained_ts())),
@ -1723,8 +1692,9 @@ impl TyParam {
Self::FreeVar(fv) if fv.is_generalized() => {
fv.update_init();
}
Self::FreeVar(_) => {}
Self::Type(t) => t.dereference(),
Self::Value(ValueObj::Type(t)) => t.typ_mut().dereference(),
Self::Value(val) => val.dereference(),
Self::App { args, .. } => {
for arg in args {
arg.dereference();
@ -1780,7 +1750,7 @@ impl TyParam {
rhs.dereference();
}
Self::Erased(t) => t.dereference(),
_ => {}
Self::Mono(_) | Self::Failure => {}
}
}
@ -1807,6 +1777,7 @@ impl TyParam {
match self {
Self::FreeVar(fv) if fv.is_linked() => fv.crack().variables(),
Self::FreeVar(fv) if fv.get_type().is_some() => fv.get_type().unwrap().variables(),
Self::FreeVar(_) => set! {},
Self::Mono(name) => set! { name.clone() },
Self::App { name, args } => {
let mut set = set! { name.clone() };
@ -1841,14 +1812,21 @@ impl TyParam {
set
}
Self::Type(t) | Self::Erased(t) => t.variables(),
Self::Value(ValueObj::Type(t)) => t.typ().variables(),
_ => set! {},
Self::Value(val) => val.variables(),
Self::Failure => set! {},
}
}
pub fn map(self, f: impl Fn(TyParam) -> TyParam) -> TyParam {
/// For recursive function
pub fn map(self, f: &mut impl FnMut(TyParam) -> TyParam) -> TyParam {
match self {
TyParam::FreeVar(fv) if fv.is_linked() => f(fv.unwrap_linked()),
TyParam::FreeVar(fv) if fv.get_type().is_some() => {
let typ = fv.get_type().unwrap();
fv.update_type(typ.map_tp(f));
TyParam::FreeVar(fv)
}
TyParam::FreeVar(_) => self,
TyParam::App { name, args } => {
let new_args = args.into_iter().map(f).collect::<Vec<_>>();
TyParam::app(name, new_args)
@ -1889,17 +1867,87 @@ impl TyParam {
obj: Box::new(f(*obj)),
attr,
},
TyParam::ProjCall { obj, attr, args } => TyParam::ProjCall {
obj: Box::new(f(*obj)),
attr,
args: args.into_iter().map(f).collect::<Vec<_>>(),
},
TyParam::Value(val) => TyParam::Value(val.map_tp(f)),
TyParam::Type(t) => TyParam::t(t.map_tp(f)),
TyParam::Erased(t) => TyParam::erased(t.map_tp(f)),
TyParam::Mono(_) | TyParam::Failure => self,
}
}
pub fn map_t(self, f: &mut impl FnMut(Type) -> Type) -> TyParam {
match self {
TyParam::FreeVar(fv) if fv.is_linked() => fv.unwrap_linked().map_t(f),
TyParam::FreeVar(fv) if fv.get_type().is_some() => {
let typ = fv.get_type().unwrap();
fv.update_type(f(typ));
TyParam::FreeVar(fv)
}
TyParam::FreeVar(_) => self,
TyParam::App { name, args } => {
let new_args = args.into_iter().map(|tp| tp.map_t(f)).collect::<Vec<_>>();
TyParam::app(name, new_args)
}
TyParam::BinOp { op, lhs, rhs } => TyParam::bin(op, lhs.map_t(f), rhs.map_t(f)),
TyParam::UnaryOp { op, val } => TyParam::unary(op, val.map_t(f)),
TyParam::UnsizedList(elem) => TyParam::unsized_list(elem.map_t(f)),
TyParam::List(tps) => TyParam::List(tps.into_iter().map(|tp| tp.map_t(f)).collect()),
TyParam::Tuple(tps) => TyParam::Tuple(tps.into_iter().map(|tp| tp.map_t(f)).collect()),
TyParam::Set(tps) => TyParam::Set(tps.into_iter().map(|tp| tp.map_t(f)).collect()),
TyParam::Dict(tps) => {
let new_tps = tps
.into_iter()
.map(|(k, v)| (k.map_t(f), v.map_t(f)))
.collect();
TyParam::Dict(new_tps)
}
TyParam::Record(rec) => {
let new_rec = rec.into_iter().map(|(k, v)| (k, v.map_t(f))).collect();
TyParam::Record(new_rec)
}
TyParam::DataClass { name, fields } => {
let new_fields = fields.into_iter().map(|(k, v)| (k, v.map_t(f))).collect();
TyParam::DataClass {
name,
fields: new_fields,
}
}
TyParam::Lambda(lambda) => {
let new_body = lambda.body.into_iter().map(|tp| tp.map_t(f)).collect();
TyParam::Lambda(TyParamLambda {
body: new_body,
..lambda
})
}
TyParam::Proj { obj, attr } => TyParam::Proj {
obj: Box::new(obj.map_t(f)),
attr,
},
TyParam::ProjCall { obj, attr, args } => {
let new_args = args.into_iter().map(&f).collect::<Vec<_>>();
let new_args = args.into_iter().map(|tp| tp.map_t(f)).collect::<Vec<_>>();
TyParam::ProjCall {
obj: Box::new(f(*obj)),
obj: Box::new(obj.map_t(f)),
attr,
args: new_args,
}
}
self_ => self_,
TyParam::Value(val) => TyParam::Value(val.map_t(f)),
TyParam::Type(t) => TyParam::t(f(*t)),
TyParam::Erased(t) => TyParam::erased(f(*t)),
TyParam::Mono(_) | TyParam::Failure => self,
}
}
pub fn eliminate_recursion(self, target: &TyParam) -> Self {
if self.addr_eq(target) {
return Self::Failure;
}
self.map(&mut |tp| tp.eliminate_recursion(target))
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]

View file

@ -7,6 +7,7 @@ use std::hash::{Hash, Hasher};
use std::ops::Neg;
use std::sync::Arc;
use erg_common::consts::DEBUG_MODE;
use erg_common::dict::Dict;
use erg_common::error::{ErrorCore, ErrorKind, Location};
use erg_common::fresh::FRESH_GEN;
@ -15,7 +16,7 @@ use erg_common::python_util::PythonVersion;
use erg_common::serialize::*;
use erg_common::set::Set;
use erg_common::traits::LimitedDisplay;
use erg_common::{dict, fmt_iter, impl_display_from_debug, log, switch_lang};
use erg_common::{dict, fmt_iter, log, switch_lang};
use erg_common::{ArcArray, Str};
use erg_parser::ast::{ConstArgs, ConstExpr};
@ -26,6 +27,7 @@ use self::value_set::inner_class;
use super::codeobj::{tuple_into_bytes, CodeObj};
use super::constructors::{dict_t, list_t, refinement, set_t, tuple_t, unsized_list_t};
use super::free::{Constraint, FreeTyVar};
use super::typaram::{OpKind, TyParam};
use super::{ConstSubr, Field, HasType, Predicate, Type};
use super::{CONTAINER_OMIT_THRESHOLD, STR_OMIT_THRESHOLD};
@ -220,15 +222,27 @@ pub enum GenTypeObj {
impl fmt::Display for GenTypeObj {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "<{}>", self.typ())
if DEBUG_MODE {
write!(f, "<")?;
}
self.typ().fmt(f)?;
if DEBUG_MODE {
write!(f, ">")?;
}
Ok(())
}
}
impl LimitedDisplay for GenTypeObj {
fn limited_fmt<W: std::fmt::Write>(&self, f: &mut W, limit: isize) -> std::fmt::Result {
write!(f, "<")?;
if DEBUG_MODE {
write!(f, "<")?;
}
self.typ().limited_fmt(f, limit)?;
write!(f, ">")
if DEBUG_MODE {
write!(f, ">")?;
}
Ok(())
}
}
@ -373,11 +387,23 @@ impl GenTypeObj {
}
pub fn map_t(&mut self, f: impl FnOnce(Type) -> Type) {
*self.typ_mut() = f(self.typ().clone());
*self.typ_mut() = f(std::mem::take(self.typ_mut()));
}
pub fn map_tp(&mut self, f: &mut impl FnMut(TyParam) -> TyParam) {
*self.typ_mut() = std::mem::take(self.typ_mut()).map_tp(f);
}
pub fn try_map_t<E>(&mut self, f: impl FnOnce(Type) -> Result<Type, E>) -> Result<(), E> {
*self.typ_mut() = f(self.typ().clone())?;
*self.typ_mut() = f(std::mem::take(self.typ_mut()))?;
Ok(())
}
pub fn try_map_tp<E>(
&mut self,
f: &mut impl FnMut(TyParam) -> Result<TyParam, E>,
) -> Result<(), E> {
*self.typ_mut() = std::mem::take(self.typ_mut()).try_map_tp(f)?;
Ok(())
}
}
@ -410,7 +436,7 @@ impl LimitedDisplay for TypeObj {
fn limited_fmt<W: std::fmt::Write>(&self, f: &mut W, limit: isize) -> std::fmt::Result {
match self {
TypeObj::Builtin { t, .. } => {
if cfg!(feature = "debug") {
if DEBUG_MODE {
write!(f, "<type ")?;
t.limited_fmt(f, limit - 1)?;
write!(f, ">")
@ -419,7 +445,7 @@ impl LimitedDisplay for TypeObj {
}
}
TypeObj::Generated(t) => {
if cfg!(feature = "debug") {
if DEBUG_MODE {
write!(f, "<user type ")?;
t.limited_fmt(f, limit - 1)?;
write!(f, ">")
@ -483,25 +509,66 @@ impl TypeObj {
pub fn map_t(&mut self, f: impl FnOnce(Type) -> Type) {
match self {
TypeObj::Builtin { t, .. } => *t = f(t.clone()),
TypeObj::Builtin { t, .. } => *t = f(std::mem::take(t)),
TypeObj::Generated(t) => t.map_t(f),
}
}
pub fn map_tp(&mut self, f: &mut impl FnMut(TyParam) -> TyParam) {
match self {
TypeObj::Builtin { t, .. } => *t = std::mem::take(t).map_tp(f),
TypeObj::Generated(t) => t.map_tp(f),
}
}
pub fn mapped_t(mut self, f: impl FnOnce(Type) -> Type) -> Self {
self.map_t(f);
self
}
pub fn try_map_t<E>(&mut self, f: impl FnOnce(Type) -> Result<Type, E>) -> Result<(), E> {
pub fn mapped_tp(mut self, f: &mut impl FnMut(TyParam) -> TyParam) -> Self {
self.map_tp(f);
self
}
pub fn try_map_t<E>(&mut self, f: &mut impl FnMut(Type) -> Result<Type, E>) -> Result<(), E> {
match self {
TypeObj::Builtin { t, .. } => {
*t = f(t.clone())?;
*t = f(std::mem::take(t))?;
Ok(())
}
TypeObj::Generated(t) => t.try_map_t(f),
}
}
pub fn try_mapped_t<E>(
mut self,
f: &mut impl FnMut(Type) -> Result<Type, E>,
) -> Result<Self, E> {
self.try_map_t(f)?;
Ok(self)
}
pub fn try_map_tp<E>(
&mut self,
f: &mut impl FnMut(TyParam) -> Result<TyParam, E>,
) -> Result<(), E> {
match self {
TypeObj::Builtin { t, .. } => {
*t = std::mem::take(t).try_map_tp(f)?;
Ok(())
}
TypeObj::Generated(t) => t.try_map_tp(f),
}
}
pub fn try_mapped_tp<E>(
mut self,
f: &mut impl FnMut(TyParam) -> Result<TyParam, E>,
) -> Result<Self, E> {
self.try_map_tp(f)?;
Ok(self)
}
}
/// 値オブジェクト
@ -536,18 +603,36 @@ pub enum ValueObj {
Failure, // placeholder for illegal values
}
#[macro_export]
macro_rules! mono_value_pattern {
() => {
$crate::ty::ValueObj::Int(_)
| $crate::ty::ValueObj::Nat(_)
| $crate::ty::ValueObj::Float(_)
| $crate::ty::ValueObj::Inf
| $crate::ty::ValueObj::NegInf
| $crate::ty::ValueObj::Bool(_)
| $crate::ty::ValueObj::Str(_)
| $crate::ty::ValueObj::Code(_)
| $crate::ty::ValueObj::None
| $crate::ty::ValueObj::NotImplemented
| $crate::ty::ValueObj::Ellipsis
| $crate::ty::ValueObj::Failure
};
}
impl fmt::Debug for ValueObj {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Int(i) => {
if cfg!(feature = "debug") {
if DEBUG_MODE {
write!(f, "Int({i})")
} else {
write!(f, "{i}")
}
}
Self::Nat(n) => {
if cfg!(feature = "debug") {
if DEBUG_MODE {
write!(f, "Nat({n})")
} else {
write!(f, "{n}")
@ -560,7 +645,7 @@ impl fmt::Debug for ValueObj {
} else {
write!(f, "{fl}")?;
}
if cfg!(feature = "debug") {
if DEBUG_MODE {
write!(f, "f64")?;
}
Ok(())
@ -608,8 +693,8 @@ impl fmt::Debug for ValueObj {
}
write!(f, "}}")
}
Self::Subr(subr) => write!(f, "{subr}"),
Self::Type(t) => write!(f, "{t}"),
Self::Subr(subr) => subr.fmt(f),
Self::Type(t) => t.fmt(f),
Self::None => write!(f, "None"),
Self::Ellipsis => write!(f, "Ellipsis"),
Self::NotImplemented => write!(f, "NotImplemented"),
@ -620,7 +705,89 @@ impl fmt::Debug for ValueObj {
}
}
impl_display_from_debug!(ValueObj);
impl fmt::Display for ValueObj {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Int(i) => {
if DEBUG_MODE {
write!(f, "Int({i})")
} else {
write!(f, "{i}")
}
}
Self::Nat(n) => {
if DEBUG_MODE {
write!(f, "Nat({n})")
} else {
write!(f, "{n}")
}
}
Self::Float(fl) => {
// In Rust, .0 is shown omitted.
if fl.fract() < 1e-10 {
write!(f, "{fl:.1}")?;
} else {
write!(f, "{fl}")?;
}
if DEBUG_MODE {
write!(f, "f64")?;
}
Ok(())
}
Self::Str(s) => write!(f, "\"{}\"", s.escape()),
Self::Bool(b) => {
if *b {
write!(f, "True")
} else {
write!(f, "False")
}
}
Self::List(lis) => write!(f, "[{}]", fmt_iter(lis.iter())),
Self::UnsizedList(elem) => write!(f, "[{elem}; _]"),
Self::Dict(dict) => {
write!(f, "{{")?;
for (i, (k, v)) in dict.iter().enumerate() {
if i != 0 {
write!(f, ", ")?;
}
write!(f, "{k}: {v}")?;
}
write!(f, "}}")
}
Self::Tuple(tup) => write!(f, "({})", fmt_iter(tup.iter())),
Self::Set(st) => write!(f, "{{{}}}", fmt_iter(st.iter())),
Self::Code(code) => write!(f, "{code}"),
Self::Record(rec) => {
write!(f, "{{")?;
for (i, (k, v)) in rec.iter().enumerate() {
if i != 0 {
write!(f, "; ")?;
}
write!(f, "{k} = {v}")?;
}
write!(f, "}}")
}
Self::DataClass { name, fields } => {
write!(f, "{name} {{")?;
for (i, (k, v)) in fields.iter().enumerate() {
if i != 0 {
write!(f, "; ")?;
}
write!(f, "{k} = {v}")?;
}
write!(f, "}}")
}
Self::Subr(subr) => subr.fmt(f),
Self::Type(t) => t.fmt(f),
Self::None => write!(f, "None"),
Self::Ellipsis => write!(f, "Ellipsis"),
Self::NotImplemented => write!(f, "NotImplemented"),
Self::NegInf => write!(f, "-Inf"),
Self::Inf => write!(f, "Inf"),
Self::Failure => write!(f, "<failure>"),
}
}
}
impl LimitedDisplay for ValueObj {
fn limited_fmt<W: std::fmt::Write>(&self, f: &mut W, limit: isize) -> std::fmt::Result {
@ -1610,98 +1777,149 @@ impl ValueObj {
}
}
pub fn replace_t(self, target: &Type, to: &Type) -> Self {
pub fn map_t(self, f: &mut impl FnMut(Type) -> Type) -> Self {
match self {
ValueObj::Type(obj) => ValueObj::Type(obj.mapped_t(|t| t._replace(target, to))),
ValueObj::List(lis) => ValueObj::List(
lis.iter()
.map(|v| v.clone().replace_t(target, to))
.collect(),
),
ValueObj::Tuple(tup) => ValueObj::Tuple(
tup.iter()
.map(|v| v.clone().replace_t(target, to))
.collect(),
),
ValueObj::Set(st) => {
ValueObj::Set(st.iter().map(|v| v.clone().replace_t(target, to)).collect())
ValueObj::Type(obj) => ValueObj::Type(obj.mapped_t(f)),
ValueObj::List(lis) => ValueObj::List(lis.iter().map(|v| v.clone().map_t(f)).collect()),
ValueObj::Tuple(tup) => {
ValueObj::Tuple(tup.iter().map(|v| v.clone().map_t(f)).collect())
}
ValueObj::Set(st) => ValueObj::Set(st.into_iter().map(|v| v.map_t(f)).collect()),
ValueObj::Dict(dict) => ValueObj::Dict(
dict.iter()
.map(|(k, v)| {
(
k.clone().replace_t(target, to),
v.clone().replace_t(target, to),
)
})
.collect(),
),
ValueObj::Record(rec) => ValueObj::Record(
rec.iter()
.map(|(k, v)| (k.clone(), v.clone().replace_t(target, to)))
dict.into_iter()
.map(|(k, v)| (k.map_t(f), v.map_t(f)))
.collect(),
),
ValueObj::Record(rec) => {
ValueObj::Record(rec.into_iter().map(|(k, v)| (k, v.map_t(f))).collect())
}
ValueObj::DataClass { name, fields } => ValueObj::DataClass {
name,
fields: fields
.iter()
.map(|(k, v)| (k.clone(), v.clone().replace_t(target, to)))
.collect(),
fields: fields.into_iter().map(|(k, v)| (k, v.map_t(f))).collect(),
},
ValueObj::UnsizedList(elem) => {
ValueObj::UnsizedList(Box::new(elem.clone().replace_t(target, to)))
}
ValueObj::UnsizedList(elem) => ValueObj::UnsizedList(Box::new(elem.map_t(f))),
self_ => self_,
}
}
pub fn replace_tp(self, target: &TyParam, to: &TyParam) -> Self {
pub fn try_map_t<E>(self, f: &mut impl FnMut(Type) -> Result<Type, E>) -> Result<Self, E> {
match self {
ValueObj::Type(obj) => ValueObj::Type(obj.mapped_t(|t| t._replace_tp(target, to))),
ValueObj::List(lis) => ValueObj::List(
ValueObj::Type(obj) => Ok(ValueObj::Type(obj.try_mapped_t(f)?)),
ValueObj::List(lis) => Ok(ValueObj::List(
lis.iter()
.map(|v| v.clone().replace_tp(target, to))
.collect(),
),
ValueObj::Tuple(tup) => ValueObj::Tuple(
.map(|v| v.clone().try_map_t(f))
.collect::<Result<Arc<_>, _>>()?,
)),
ValueObj::Tuple(tup) => Ok(ValueObj::Tuple(
tup.iter()
.map(|v| v.clone().replace_tp(target, to))
.collect(),
),
ValueObj::Set(st) => ValueObj::Set(
st.iter()
.map(|v| v.clone().replace_tp(target, to))
.collect(),
),
ValueObj::Dict(dict) => ValueObj::Dict(
dict.iter()
.map(|(k, v)| {
(
k.clone().replace_tp(target, to),
v.clone().replace_tp(target, to),
)
})
.collect(),
),
ValueObj::Record(rec) => ValueObj::Record(
rec.iter()
.map(|(k, v)| (k.clone(), v.clone().replace_tp(target, to)))
.collect(),
),
ValueObj::DataClass { name, fields } => ValueObj::DataClass {
.map(|v| v.clone().try_map_t(f))
.collect::<Result<Arc<_>, _>>()?,
)),
ValueObj::Set(st) => Ok(ValueObj::Set(
st.into_iter()
.map(|v| v.try_map_t(f))
.collect::<Result<Set<_>, _>>()?,
)),
ValueObj::Dict(dict) => Ok(ValueObj::Dict(
dict.into_iter()
.map(|(k, v)| Ok((k.try_map_t(f)?, v.try_map_t(f)?)))
.collect::<Result<Dict<_, _>, _>>()?,
)),
ValueObj::Record(rec) => Ok(ValueObj::Record(
rec.into_iter()
.map(|(k, v)| Ok((k, v.try_map_t(f)?)))
.collect::<Result<Dict<_, _>, _>>()?,
)),
ValueObj::DataClass { name, fields } => Ok(ValueObj::DataClass {
name,
fields: fields
.iter()
.map(|(k, v)| (k.clone(), v.clone().replace_tp(target, to)))
.collect(),
},
ValueObj::UnsizedList(elem) => {
ValueObj::UnsizedList(Box::new(elem.clone().replace_tp(target, to)))
.into_iter()
.map(|(k, v)| Ok((k, v.try_map_t(f)?)))
.collect::<Result<Dict<_, _>, _>>()?,
}),
ValueObj::UnsizedList(elem) => Ok(ValueObj::UnsizedList(Box::new(elem.try_map_t(f)?))),
self_ => Ok(self_),
}
}
pub fn map_tp(self, f: &mut impl FnMut(TyParam) -> TyParam) -> Self {
match self {
ValueObj::Type(obj) => ValueObj::Type(obj.mapped_tp(f)),
ValueObj::List(lis) => {
ValueObj::List(lis.iter().map(|v| v.clone().map_tp(f)).collect())
}
ValueObj::Tuple(tup) => {
ValueObj::Tuple(tup.iter().map(|v| v.clone().map_tp(f)).collect())
}
ValueObj::Set(st) => ValueObj::Set(st.into_iter().map(|v| v.map_tp(f)).collect()),
ValueObj::Dict(dict) => ValueObj::Dict(
dict.into_iter()
.map(|(k, v)| (k.map_tp(f), v.map_tp(f)))
.collect(),
),
ValueObj::Record(rec) => {
ValueObj::Record(rec.into_iter().map(|(k, v)| (k, v.map_tp(f))).collect())
}
ValueObj::DataClass { name, fields } => ValueObj::DataClass {
name,
fields: fields.into_iter().map(|(k, v)| (k, v.map_tp(f))).collect(),
},
ValueObj::UnsizedList(elem) => ValueObj::UnsizedList(Box::new(elem.map_tp(f))),
self_ => self_,
}
}
pub fn try_map_tp<E>(
self,
f: &mut impl FnMut(TyParam) -> Result<TyParam, E>,
) -> Result<Self, E> {
match self {
ValueObj::Type(obj) => Ok(ValueObj::Type(obj.try_mapped_tp(f)?)),
ValueObj::List(lis) => Ok(ValueObj::List(
lis.iter()
.map(|v| v.clone().try_map_tp(f))
.collect::<Result<Arc<_>, _>>()?,
)),
ValueObj::Tuple(tup) => Ok(ValueObj::Tuple(
tup.iter()
.map(|v| v.clone().try_map_tp(f))
.collect::<Result<Arc<_>, _>>()?,
)),
ValueObj::Set(st) => Ok(ValueObj::Set(
st.into_iter()
.map(|v| v.try_map_tp(f))
.collect::<Result<Set<_>, _>>()?,
)),
ValueObj::Dict(dict) => Ok(ValueObj::Dict(
dict.into_iter()
.map(|(k, v)| Ok((k.try_map_tp(f)?, v.try_map_tp(f)?)))
.collect::<Result<Dict<_, _>, _>>()?,
)),
ValueObj::Record(rec) => Ok(ValueObj::Record(
rec.into_iter()
.map(|(k, v)| Ok((k, v.try_map_tp(f)?)))
.collect::<Result<Dict<_, _>, _>>()?,
)),
ValueObj::DataClass { name, fields } => Ok(ValueObj::DataClass {
name,
fields: fields
.into_iter()
.map(|(k, v)| Ok((k, v.try_map_tp(f)?)))
.collect::<Result<Dict<_, _>, _>>()?,
}),
ValueObj::UnsizedList(elem) => Ok(ValueObj::UnsizedList(Box::new(elem.try_map_tp(f)?))),
self_ => Ok(self_),
}
}
pub fn replace_t(self, target: &Type, to: &Type) -> Self {
self.map_t(&mut |t| t._replace(target, to))
}
pub fn replace_tp(self, target: &TyParam, to: &TyParam) -> Self {
self.map_t(&mut |t| t._replace_tp(target, to))
}
pub fn contains(&self, val: &ValueObj) -> bool {
match self {
ValueObj::List(lis) => lis.iter().any(|v| v.contains(val)),
@ -1714,6 +1932,165 @@ impl ValueObj {
_ => self == val,
}
}
pub fn contains_type(&self, target: &Type) -> bool {
match self {
Self::Type(t) => t.typ().contains_type(target),
Self::List(ts) | Self::Tuple(ts) => ts.iter().any(|t| t.contains_type(target)),
Self::UnsizedList(elem) => elem.contains_type(target),
Self::Set(ts) => ts.iter().any(|t| t.contains_type(target)),
Self::Dict(ts) => ts
.iter()
.any(|(k, v)| k.contains_type(target) || v.contains_type(target)),
Self::Record(rec) | Self::DataClass { fields: rec, .. } => {
rec.iter().any(|(_, tp)| tp.contains_type(target))
}
_ => false,
}
}
pub fn contains_tp(&self, target: &TyParam) -> bool {
match self {
Self::Type(t) => t.typ().contains_tp(target),
Self::List(ts) | Self::Tuple(ts) => ts.iter().any(|t| t.contains_tp(target)),
Self::UnsizedList(elem) => elem.contains_tp(target),
Self::Set(ts) => ts.iter().any(|t| t.contains_tp(target)),
Self::Dict(ts) => ts
.iter()
.any(|(k, v)| k.contains_tp(target) || v.contains_tp(target)),
Self::Record(rec) | Self::DataClass { fields: rec, .. } => {
rec.iter().any(|(_, tp)| tp.contains_tp(target))
}
_ => false,
}
}
pub fn has_unbound_var(&self) -> bool {
match self {
Self::Type(t) => t.typ().has_unbound_var(),
Self::List(ts) | Self::Tuple(ts) => ts.iter().any(|t| t.has_unbound_var()),
Self::UnsizedList(elem) => elem.has_unbound_var(),
Self::Set(ts) => ts.iter().any(|t| t.has_unbound_var()),
Self::Dict(ts) => ts
.iter()
.any(|(k, v)| k.has_unbound_var() || v.has_unbound_var()),
Self::Record(rec) | Self::DataClass { fields: rec, .. } => {
rec.iter().any(|(_, tp)| tp.has_unbound_var())
}
_ => false,
}
}
pub fn has_undoable_linked_var(&self) -> bool {
match self {
Self::Type(t) => t.typ().has_undoable_linked_var(),
Self::List(ts) | Self::Tuple(ts) => ts.iter().any(|t| t.has_undoable_linked_var()),
Self::UnsizedList(elem) => elem.has_undoable_linked_var(),
Self::Set(ts) => ts.iter().any(|t| t.has_undoable_linked_var()),
Self::Dict(ts) => ts
.iter()
.any(|(k, v)| k.has_undoable_linked_var() || v.has_undoable_linked_var()),
Self::Record(rec) | Self::DataClass { fields: rec, .. } => {
rec.iter().any(|(_, tp)| tp.has_undoable_linked_var())
}
_ => false,
}
}
pub fn has_qvar(&self) -> bool {
match self {
Self::Type(t) => t.typ().has_qvar(),
Self::List(ts) | Self::Tuple(ts) => ts.iter().any(|t| t.has_qvar()),
Self::UnsizedList(elem) => elem.has_qvar(),
Self::Set(ts) => ts.iter().any(|t| t.has_qvar()),
Self::Dict(ts) => ts.iter().any(|(k, v)| k.has_qvar() || v.has_qvar()),
Self::Record(rec) | Self::DataClass { fields: rec, .. } => {
rec.iter().any(|(_, tp)| tp.has_qvar())
}
_ => false,
}
}
pub fn contains_tvar(&self, target: &FreeTyVar) -> bool {
match self {
Self::Type(t) => t.typ().contains_tvar(target),
Self::List(ts) | Self::Tuple(ts) => ts.iter().any(|t| t.contains_tvar(target)),
Self::UnsizedList(elem) => elem.contains_tvar(target),
Self::Set(ts) => ts.iter().any(|t| t.contains_tvar(target)),
Self::Dict(ts) => ts
.iter()
.any(|(k, v)| k.contains_tvar(target) || v.contains_tvar(target)),
Self::Record(rec) | Self::DataClass { fields: rec, .. } => {
rec.iter().any(|(_, tp)| tp.contains_tvar(target))
}
_ => false,
}
}
pub fn qvars(&self) -> Set<(Str, Constraint)> {
match self {
Self::Type(t) => t.typ().qvars(),
Self::List(ts) | Self::Tuple(ts) => ts.iter().flat_map(|t| t.qvars()).collect(),
Self::UnsizedList(elem) => elem.qvars(),
Self::Set(ts) => ts.iter().flat_map(|t| t.qvars()).collect(),
Self::Dict(ts) => ts
.iter()
.flat_map(|(k, v)| k.qvars().concat(v.qvars()))
.collect(),
Self::Record(rec) | Self::DataClass { fields: rec, .. } => {
rec.iter().flat_map(|(_, tp)| tp.qvars()).collect()
}
_ => Set::new(),
}
}
pub fn typarams(&self) -> Vec<TyParam> {
match self {
Self::Type(t) => t.typ().typarams(),
_ => Vec::new(),
}
}
pub fn contained_ts(&self) -> Set<Type> {
match self {
Self::Type(t) => t.typ().contained_ts(),
Self::List(ts) | Self::Tuple(ts) => ts.iter().flat_map(|t| t.contained_ts()).collect(),
Self::UnsizedList(elem) => elem.contained_ts(),
Self::Set(ts) => ts.iter().flat_map(|t| t.contained_ts()).collect(),
Self::Dict(ts) => ts
.iter()
.flat_map(|(k, v)| k.contained_ts().concat(v.contained_ts()))
.collect(),
Self::Record(rec) | Self::DataClass { fields: rec, .. } => {
rec.iter().flat_map(|(_, tp)| tp.contained_ts()).collect()
}
_ => Set::new(),
}
}
pub fn dereference(&mut self) {
*self = std::mem::take(self).map_t(&mut |mut t| {
t.dereference();
t
});
}
pub fn variables(&self) -> Set<Str> {
match self {
Self::Type(t) => t.typ().variables(),
Self::List(ts) | Self::Tuple(ts) => ts.iter().flat_map(|t| t.variables()).collect(),
Self::UnsizedList(elem) => elem.variables(),
Self::Set(ts) => ts.iter().flat_map(|t| t.variables()).collect(),
Self::Dict(ts) => ts
.iter()
.flat_map(|(k, v)| k.variables().concat(v.variables()))
.collect(),
Self::Record(rec) | Self::DataClass { fields: rec, .. } => {
rec.iter().flat_map(|(_, tp)| tp.variables()).collect()
}
_ => Set::new(),
}
}
}
pub mod value_set {