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

@ -528,6 +528,14 @@ macro_rules! log {
} }
}}; }};
(backtrace) => {{
if cfg!(feature = "debug") {
use $crate::style::*;
$crate::debug_info!();
println!("\n{}", std::backtrace::Backtrace::capture());
}
}};
(caller) => {{ (caller) => {{
if cfg!(feature = "debug") { if cfg!(feature = "debug") {
use $crate::style::*; use $crate::style::*;
@ -592,3 +600,43 @@ macro_rules! fmt_dbg {
} }
}; };
} }
use std::sync::atomic::AtomicU32;
pub struct RecursionCounter {
count: &'static AtomicU32,
}
impl Drop for RecursionCounter {
fn drop(&mut self) {
self.count
.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
}
}
impl RecursionCounter {
pub fn new(count: &'static AtomicU32) -> Self {
count.fetch_sub(1, std::sync::atomic::Ordering::Relaxed);
Self { count }
}
pub fn limit_reached(&self) -> bool {
self.count.load(std::sync::atomic::Ordering::Relaxed) == 0
}
}
#[macro_export]
macro_rules! set_recursion_limit {
($returns:expr, $limit:expr) => {
use std::sync::atomic::AtomicU32;
static COUNTER: AtomicU32 = AtomicU32::new($limit);
let counter = $crate::macros::RecursionCounter::new(&COUNTER);
if counter.limit_reached() {
$crate::log!(err "Recursion limit reached");
$crate::log!(backtrace);
return $returns;
}
};
}

View file

@ -13,7 +13,7 @@ use std::time::{Duration, SystemTime};
use erg_common::config::ErgMode; use erg_common::config::ErgMode;
use erg_common::config::ErgConfig; 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::debug_power_assert;
use erg_common::dict::Dict; use erg_common::dict::Dict;
use erg_common::env::is_std_decl_path; use erg_common::env::is_std_decl_path;
@ -155,6 +155,18 @@ pub struct ResolveError {
pub type ResolveResult<T> = Result<T, Vec<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. /// Resolve dependencies and build a package.
/// This object should be a singleton. /// This object should be a singleton.
/// ///
@ -171,7 +183,7 @@ pub struct GenericPackageBuilder<
cyclic: Vec<NormalizedPathBuf>, cyclic: Vec<NormalizedPathBuf>,
// key: inlined module, value: inliner module (child) // key: inlined module, value: inliner module (child)
inlines: Dict<NormalizedPathBuf, NormalizedPathBuf>, inlines: Dict<NormalizedPathBuf, NormalizedPathBuf>,
asts: Dict<NormalizedPathBuf, (Str, AST)>, asts: Dict<NormalizedPathBuf, ASTEntry>,
parse_errors: ErrorArtifact, parse_errors: ErrorArtifact,
_parser: PhantomData<fn() -> ASTBuilder>, _parser: PhantomData<fn() -> ASTBuilder>,
} }
@ -725,9 +737,10 @@ impl<ASTBuilder: ASTBuildable, HIRBuilder: Buildable>
|| self.asts.contains_key(&root_import_path) || self.asts.contains_key(&root_import_path)
{ {
// pass // 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 _ = 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()); debug_assert!(prev.is_none());
} }
} }
@ -746,7 +759,7 @@ impl<ASTBuilder: ASTBuildable, HIRBuilder: Buildable>
{ {
return Ok(()); return Ok(());
} }
let Ok(mut ast) = self.parse(&import_path) else { let Some(mut ast) = self.parse(&import_path) else {
return Ok(()); return Ok(());
}; };
if let Err(mut errs) = self.resolve(&mut ast, &import_cfg) { if let Err(mut errs) = self.resolve(&mut ast, &import_cfg) {
@ -764,14 +777,16 @@ impl<ASTBuilder: ASTBuildable, HIRBuilder: Buildable>
return Err(errs); 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()); debug_assert!(prev.is_none());
Ok(()) 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 { let Ok(src) = import_path.try_read() else {
return Err(()); return None;
}; };
let cfg = self.cfg.inherit(import_path.to_path_buf()); let cfg = self.cfg.inherit(import_path.to_path_buf());
let result = if import_path.extension() == Some(OsStr::new("er")) { let result = if import_path.extension() == Some(OsStr::new("er")) {
@ -786,7 +801,7 @@ impl<ASTBuilder: ASTBuildable, HIRBuilder: Buildable>
self.parse_errors self.parse_errors
.warns .warns
.extend(CompileErrors::from(art.warns)); .extend(CompileErrors::from(art.warns));
Ok(art.ast) Some(art.ast)
} }
Err(iart) => { Err(iart) => {
self.parse_errors self.parse_errors
@ -795,11 +810,7 @@ impl<ASTBuilder: ASTBuildable, HIRBuilder: Buildable>
self.parse_errors self.parse_errors
.warns .warns
.extend(CompileErrors::from(iart.warns)); .extend(CompileErrors::from(iart.warns));
if let Some(ast) = iart.ast { iart.ast
Ok(ast)
} else {
Err(())
}
} }
} }
} }
@ -821,8 +832,8 @@ impl<ASTBuilder: ASTBuildable, HIRBuilder: Buildable>
while let Some(ancestor) = ancestors.pop() { while let Some(ancestor) = ancestors.pop() {
if graph.ancestors(&ancestor).is_empty() { if graph.ancestors(&ancestor).is_empty() {
graph.remove(&ancestor); graph.remove(&ancestor);
if let Some((__name__, ancestor_ast)) = self.asts.remove(&ancestor) { if let Some(entry) = self.asts.remove(&ancestor) {
self.start_analysis_process(ancestor_ast, __name__, ancestor); self.start_analysis_process(entry.ast, entry.name, ancestor);
} else { } else {
self.build_inlined_module(&ancestor, graph); 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) { fn build_inlined_module(&mut self, path: &NormalizedPathBuf, graph: &mut ModuleGraph) {
if self.shared.get_module(path).is_some() { if self.shared.get_module(path).is_some() {
// do nothing // 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() { } else if let Some(inliner) = self.inlines.get(path).cloned() {
self.build_deps_and_module(&inliner, graph); self.build_deps_and_module(&inliner, graph);
} else if DEBUG_MODE { } else {
todo!("{path} is not found in self.inlines and self.asts"); 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::set::Set;
use erg_common::style::colors::DEBUG_ERROR; use erg_common::style::colors::DEBUG_ERROR;
use erg_common::traits::StructuralEq; 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 erg_common::{Str, Triple};
use crate::context::eval::UndoableLinkedList; use crate::context::eval::UndoableLinkedList;
@ -126,6 +126,7 @@ impl Context {
/// lhs :> rhs ? /// lhs :> rhs ?
pub(crate) fn supertype_of(&self, lhs: &Type, rhs: &Type) -> bool { 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) { let res = match Self::cheap_supertype_of(lhs, rhs) {
(Absolutely, judge) => judge, (Absolutely, judge) => judge,
(Maybe, judge) => { (Maybe, judge) => {
@ -1072,6 +1073,23 @@ impl Context {
(TyParam::UnsizedList(sup), TyParam::UnsizedList(sub)) => { (TyParam::UnsizedList(sup), TyParam::UnsizedList(sub)) => {
self.supertype_of_tp(sup, sub, variance) 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 { (TyParam::Type(sup), TyParam::Type(sub)) => match variance {
Variance::Contravariant => self.subtype_of(sup, sub), Variance::Contravariant => self.subtype_of(sup, sub),
Variance::Covariant => self.supertype_of(sup, sub), Variance::Covariant => self.supertype_of(sup, sub),
@ -1465,6 +1483,7 @@ impl Context {
t t
} }
(t, Type::Never) | (Type::Never, t) => t.clone(), (t, Type::Never) | (Type::Never, t) => t.clone(),
// REVIEW: variance?
// List({1, 2}, 2), List({3, 4}, 2) ==> List({1, 2, 3, 4}, 2) // List({1, 2}, 2), List({3, 4}, 2) ==> List({1, 2, 3, 4}, 2)
( (
Type::Poly { Type::Poly {
@ -1566,19 +1585,27 @@ impl Context {
/// ``` /// ```
fn simple_union(&self, lhs: &Type, rhs: &Type) -> Type { fn simple_union(&self, lhs: &Type, rhs: &Type) -> Type {
if let Ok(free) = <&FreeTyVar>::try_from(lhs) { 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() lhs.clone()
} else { } else {
or(lhs.clone(), rhs.clone()) or(lhs.clone(), rhs.clone())
} };
free.undo();
res
} else if let Ok(free) = <&FreeTyVar>::try_from(rhs) { } 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() rhs.clone()
} else { } else {
or(lhs.clone(), rhs.clone()) or(lhs.clone(), rhs.clone())
} };
free.undo();
res
} else { } else {
if lhs.is_totally_unbound() || rhs.is_totally_unbound() { if lhs.is_totally_unbound() || rhs.is_totally_unbound() {
return or(lhs.clone(), rhs.clone()); return or(lhs.clone(), rhs.clone());
@ -1677,6 +1704,29 @@ impl Context {
} }
t 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) => { (other, Refinement(refine)) | (Refinement(refine), other) => {
let other = other.clone().into_refinement(); let other = other.clone().into_refinement();
let intersec = self.intersection_refinement(&other, refine); 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 /// ```erg
/// intersection_add(Nat and ?T(:> NoneType), Int) == Nat and ?T /// intersection_add(Nat and ?T(:> NoneType), Int) == Nat and ?T
/// intersection_add(Int and ?T(:> NoneType), Nat) == 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::set::Set;
use erg_common::shared::Shared; use erg_common::shared::Shared;
use erg_common::traits::{Locational, Stream}; 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 erg_common::{ArcArray, Str};
use OpKind::*; use OpKind::*;
@ -37,7 +37,7 @@ use crate::error::{EvalError, EvalErrors, EvalResult, Failable, SingleEvalResult
use crate::varinfo::{AbsLocation, VarInfo}; use crate::varinfo::{AbsLocation, VarInfo};
use super::instantiate::TyVarCache; use super::instantiate::TyVarCache;
use Type::{Failure, Never, Subr}; use Type::{Failure, Never};
macro_rules! feature_error { macro_rules! feature_error {
($ctx: expr, $loc: expr, $name: expr) => { ($ctx: expr, $loc: expr, $name: expr) => {
@ -406,11 +406,17 @@ impl<'c> Substituter<'c> {
/// -> Iterable(Int) /// -> Iterable(Int)
/// ``` /// ```
pub(crate) fn substitute_self(qt: &Type, subtype: &Type, ctx: &'c Context) -> Option<Self> { 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() { for t in qt.contained_ts() {
if t.is_qvar() if t.is_qvar()
&& &t.qual_name()[..] == "Self" && &t.qual_name()[..] == "Self"
&& t.get_super() && t.get_super().is_some_and(|sup| {
.is_some_and(|sup| ctx.supertype_of(&sup, subtype)) 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); let mut _self = Self::new(ctx);
t.undoable_link(subtype, &_self.undoable_linked); t.undoable_link(subtype, &_self.undoable_linked);
@ -633,7 +639,7 @@ impl Context {
Ok(tp) => (tp, EvalErrors::empty()), Ok(tp) => (tp, EvalErrors::empty()),
Err((tp, errs)) => (tp, errs), Err((tp, errs)) => (tp, errs),
}; };
match ValueObj::try_from(tp) { match self.convert_tp_into_value(tp) {
Ok(val) => { Ok(val) => {
if errs.is_empty() { if errs.is_empty() {
Ok(val) Ok(val)
@ -641,7 +647,7 @@ impl Context {
Err((val, errs)) Err((val, errs))
} }
} }
Err(()) => { Err(_) => {
if errs.is_empty() { if errs.is_empty() {
Err(( Err((
ValueObj::Failure, ValueObj::Failure,
@ -1748,21 +1754,38 @@ impl Context {
fn eval_unary_val(&self, op: OpKind, val: ValueObj) -> EvalResult<ValueObj> { fn eval_unary_val(&self, op: OpKind, val: ValueObj) -> EvalResult<ValueObj> {
match op { match op {
Pos => Err(EvalErrors::from(EvalError::unreachable( Pos => match val {
ValueObj::Nat(_)
| ValueObj::Int(_)
| ValueObj::Float(_)
| ValueObj::Inf
| ValueObj::NegInf => Ok(val),
_ => Err(EvalErrors::from(EvalError::unreachable(
self.cfg.input.clone(), self.cfg.input.clone(),
fn_name!(), fn_name!(),
line!(), line!(),
))), ))),
Neg => Err(EvalErrors::from(EvalError::unreachable( },
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(), self.cfg.input.clone(),
fn_name!(), fn_name!(),
line!(), line!(),
))), ))),
Invert => Err(EvalErrors::from(EvalError::unreachable( },
Invert => match val {
ValueObj::Bool(b) => Ok(ValueObj::Bool(!b)),
_ => Err(EvalErrors::from(EvalError::unreachable(
self.cfg.input.clone(), self.cfg.input.clone(),
fn_name!(), fn_name!(),
line!(), line!(),
))), ))),
},
Not => match val { Not => match val {
ValueObj::Bool(b) => Ok(ValueObj::Bool(!b)), ValueObj::Bool(b) => Ok(ValueObj::Bool(!b)),
ValueObj::Type(lhs) => Ok(self.eval_not_type(lhs)), 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> { pub(crate) fn eval_tp(&self, p: TyParam) -> Failable<TyParam> {
let mut errs = EvalErrors::empty(); let mut errs = EvalErrors::empty();
let tp = match p { let tp = match p {
TyParam::FreeVar(fv) if fv.is_linked() => { TyParam::FreeVar(fv) if fv.is_linked() => match self.eval_tp(fv.unwrap_linked()) {
let tp = fv.crack().clone();
match self.eval_tp(tp) {
Ok(tp) => tp, Ok(tp) => tp,
Err((tp, es)) => { Err((tp, es)) => {
errs.extend(es); errs.extend(es);
tp tp
} }
} },
}
TyParam::FreeVar(_) => p, TyParam::FreeVar(_) => p,
TyParam::Mono(name) => match self TyParam::Mono(name) => match self
.rec_get_const_obj(&name) .rec_get_const_obj(&name)
@ -1968,15 +1988,17 @@ impl Context {
TyParam::erased(t) TyParam::erased(t)
} }
}, },
TyParam::Value(ValueObj::Type(mut t)) => { TyParam::Value(val) => {
match t.try_map_t(|t| self.eval_t_params(t, self.level, &())) { match val
Ok(_) => {} .clone()
.try_map_t(&mut |t| self.eval_t_params(t, self.level, &()))
{
Ok(val) => TyParam::Value(val),
Err((_t, es)) => { Err((_t, es)) => {
errs.extend(es); errs.extend(es);
*t.typ_mut() = _t; TyParam::Value(val)
} }
} }
TyParam::Value(ValueObj::Type(t))
} }
TyParam::ProjCall { obj, attr, args } => { TyParam::ProjCall { obj, attr, args } => {
match self.eval_proj_call(*obj, attr, args, &()) { match self.eval_proj_call(*obj, attr, args, &()) {
@ -1994,7 +2016,6 @@ impl Context {
return Err((TyParam::Failure, errs)); return Err((TyParam::Failure, errs));
} }
}, },
TyParam::Value(_) => p.clone(),
other => { other => {
errs.push(EvalError::feature_error( errs.push(EvalError::feature_error(
self.cfg.input.clone(), self.cfg.input.clone(),
@ -2046,11 +2067,11 @@ impl Context {
level: usize, level: usize,
t_loc: &impl Locational, t_loc: &impl Locational,
) -> Failable<Type> { ) -> Failable<Type> {
set_recursion_limit!(Ok(Failure), 128);
let mut errs = EvalErrors::empty(); let mut errs = EvalErrors::empty();
match substituted { match substituted {
Type::FreeVar(fv) if fv.is_linked() => { Type::FreeVar(fv) if fv.is_linked() => {
let t = fv.crack().clone(); self.eval_t_params(fv.unwrap_linked(), level, t_loc)
self.eval_t_params(t, level, t_loc)
} }
Type::FreeVar(fv) if fv.constraint_is_sandwiched() => { Type::FreeVar(fv) if fv.constraint_is_sandwiched() => {
let (sub, sup) = fv.get_subsup().unwrap(); 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) *pt.typ_mut() = match self.eval_t_params(mem::take(pt.typ_mut()), level, t_loc)
{ {
Ok(t) => t, Ok(t) => t,
Err((_, errs)) => { Err((t, es)) => {
// `mem::take` replaces the type with `Type::Failure`, so it can return as is errs.extend(es);
return Err((Subr(subr), errs)); t
} }
}; };
} }
@ -2083,19 +2104,28 @@ impl Context {
*var_args.typ_mut() = *var_args.typ_mut() =
match self.eval_t_params(mem::take(var_args.typ_mut()), level, t_loc) { match self.eval_t_params(mem::take(var_args.typ_mut()), level, t_loc) {
Ok(t) => t, 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() { for pt in subr.default_params.iter_mut() {
*pt.typ_mut() = match self.eval_t_params(mem::take(pt.typ_mut()), level, t_loc) *pt.typ_mut() = match self.eval_t_params(mem::take(pt.typ_mut()), level, t_loc)
{ {
Ok(t) => t, 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() { if let Some(default) = pt.default_typ_mut() {
*default = match self.eval_t_params(mem::take(default), level, t_loc) { *default = match self.eval_t_params(mem::take(default), level, t_loc) {
Ok(t) => t, 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() = *kw_var_args.typ_mut() =
match self.eval_t_params(mem::take(kw_var_args.typ_mut()), level, t_loc) { match self.eval_t_params(mem::take(kw_var_args.typ_mut()), level, t_loc) {
Ok(t) => t, 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) { let return_t = match self.eval_t_params(*subr.return_t, level, t_loc) {
Ok(return_t) => Ok(subr_t( Ok(return_t) => return_t,
subr.kind, Err((return_t, es)) => {
subr.non_default_params, errs.extend(es);
subr.var_params.map(|v| *v), return_t
subr.default_params, }
subr.kw_var_params.map(|v| *v), };
return_t,
)),
Err((_, errs)) => {
let subr = subr_t( let subr = subr_t(
subr.kind, subr.kind,
subr.non_default_params, subr.non_default_params,
subr.var_params.map(|v| *v), subr.var_params.map(|v| *v),
subr.default_params, subr.default_params,
subr.kw_var_params.map(|v| *v), subr.kw_var_params.map(|v| *v),
Failure, return_t,
); );
if errs.is_empty() {
Ok(subr)
} else {
Err((subr, errs)) 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) => { Type::Refinement(refine) => {
if refine.pred.variables().is_empty() { if refine.pred.variables().is_empty() {
let pred = match self.eval_pred(*refine.pred) { let pred = match self.eval_pred(*refine.pred) {
@ -2157,27 +2193,33 @@ impl Context {
.map_err(|errs| (Failure, errs)), .map_err(|errs| (Failure, errs)),
Type::Ref(l) => match self.eval_t_params(*l, level, t_loc) { Type::Ref(l) => match self.eval_t_params(*l, level, t_loc) {
Ok(t) => Ok(ref_(t)), Ok(t) => Ok(ref_(t)),
Err((_, errs)) => Err((ref_(Failure), errs)), Err((t, errs)) => Err((ref_(t), errs)),
}, },
Type::RefMut { before, after } => { Type::RefMut { before, after } => {
let before = match self.eval_t_params(*before, level, t_loc) { let before = match self.eval_t_params(*before, level, t_loc) {
Ok(before) => before, Ok(before) => before,
Err((_, errs)) => { Err((before, es)) => {
return Err((ref_mut(Failure, after.map(|x| *x)), errs)); errs.extend(es);
before
} }
}; };
let after = if let Some(after) = after { let after = if let Some(after) = after {
let aft = match self.eval_t_params(*after, level, t_loc) { let aft = match self.eval_t_params(*after, level, t_loc) {
Ok(aft) => aft, Ok(aft) => aft,
Err((_, errs)) => { Err((aft, es)) => {
return Err((ref_mut(before, Some(Failure)), errs)); errs.extend(es);
aft
} }
}; };
Some(aft) Some(aft)
} else { } else {
None None
}; };
if errs.is_empty() {
Ok(ref_mut(before, after)) Ok(ref_mut(before, after))
} else {
Err((ref_mut(before, after), errs))
}
} }
Type::Poly { name, mut params } => { Type::Poly { name, mut params } => {
for p in params.iter_mut() { for p in params.iter_mut() {
@ -2208,82 +2250,115 @@ impl Context {
Type::And(l, r) => { Type::And(l, r) => {
let l = match self.eval_t_params(*l, level, t_loc) { let l = match self.eval_t_params(*l, level, t_loc) {
Ok(l) => l, Ok(l) => l,
Err((_, errs)) => { Err((l, es)) => {
return Err((Failure, errs)); errs.extend(es);
l
} }
}; };
let r = match self.eval_t_params(*r, level, t_loc) { let r = match self.eval_t_params(*r, level, t_loc) {
Ok(r) => r, Ok(r) => r,
Err((_, errs)) => { Err((r, es)) => {
// L and Never == Never errs.extend(es);
return Err((Failure, errs)); 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) => { Type::Or(l, r) => {
let l = match self.eval_t_params(*l, level, t_loc) { let l = match self.eval_t_params(*l, level, t_loc) {
Ok(l) => l, Ok(l) => l,
Err((_, errs)) => { Err((l, es)) => {
return Err((Failure, errs)); errs.extend(es);
l
} }
}; };
let r = match self.eval_t_params(*r, level, t_loc) { let r = match self.eval_t_params(*r, level, t_loc) {
Ok(r) => r, Ok(r) => r,
Err((_, errs)) => { Err((r, es)) => {
// L or Never == L errs.extend(es);
return Err((l, errs)); 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) { Type::Not(ty) => match self.eval_t_params(*ty, level, t_loc) {
Ok(ty) => Ok(self.complement(&ty)), 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) => { Type::Record(rec) => {
let mut fields = dict! {}; let mut fields = dict! {};
for (name, tp) in rec.into_iter() { for (name, ty) in rec.into_iter() {
fields.insert(name, self.eval_t_params(tp, level, t_loc)?); 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)) Ok(Type::Record(fields))
} }
Type::NamedTuple(tuple) => { Type::NamedTuple(tuple) => {
let mut new_tuple = vec![]; let mut new_tuple = vec![];
for (name, tp) in tuple.into_iter() { for (name, ty) in tuple.into_iter() {
new_tuple.push((name, self.eval_t_params(tp, level, t_loc)?)); 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)) Ok(Type::NamedTuple(new_tuple))
} }
Type::Bounded { sub, sup } => { Type::Bounded { sub, sup } => {
let sub = match self.eval_t_params(*sub, level, t_loc) { let sub = match self.eval_t_params(*sub, level, t_loc) {
Ok(sub) => sub, Ok(sub) => sub,
Err((_, errs)) => { Err((sub, es)) => {
return Err((Failure, errs)); errs.extend(es);
sub
} }
}; };
let sup = match self.eval_t_params(*sup, level, t_loc) { let sup = match self.eval_t_params(*sup, level, t_loc) {
Ok(sup) => sup, Ok(sup) => sup,
Err((_, errs)) => { Err((sup, es)) => {
return Err((Failure, errs)); errs.extend(es);
sup
} }
}; };
if errs.is_empty() {
Ok(bounded(sub, sup)) Ok(bounded(sub, sup))
} else {
Err((bounded(sub, sup), errs))
} }
Type::Guard(grd) => {
let to = self.eval_t_params(*grd.to, level, t_loc)?;
Ok(guard(grd.namespace, grd.target, to))
} }
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 if other.is_monomorphic() => Ok(other),
other => feature_error!(self, t_loc.loc(), &format!("eval {other}")) other => feature_error!(self, t_loc.loc(), &format!("eval {other}"))
.map_err(|errs| (other, errs)), .map_err(|errs| (other, errs)),
} }
} }
/// This may do nothing (be careful with recursive calls).
/// lhs: mainly class /// lhs: mainly class
pub(crate) fn eval_proj( pub(crate) fn eval_proj(
&self, &self,
@ -2476,6 +2551,7 @@ impl Context {
/// {x = Int; y = Int} => Type::Record({x = Int, y = Int}) /// {x = Int; y = Int} => Type::Record({x = Int, y = Int})
/// {Str: Int} => Dict({Str: Int}) /// {Str: Int} => Dict({Str: Int})
/// {1, 2} => {I: Int | I == 1 or I == 2 } (== {1, 2}) /// {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> { pub(crate) fn convert_tp_into_type(&self, tp: TyParam) -> Result<Type, TyParam> {
match tp { match tp {
@ -2544,22 +2620,46 @@ impl Context {
} }
TyParam::Type(t) => Ok(t.as_ref().clone()), TyParam::Type(t) => Ok(t.as_ref().clone()),
TyParam::Mono(name) => Ok(Type::Mono(name)), TyParam::Mono(name) => Ok(Type::Mono(name)),
// REVIEW: should be checked? TyParam::App { name, args } => {
TyParam::App { name, args } => Ok(Type::Poly { name, params: args }), if self.get_type_ctx(&name).is_none() {
TyParam::Proj { obj, attr } => { Err(TyParam::App { name, args })
let lhs = self.convert_tp_into_type(*obj)?; } else {
Ok(lhs.proj(attr)) 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::Erased(_t) => Ok(Type::Obj),
TyParam::Value(v) => self.convert_value_into_type(v).map_err(TyParam::Value), TyParam::Value(v) => self.convert_value_into_type(v).map_err(TyParam::Value),
TyParam::Erased(t) if t.is_type() => Ok(Type::Obj), TyParam::Erased(t) if t.is_type() => Ok(Type::Obj),
// TODO: Dict, Set // TODO: DataClass, ...
other => Err(other), other => Err(other),
} }
} }
#[allow(clippy::only_used_in_recursion)]
pub(crate) fn convert_tp_into_value(&self, tp: TyParam) -> Result<ValueObj, TyParam> { pub(crate) fn convert_tp_into_value(&self, tp: TyParam) -> Result<ValueObj, TyParam> {
match tp { match tp {
TyParam::FreeVar(fv) if fv.is_linked() => { TyParam::FreeVar(fv) if fv.is_linked() => {
@ -2595,6 +2695,16 @@ impl Context {
} }
Ok(ValueObj::Record(new)) 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) => { TyParam::Set(set) => {
let mut new = set! {}; let mut new = set! {};
for elem in 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> { pub(crate) fn convert_value_into_type(&self, val: ValueObj) -> Result<Type, ValueObj> {
match val { match val {
ValueObj::Failure => Ok(Type::Failure), ValueObj::Failure => Ok(Type::Failure),
ValueObj::Ellipsis => Ok(Type::Ellipsis), ValueObj::Ellipsis => Ok(Type::Ellipsis),
ValueObj::NotImplemented => Ok(Type::NotImplementedType),
ValueObj::Type(t) => Ok(t.into_typ()), ValueObj::Type(t) => Ok(t.into_typ()),
ValueObj::Record(rec) => { ValueObj::Record(rec) => {
let mut fields = dict! {}; let mut fields = dict! {};
@ -2812,6 +2924,30 @@ impl Context {
} }
Ok(new_dict) 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(()), _ => Err(()),
} }
} }
@ -2832,6 +2968,31 @@ impl Context {
} }
Ok(tys) 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(()), _ => Err(()),
} }
} }
@ -2857,6 +3018,24 @@ impl Context {
}; };
Ok(vec![ValueObj::builtin_type(t); len]) 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), _ => Err(ty),
} }
} }
@ -3018,7 +3197,7 @@ impl Context {
let Some(lhs) = lhs else { let Some(lhs) = lhs else {
return feature_error!(self, t_loc.loc(), "??"); 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); pos_args.push(value);
} else if let Ok(value) = self.eval_tp_into_value(lhs.clone()) { } else if let Ok(value) = self.eval_tp_into_value(lhs.clone()) {
pos_args.push(value); pos_args.push(value);
@ -3027,7 +3206,7 @@ impl Context {
} }
} }
for pos_arg in args.into_iter() { 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); pos_args.push(value);
} else if let Ok(value) = self.eval_tp_into_value(pos_arg.clone()) { } else if let Ok(value) = self.eval_tp_into_value(pos_arg.clone()) {
pos_args.push(value); 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( pub(crate) fn eval_proj_call_t(
&self, &self,
lhs: TyParam, lhs: TyParam,

View file

@ -18,7 +18,7 @@ use crate::ty::{HasType, Predicate, SubrType, Type};
use crate::context::{Context, Variance}; use crate::context::{Context, Variance};
use crate::error::{TyCheckError, TyCheckErrors, TyCheckResult}; 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 Type::*;
use Variance::*; use Variance::*;
@ -45,9 +45,10 @@ impl Generalizer {
fn generalize_tp(&mut self, free: TyParam, uninit: bool) -> TyParam { fn generalize_tp(&mut self, free: TyParam, uninit: bool) -> TyParam {
match free { match free {
TyParam::Type(t) => TyParam::t(self.generalize_t(*t, uninit)), TyParam::Type(t) => TyParam::t(self.generalize_t(*t, uninit)),
TyParam::Value(ValueObj::Type(t)) => { TyParam::Value(val) => TyParam::Value(
TyParam::t(self.generalize_t(t.into_typ(), uninit)) 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_generalized() => TyParam::FreeVar(fv),
TyParam::FreeVar(fv) if fv.is_linked() => { TyParam::FreeVar(fv) if fv.is_linked() => {
let tp = fv.crack().clone(); let tp = fv.crack().clone();
@ -65,6 +66,9 @@ impl Generalizer {
.map(|tp| self.generalize_tp(tp, uninit)) .map(|tp| self.generalize_tp(tp, uninit))
.collect(), .collect(),
), ),
TyParam::UnsizedList(tp) => {
TyParam::UnsizedList(Box::new(self.generalize_tp(*tp, uninit)))
}
TyParam::Tuple(tps) => TyParam::Tuple( TyParam::Tuple(tps) => TyParam::Tuple(
tps.into_iter() tps.into_iter()
.map(|tp| self.generalize_tp(tp, uninit)) .map(|tp| self.generalize_tp(tp, uninit))
@ -128,6 +132,14 @@ impl Generalizer {
let obj = self.generalize_tp(*obj, uninit); let obj = self.generalize_tp(*obj, uninit);
TyParam::proj(obj, attr) 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::Erased(t) => TyParam::erased(self.generalize_t(*t, uninit)),
TyParam::App { name, args } => { TyParam::App { name, args } => {
let args = args let args = args
@ -145,13 +157,7 @@ impl Generalizer {
let val = self.generalize_tp(*val, uninit); let val = self.generalize_tp(*val, uninit);
TyParam::unary(op, val) TyParam::unary(op, val)
} }
other if other.has_no_unbound_var() => other, TyParam::Mono(_) | TyParam::Failure => free,
other => {
if DEBUG_MODE {
todo!("{other:?}");
}
other
}
} }
} }
@ -203,6 +209,7 @@ impl Generalizer {
Type::FreeVar(fv) Type::FreeVar(fv)
} }
} }
FreeVar(_) => free_type,
Subr(mut subr) => { Subr(mut subr) => {
self.variance = Contravariant; self.variance = Contravariant;
let qnames = subr.essential_qnames(); let qnames = subr.essential_qnames();
@ -231,6 +238,10 @@ impl Generalizer {
return_t, return_t,
) )
} }
Quantified(quant) => {
log!(err "{quant}");
quant.quantify()
}
Record(rec) => { Record(rec) => {
let fields = rec let fields = rec
.into_iter() .into_iter()
@ -307,8 +318,14 @@ impl Generalizer {
let to = self.generalize_t(*grd.to, uninit); let to = self.generalize_t(*grd.to, uninit);
guard(grd.namespace, grd.target, to) guard(grd.namespace, grd.target, to)
} }
// REVIEW: その他何でもそのまま通していいのか? Bounded { sub, sup } => {
other => other, 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 { fn generalize_pred(&mut self, pred: Predicate, uninit: bool) -> Predicate {
match pred { match pred {
Predicate::Const(_) | Predicate::Failure => pred, Predicate::Const(_) | Predicate::Failure => pred,
Predicate::Value(ValueObj::Type(mut typ)) => { Predicate::Value(val) => {
*typ.typ_mut() = self.generalize_t(mem::take(typ.typ_mut()), uninit); Predicate::Value(val.map_t(&mut |t| self.generalize_t(t, uninit)))
Predicate::Value(ValueObj::Type(typ))
} }
Predicate::Call { Predicate::Call {
receiver, receiver,
@ -348,7 +364,6 @@ impl Generalizer {
let receiver = self.generalize_tp(receiver, uninit); let receiver = self.generalize_tp(receiver, uninit);
Predicate::attr(receiver, name) Predicate::attr(receiver, name)
} }
Predicate::Value(_) => pred,
Predicate::GeneralEqual { lhs, rhs } => { Predicate::GeneralEqual { lhs, rhs } => {
let lhs = self.generalize_pred(*lhs, uninit); let lhs = self.generalize_pred(*lhs, uninit);
let rhs = self.generalize_pred(*rhs, 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> { fn deref_value(&mut self, val: ValueObj) -> TyCheckResult<ValueObj> {
match val { match val {
ValueObj::Type(mut t) => { 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)) Ok(ValueObj::Type(t))
} }
ValueObj::List(vs) => { 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)?))), 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); fv.update_type(t);
Ok(TyParam::FreeVar(fv)) Ok(TyParam::FreeVar(fv))
} }
TyParam::FreeVar(_) => Ok(tp),
TyParam::Type(t) => Ok(TyParam::t(self.deref_tyvar(*t)?)), TyParam::Type(t) => Ok(TyParam::t(self.deref_tyvar(*t)?)),
TyParam::Value(val) => self.deref_value(val).map(TyParam::Value), TyParam::Value(val) => self.deref_value(val).map(TyParam::Value),
TyParam::Erased(t) => Ok(TyParam::erased(self.deref_tyvar(*t)?)), 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)) Ok(TyParam::List(new_tps))
} }
TyParam::UnsizedList(tp) => Ok(TyParam::UnsizedList(Box::new(self.deref_tp(*tp)?))),
TyParam::Tuple(tps) => { TyParam::Tuple(tps) => {
let mut new_tps = vec![]; let mut new_tps = vec![];
for tp in tps { for tp in tps {
@ -613,20 +631,20 @@ impl<'c, 'q, 'l, L: Locational> Dereferencer<'c, 'q, 'l, L> {
let nd_params = lambda let nd_params = lambda
.nd_params .nd_params
.into_iter() .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<_>>()?; .collect::<TyCheckResult<_>>()?;
let var_params = lambda let var_params = lambda
.var_params .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()?; .transpose()?;
let d_params = lambda let d_params = lambda
.d_params .d_params
.into_iter() .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<_>>()?; .collect::<TyCheckResult<_>>()?;
let kw_var_params = lambda let kw_var_params = lambda
.kw_var_params .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()?; .transpose()?;
let body = lambda let body = lambda
.body .body
@ -649,10 +667,22 @@ impl<'c, 'q, 'l, L: Locational> Dereferencer<'c, 'q, 'l, L> {
attr, 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( TyParam::Failure if self.level == 0 => Err(TyCheckErrors::from(
TyCheckError::dummy_infer_error(self.ctx.cfg.input.clone(), fn_name!(), line!()), 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)?; let pred = self.deref_pred(*pred)?;
Ok(!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), 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)) Ok(Type::FreeVar(fv))
} }
} }
FreeVar(_) => Ok(t),
Poly { name, mut params } => { Poly { name, mut params } => {
let typ = poly(&name, params.clone()); let typ = poly(&name, params.clone());
let ctx = self.ctx.get_nominal_type_ctx(&typ).ok_or_else(|| { 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)?; let to = self.deref_tyvar(*grd.to)?;
Ok(guard(grd.namespace, grd.target, 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()) Ok(v.into())
} else { } else {
let index = if let ValueObj::Type(t) = &index { let index = if let ValueObj::Type(t) = &index {
let derefed = ctx.coerce(t.typ().clone(), &()).unwrap_or(t.typ().clone()); ValueObj::builtin_type(ctx.readable_type(t.typ().clone()))
ValueObj::builtin_type(derefed)
} else { } else {
index index
}; };

View file

@ -1854,7 +1854,10 @@ impl Context {
), ),
Type::FreeVar(fv) => { Type::FreeVar(fv) => {
if let Some(sub) = fv.get_sub() { 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)); return Err(self.not_callable_error(obj, attr_name, instance, None));
} }
if sub != Never { 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::consts::DEBUG_MODE;
use erg_common::dict::Dict; use erg_common::dict::Dict;
use erg_common::enum_unwrap;
#[allow(unused)] #[allow(unused)]
use erg_common::log; use erg_common::log;
use erg_common::set::Set; use erg_common::set::Set;
use erg_common::traits::Locational; use erg_common::traits::Locational;
use erg_common::Str; use erg_common::Str;
use erg_common::{enum_unwrap, set_recursion_limit};
use erg_parser::ast::VarName; use erg_parser::ast::VarName;
use crate::ty::constructors::*; use crate::ty::constructors::*;
@ -19,7 +19,7 @@ use crate::ty::ConstSubr;
use crate::ty::GuardType; use crate::ty::GuardType;
use crate::ty::ValueObj; use crate::ty::ValueObj;
use crate::ty::{HasType, Predicate, Type}; use crate::ty::{HasType, Predicate, Type};
use crate::{type_feature_error, unreachable_error}; use crate::{mono_type_pattern, unreachable_error};
use Type::*; use Type::*;
use crate::context::{Context, VarInfo}; use crate::context::{Context, VarInfo};
@ -40,7 +40,6 @@ pub struct TyVarCache {
pub(crate) tyvar_instances: Dict<VarName, Type>, pub(crate) tyvar_instances: Dict<VarName, Type>,
pub(crate) typaram_instances: Dict<VarName, TyParam>, pub(crate) typaram_instances: Dict<VarName, TyParam>,
pub(crate) var_infos: Dict<VarName, VarInfo>, pub(crate) var_infos: Dict<VarName, VarInfo>,
pub(crate) structural_inner: bool,
} }
impl fmt::Display for TyVarCache { impl fmt::Display for TyVarCache {
@ -61,7 +60,6 @@ impl TyVarCache {
tyvar_instances: Dict::new(), tyvar_instances: Dict::new(),
typaram_instances: Dict::new(), typaram_instances: Dict::new(),
var_infos: Dict::new(), var_infos: Dict::new(),
structural_inner: false,
} }
} }
@ -419,6 +417,8 @@ impl Context {
tmp_tv_cache.instantiate_constraint(constr, self, loc)?; tmp_tv_cache.instantiate_constraint(constr, self, loc)?;
fv.update_constraint(new_constr, true); fv.update_constraint(new_constr, true);
} }
} else {
todo!("{tp}");
} }
Ok(tp) Ok(tp)
} else if let Some(t) = tmp_tv_cache.get_tyvar(&name) { } 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)?; tmp_tv_cache.instantiate_constraint(constr, self, loc)?;
fv.update_constraint(new_constr, true); fv.update_constraint(new_constr, true);
} }
} else {
todo!("{t}");
} }
Ok(TyParam::t(t)) Ok(TyParam::t(t))
} else { } else {
@ -517,20 +519,28 @@ impl Context {
let nd_params = lambda let nd_params = lambda
.nd_params .nd_params
.into_iter() .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<_>>()?; .collect::<TyCheckResult<_>>()?;
let var_params = lambda let var_params = lambda
.var_params .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()?; .transpose()?;
let d_params = lambda let d_params = lambda
.d_params .d_params
.into_iter() .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<_>>()?; .collect::<TyCheckResult<_>>()?;
let kw_var_params = lambda let kw_var_params = lambda
.kw_var_params .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()?; .transpose()?;
let body = lambda let body = lambda
.body .body
@ -578,22 +588,18 @@ impl Context {
let t = self.instantiate_t_inner(*t, tmp_tv_cache, loc)?; let t = self.instantiate_t_inner(*t, tmp_tv_cache, loc)?;
Ok(TyParam::t(t)) Ok(TyParam::t(t))
} }
TyParam::Value(ValueObj::Type(t)) => { TyParam::Value(val) => {
let t = self.instantiate_t_inner(t.into_typ(), tmp_tv_cache, loc)?; // println!("592: {val} / {tmp_tv_cache}");
Ok(TyParam::t(t)) 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) => { TyParam::Erased(t) => {
let t = self.instantiate_t_inner(*t, tmp_tv_cache, loc)?; let t = self.instantiate_t_inner(*t, tmp_tv_cache, loc)?;
Ok(TyParam::Erased(Box::new(t))) Ok(TyParam::Erased(Box::new(t)))
} }
p @ (TyParam::Value(_) | TyParam::Mono(_) | TyParam::FreeVar(_)) => Ok(p), p @ (TyParam::Mono(_) | TyParam::FreeVar(_) | TyParam::Failure) => Ok(p),
other => {
type_feature_error!(
self,
loc.loc(),
&format!("instantiating type-parameter {other}")
)
}
} }
} }
@ -670,7 +676,11 @@ impl Context {
let rhs = self.instantiate_pred(*rhs, tmp_tv_cache, loc)?; let rhs = self.instantiate_pred(*rhs, tmp_tv_cache, loc)?;
Ok(Predicate::general_ne(lhs, rhs)) 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())) 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) => { ValueObj::Tuple(tup) => {
let mut new = vec![]; let mut new = vec![];
for v in tup.iter().cloned() { for v in tup.iter().cloned() {
@ -754,7 +768,18 @@ impl Context {
} }
Ok(ValueObj::DataClass { name, fields: new }) 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, tmp_tv_cache: &mut TyVarCache,
loc: &impl Locational, loc: &impl Locational,
) -> TyCheckResult<Type> { ) -> TyCheckResult<Type> {
// Structural types may have recursive structures
set_recursion_limit!(Ok(unbound), 128);
match unbound { match unbound {
FreeVar(fv) if fv.is_linked() => { FreeVar(fv) if fv.is_linked() => {
let t = fv.crack().clone(); let t = fv.crack().clone();
@ -776,8 +803,7 @@ impl Context {
let t = t.clone(); let t = t.clone();
Ok(t) Ok(t)
} else if let Some(tp) = tmp_tv_cache.get_typaram(&name) { } else if let Some(tp) = tmp_tv_cache.get_typaram(&name) {
if let TyParam::Type(t) = tp { if let Ok(t) = self.convert_tp_into_type(tp.clone()) {
let t = *t.clone();
Ok(t) Ok(t)
} else { } else {
todo!( todo!(
@ -797,8 +823,8 @@ impl Context {
if let Some(t) = tv_ctx.get_tyvar(&name) { if let Some(t) = tv_ctx.get_tyvar(&name) {
return Ok(t.clone()); return Ok(t.clone());
} else if let Some(tp) = tv_ctx.get_typaram(&name) { } else if let Some(tp) = tv_ctx.get_typaram(&name) {
if let TyParam::Type(t) = tp { if let Ok(t) = self.convert_tp_into_type(tp.clone()) {
return Ok(*t.clone()); return Ok(t);
} else { } else {
todo!( todo!(
"typaram_insts: {}\ntyvar_insts:{}\n{tp}", "typaram_insts: {}\ntyvar_insts:{}\n{tp}",
@ -902,17 +928,9 @@ impl Context {
Ok(poly(name, params)) Ok(poly(name, params))
} }
Structural(t) => { 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)?; let t = self.instantiate_t_inner(*t, tmp_tv_cache, loc)?;
Ok(t.structuralize()) Ok(t.structuralize())
} }
}
FreeVar(fv) => { FreeVar(fv) => {
if let Some((sub, sup)) = fv.get_subsup() { if let Some((sub, sup)) = fv.get_subsup() {
let sub = if sub.is_recursive() { let sub = if sub.is_recursive() {
@ -961,8 +979,15 @@ impl Context {
let sup = self.instantiate_t_inner(*sup, tmp_tv_cache, loc)?; let sup = self.instantiate_t_inner(*sup, tmp_tv_cache, loc)?;
Ok(bounded(sub, sup)) Ok(bounded(sub, sup))
} }
other if other.is_monomorphic() => Ok(other), Callable { param_ts, return_t } => {
other => type_feature_error!(self, loc.loc(), &format!("instantiating type {other}")), 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() { if let Some(self_t) = ty.self_t() {
self.sub_unify(callee.ref_t(), self_t, callee, Some(&Str::ever("self")))?; 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") panic!("{ty} has qvar")
} }
Ok(ty) Ok(ty)
@ -1028,6 +1053,7 @@ impl Context {
log!(err "{subr} has qvar"); log!(err "{subr} has qvar");
self.instantiate(Type::Subr(subr).quantify(), callee) 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型)の内側に量化型は存在しない // rank-1制限により、通常の型(rank-0型)の内側に量化型は存在しない
other => Ok(other), other => Ok(other),
} }
@ -1047,7 +1073,7 @@ impl Context {
Quantified(quant) => { Quantified(quant) => {
let mut tmp_tv_cache = TyVarCache::new(self.level, self); let mut tmp_tv_cache = TyVarCache::new(self.level, self);
let ty = self.instantiate_t_inner(*quant, &mut tmp_tv_cache, &())?; 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") panic!("{ty} has qvar")
} }
Ok(ty) Ok(ty)

View file

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

View file

@ -292,6 +292,15 @@ impl<'c, 'l, 'u, L: Locational> Unifier<'c, 'l, 'u, L> {
Ok(()) Ok(())
} }
(ValueObj::Dict(sub), ValueObj::Dict(sup)) => { (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() { for (sub_k, sub_v) in sub.iter() {
if let Some(sup_v) = sup.get(sub_k) { if let Some(sup_v) = sup.get(sub_k) {
self.sub_unify_value(sub_v, sup_v)?; self.sub_unify_value(sub_v, sup_v)?;
@ -308,6 +317,22 @@ impl<'c, 'l, 'u, L: Locational> Unifier<'c, 'l, 'u, L> {
} }
Ok(()) 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)) => { (ValueObj::Record(sub), ValueObj::Record(sup)) => {
for (sub_k, sub_v) in sub.iter() { for (sub_k, sub_v) in sub.iter() {
if let Some(sup_v) = sup.get(sub_k) { 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<()> { 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_")); 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.fetch_sub(1, Ordering::SeqCst) == 0 {
if self.recursion_limit.load(Ordering::SeqCst) == 0 { self.recursion_limit.store(128, Ordering::SeqCst);
log!(err "recursion limit exceeded: {maybe_sub} / {maybe_sup}"); log!(err "recursion limit exceeded: {maybe_sub} / {maybe_sup}");
return Err(TyCheckError::recursion_limit( return Err(TyCheckError::recursion_limit(
self.ctx.cfg.input.clone(), 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() => { (FreeVar(sub_fv), Structural(struct_sup)) if sub_fv.is_unbound() => {
if sub_fv.get_sub().is_none() { let Some((sub, sup)) = sub_fv.get_subsup() else {
log!(err "{sub_fv} is not a type variable"); log!(err "{sub_fv} is not a type variable");
return Ok(()); return Ok(());
} };
sub_fv.dummy_link();
let sub_fields = self.ctx.fields(maybe_sub); 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) { if let Some((_, sub_ty)) = sub_fields.get_key_value(&sup_field) {
self.sub_unify(sub_ty, &sup_ty)?; self.sub_unify(sub_ty, &sup_ty).map_err(|errs| {
} else if !self.ctx.subtype_of(&sub_fv.get_sub().unwrap(), &Never) { sub_fv.undo();
errs
})?;
} else if !self.ctx.subtype_of(&sub, &Never) {
maybe_sub.coerce(self.undoable); maybe_sub.coerce(self.undoable);
sub_fv.dummy_link();
return self.sub_unify(maybe_sub, maybe_sup); return self.sub_unify(maybe_sub, maybe_sup);
} else { } else {
// e.g. ?T / Structural({ .method = (self: ?T) -> Int }) // 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() => { (FreeVar(sub_fv), Ref(sup)) if sub_fv.is_unbound() => {
self.sub_unify(maybe_sub, sup)?; self.sub_unify(maybe_sub, sup)?;

View file

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

View file

@ -83,7 +83,7 @@ pub struct Progress {
#[derive(Debug, Clone, Default)] #[derive(Debug, Clone, Default)]
pub struct SharedPromises { pub struct SharedPromises {
graph: SharedModuleGraph, graph: SharedModuleGraph,
pub(crate) path: NormalizedPathBuf, pub(crate) root: NormalizedPathBuf,
promises: Shared<Dict<NormalizedPathBuf, Promise>>, promises: Shared<Dict<NormalizedPathBuf, Promise>>,
} }
@ -98,10 +98,10 @@ impl fmt::Display for SharedPromises {
} }
impl SharedPromises { impl SharedPromises {
pub fn new(graph: SharedModuleGraph, path: NormalizedPathBuf) -> Self { pub fn new(graph: SharedModuleGraph, root: NormalizedPathBuf) -> Self {
Self { Self {
graph, graph,
path, root,
promises: Shared::new(Dict::new()), promises: Shared::new(Dict::new()),
} }
} }
@ -152,25 +152,30 @@ impl SharedPromises {
.is_some_and(|promise| promise.is_finished()) .is_some_and(|promise| promise.is_finished())
} }
pub fn join(&self, path: &NormalizedPathBuf) -> std::thread::Result<()> { pub fn wait_until_finished(&self, path: &NormalizedPathBuf) {
if self.graph.ancestors(path).contains(&self.path) { if self.promises.borrow().get(path).is_none() {
// cycle detected, `self.path` must not in the dependencies panic!("not registered: {path}");
// Erg analysis processes never join ancestor threads (although joining ancestors itself is allowed in Rust) }
while !self.is_finished(path) { while !self.is_finished(path) {
safe_yield(); safe_yield();
} }
}
pub fn join(&self, path: &NormalizedPathBuf) -> std::thread::Result<()> {
if self.graph.ancestors(path).contains(&self.root) {
// cycle detected, `self.path` must not in the dependencies
// Erg analysis processes never join ancestor threads (although joining ancestors itself is allowed in Rust)
// self.wait_until_finished(path);
return Ok(()); return Ok(());
} }
// Suppose A depends on B and C, and B depends on C. // 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. // In this case, B must join C before A joins C. Otherwise, a deadlock will occur.
let children = self.graph.children(path); let children = self.graph.children(path);
for child in children.iter() { for child in children.iter() {
if child == &self.path { if child == &self.root {
continue; continue;
} else if self.graph.depends_on(&self.path, child) { } else if self.graph.depends_on(&self.root, child) {
while !self.is_finished(path) { self.wait_until_finished(path);
safe_yield();
}
return Ok(()); return Ok(());
} }
} }
@ -183,9 +188,7 @@ impl SharedPromises {
let promise = self.promises.borrow_mut().get_mut(path).unwrap().take(); let promise = self.promises.borrow_mut().get_mut(path).unwrap().take();
let Promise::Running { handle, .. } = promise else { let Promise::Running { handle, .. } = promise else {
*self.promises.borrow_mut().get_mut(path).unwrap() = promise; *self.promises.borrow_mut().get_mut(path).unwrap() = promise;
while !self.is_finished(path) { self.wait_until_finished(path);
safe_yield();
}
return Ok(()); return Ok(());
}; };
if handle.thread().id() == current().id() { if handle.thread().id() == current().id() {

View file

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

View file

@ -31,13 +31,13 @@ use erg_common::fresh::FRESH_GEN;
use erg_common::log; use erg_common::log;
use erg_common::set::Set; use erg_common::set::Set;
use erg_common::traits::{LimitedDisplay, Locational, StructuralEq}; 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::ast::Expr;
use erg_parser::token::TokenKind; use erg_parser::token::TokenKind;
pub use const_subr::*; 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}; use free::{CanbeFree, Constraint, Free, FreeKind, FreeTyVar, HasLevel, Level, GENERIC_LEVEL};
pub use predicate::Predicate; pub use predicate::Predicate;
pub use typaram::{IntervalOp, TyParam}; 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 CONTAINER_OMIT_THRESHOLD: usize = if DEBUG_MODE { 100 } else { 8 };
pub const DEFAULT_PARAMS_THRESHOLD: usize = if DEBUG_MODE { 100 } else { 5 }; 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を使うようにすること /// cloneのコストがあるためなるべく.ref_tを使うようにすること
/// いくつかの構造体は直接Typeを保持していないので、その場合は.tを使う /// いくつかの構造体は直接Typeを保持していないので、その場合は.tを使う
#[allow(unused_variables)] #[allow(unused_variables)]
@ -233,10 +263,7 @@ impl ParamTy {
} }
} }
pub fn map_type<F>(self, f: F) -> Self pub fn map_type(self, f: impl FnOnce(Type) -> Type) -> Self {
where
F: FnOnce(Type) -> Type,
{
match self { match self {
Self::Pos(ty) => Self::Pos(f(ty)), Self::Pos(ty) => Self::Pos(f(ty)),
Self::Kw { name, ty } => Self::Kw { name, ty: 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 pub fn map_default_type(self, f: impl FnOnce(Type) -> Type) -> Self {
where
F: FnOnce(Type) -> Type,
{
match self { match self {
Self::KwWithDefault { name, ty, default } => Self::KwWithDefault { Self::KwWithDefault { name, ty, default } => Self::KwWithDefault {
name, name,
@ -262,10 +286,7 @@ impl ParamTy {
} }
} }
pub fn try_map_type<F, E>(self, f: F) -> Result<Self, E> pub fn try_map_type<E>(self, f: &mut impl FnMut(Type) -> Result<Type, E>) -> Result<Self, E> {
where
F: FnOnce(Type) -> Result<Type, E>,
{
match self { match self {
Self::Pos(ty) => Ok(Self::Pos(f(ty)?)), Self::Pos(ty) => Ok(Self::Pos(f(ty)?)),
Self::Kw { name, ty } => Ok(Self::Kw { name, ty: 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>) { pub fn deconstruct(self) -> (Option<Str>, Type, Option<Type>) {
match self { match self {
Self::Pos(ty) => (None, ty, None), Self::Pos(ty) => (None, ty, None),
@ -309,7 +344,7 @@ impl TryFrom<Type> for SubrType {
type Error = (); type Error = ();
fn try_from(t: Type) -> Result<Self, ()> { fn try_from(t: Type) -> Result<Self, ()> {
match t { 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::Subr(st) => Ok(st),
Type::Quantified(quant) => SubrType::try_from(*quant), Type::Quantified(quant) => SubrType::try_from(*quant),
Type::Refinement(refine) => Self::try_from(*refine.t), Type::Refinement(refine) => Self::try_from(*refine.t),
@ -521,23 +556,72 @@ impl SubrType {
|| self.return_t.contains_tp(target) || 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::new(
self.kind, self.kind,
self.non_default_params self.non_default_params
.into_iter() .into_iter()
.map(|pt| pt.map_type(&f)) .map(|pt| pt.map_type(f))
.collect(), .collect(),
self.var_params.map(|pt| pt.map_type(&f)), self.var_params.map(|pt| pt.map_type(f)),
self.default_params self.default_params
.into_iter() .into_iter()
.map(|pt| pt.map_type(&f).map_default_type(&f)) .map(|pt| pt.map_type(f).map_default_type(f))
.collect(), .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), 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 { pub fn contains_value(&self, target: &ValueObj) -> bool {
self.non_default_params self.non_default_params
.iter() .iter()
@ -1923,7 +2007,7 @@ impl HasLevel for Type {
Some(min) Some(min)
} }
} }
_ => None, mono_type_pattern!() => None,
} }
} }
@ -2000,7 +2084,7 @@ impl HasLevel for Type {
sub.set_level(level); sub.set_level(level);
sup.set_level(level); sup.set_level(level);
} }
_ => {} mono_type_pattern!() => {} //_ => {}
} }
} }
} }
@ -2744,6 +2828,14 @@ impl Type {
<&FreeTyVar>::try_from(self).ok() <&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 { pub fn contains_tvar(&self, target: &FreeTyVar) -> bool {
match self { match self {
Self::FreeVar(fv) if fv.is_linked() => fv.crack().contains_tvar(target), 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)) || after.as_ref().map_or(false, |t| t.contains_tvar(target))
} }
Self::Bounded { sub, sup } => sub.contains_tvar(target) || sup.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::Poly { params, .. } => params.iter().any(|tp| tp.contains_type(target)),
Self::Quantified(t) => t.contains_type(target), Self::Quantified(t) => t.contains_type(target),
Self::Subr(subr) => subr.contains_type(target), Self::Subr(subr) => subr.contains_type(target),
// TODO: preds Self::Refinement(refine) => {
Self::Refinement(refine) => refine.t.contains_type(target), refine.t.contains_type(target) || refine.pred.contains_t(target)
}
Self::Structural(ty) => ty.contains_type(target), Self::Structural(ty) => ty.contains_type(target),
Self::Proj { lhs, .. } => lhs.contains_type(target), Self::Proj { lhs, .. } => lhs.contains_type(target),
Self::ProjCall { lhs, args, .. } => { Self::ProjCall { lhs, args, .. } => {
@ -2844,7 +2941,11 @@ impl Type {
|| after.as_ref().map_or(false, |t| t.contains_type(target)) || after.as_ref().map_or(false, |t| t.contains_type(target))
} }
Self::Bounded { sub, sup } => sub.contains_type(target) || sup.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)) || after.as_ref().map_or(false, |t| t.contains_tp(target))
} }
Self::Bounded { sub, sup } => sub.contains_tp(target) || sup.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 { pub fn contains_value(&self, target: &ValueObj) -> bool {
match self { match self {
Self::FreeVar(fv) if fv.is_linked() => fv.crack().contains_value(target), 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::Record(rec) => rec.iter().any(|(_, t)| t.contains_value(target)),
Self::NamedTuple(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)), 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)) || after.as_ref().map_or(false, |t| t.contains_value(target))
} }
Self::Bounded { sub, sup } => sub.contains_value(target) || sup.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::Poly { params, .. } => params.iter().any(|tp| tp.contains_type(self)),
Self::Quantified(t) => t.contains_type(self), Self::Quantified(t) => t.contains_type(self),
Self::Subr(subr) => subr.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::Structural(ty) => ty.contains_type(self),
Self::Proj { lhs, .. } => lhs.contains_type(self), Self::Proj { lhs, .. } => lhs.contains_type(self),
Self::ProjCall { lhs, args, .. } => { Self::ProjCall { lhs, args, .. } => {
@ -2944,7 +3056,11 @@ impl Type {
|| after.as_ref().map_or(false, |t| t.contains_type(self)) || after.as_ref().map_or(false, |t| t.contains_type(self))
} }
Self::Bounded { sub, sup } => sub.contains_type(self) || sup.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 { pub fn into_refinement(self) -> RefinementType {
match self { 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 => { Type::Nat => {
let var = FRESH_GEN.fresh_varname(); let var = FRESH_GEN.fresh_varname();
RefinementType::new( RefinementType::new(
@ -3288,7 +3404,7 @@ impl Type {
pub fn deconstruct_refinement(self) -> Result<(Str, Type, Predicate), Type> { pub fn deconstruct_refinement(self) -> Result<(Str, Type, Predicate), Type> {
match self { 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()), Type::Refinement(r) => Ok(r.deconstruct()),
_ => Err(self), _ => Err(self),
} }
@ -3310,6 +3426,8 @@ impl Type {
fv.crack().destructive_coerce(); fv.crack().destructive_coerce();
} }
Type::FreeVar(fv) if fv.is_unbound_and_sandwiched() => { 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(); let (sub, _sup) = fv.get_subsup().unwrap();
sub.destructive_coerce(); sub.destructive_coerce();
self.destructive_link(&sub); 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(), Type::Subr(subr) => subr.destructive_coerce(),
// TODO: // TODO:
_ => {} _ => {}
@ -3338,6 +3482,7 @@ impl Type {
fv.crack().undoable_coerce(list); fv.crack().undoable_coerce(list);
} }
Type::FreeVar(fv) if fv.is_unbound_and_sandwiched() => { Type::FreeVar(fv) if fv.is_unbound_and_sandwiched() => {
set_recursion_limit!({}, 128);
let (sub, _sup) = fv.get_subsup().unwrap(); let (sub, _sup) = fv.get_subsup().unwrap();
sub.undoable_coerce(list); sub.undoable_coerce(list);
self.undoable_link(&sub, list); self.undoable_link(&sub, list);
@ -3395,6 +3540,7 @@ impl Type {
base base
} }
} }
Self::FreeVar(_) => set! {},
Self::Ref(ty) => ty.qvars_inner(), Self::Ref(ty) => ty.qvars_inner(),
Self::RefMut { before, after } => before.qvars_inner().concat( Self::RefMut { before, after } => before.qvars_inner().concat(
after after
@ -3418,6 +3564,7 @@ impl Type {
Self::Refinement(refine) => refine.t.qvars_inner().concat(refine.pred.qvars()), Self::Refinement(refine) => refine.t.qvars_inner().concat(refine.pred.qvars()),
// ((|T| T -> T) and U).qvars() == U.qvars() // ((|T| T -> T) and U).qvars() == U.qvars()
// Self::Quantified(quant) => quant.qvars(), // Self::Quantified(quant) => quant.qvars(),
Self::Quantified(_) => set! {},
Self::Poly { params, .. } => params Self::Poly { params, .. } => params
.iter() .iter()
.fold(set! {}, |acc, tp| acc.concat(tp.qvars())), .fold(set! {}, |acc, tp| acc.concat(tp.qvars())),
@ -3428,7 +3575,7 @@ impl Type {
Self::Structural(ty) => ty.qvars_inner(), Self::Structural(ty) => ty.qvars_inner(),
Self::Guard(guard) => guard.to.qvars_inner(), Self::Guard(guard) => guard.to.qvars_inner(),
Self::Bounded { sub, sup } => sub.qvars_inner().concat(sup.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() param_ts.iter().any(|t| t.has_qvar()) || return_t.has_qvar()
} }
Self::Subr(subr) => subr.has_qvar(), Self::Subr(subr) => subr.has_qvar(),
Self::Quantified(_) => false,
// Self::Quantified(quant) => quant.has_qvar(), // Self::Quantified(quant) => quant.has_qvar(),
Self::Record(r) => r.values().any(|t| t.has_qvar()), Self::Record(r) => r.values().any(|t| t.has_qvar()),
Self::NamedTuple(r) => r.iter().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::Structural(ty) => ty.has_qvar(),
Self::Guard(guard) => guard.to.has_qvar(), Self::Guard(guard) => guard.to.has_qvar(),
Self::Bounded { sub, sup } => sub.has_qvar() || sup.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 } => { Self::Bounded { sub, sup } => {
sub.has_undoable_linked_var() || sup.has_undoable_linked_var() 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::Structural(ty) => ty.has_unbound_var(),
Self::Guard(guard) => guard.to.has_unbound_var(), Self::Guard(guard) => guard.to.has_unbound_var(),
Self::Bounded { sub, sup } => sub.has_unbound_var() || sup.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. // At least in situations where this function is needed, self cannot be Quantified.
Self::Quantified(quant) => { Self::Quantified(quant) => {
if quant.return_t()?.is_generalized() { 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() quant.return_t()
} }
@ -3942,41 +4090,41 @@ impl Type {
} }
Self::Subr(subr) => Self::Subr(subr.derefine()), Self::Subr(subr) => Self::Subr(subr.derefine()),
Self::Quantified(quant) => quant.derefine().quantify(), Self::Quantified(quant) => quant.derefine().quantify(),
other => other.clone(), mono_type_pattern!() => self.clone(),
} }
} }
/// ```erg /// ```erg
/// (T or U).eliminate_sub(T) == U /// (T or U).eliminate_subsup(T) == U
/// ?X(<: T or U).eliminate_sub(T) == ?X(<: 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 { 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() => { Self::FreeVar(ref fv) if fv.constraint_is_sandwiched() => {
let (sub, sup) = fv.get_subsup().unwrap(); let (sub, sup) = fv.get_subsup().unwrap();
fv.do_avoiding_recursion(|| { fv.do_avoiding_recursion(|| {
let sub = sub.eliminate_sub(target); let sub = sub.eliminate_subsup(target);
let sup = sup.eliminate_sub(target); let sup = sup.eliminate_subsup(target);
self.update_tyvar(sub, sup, None, false); self.update_tyvar(sub, sup, None, false);
}); });
self self
} }
Self::And(l, r) => { Self::And(l, r) => {
if l.addr_eq(target) { if l.addr_eq(target) {
return r.eliminate_sub(target); return r.eliminate_subsup(target);
} else if r.addr_eq(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) => { Self::Or(l, r) => {
if l.addr_eq(target) { if l.addr_eq(target) {
return r.eliminate_sub(target); return r.eliminate_subsup(target);
} else if r.addr_eq(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, other => other,
} }
@ -3992,8 +4140,10 @@ impl Type {
} }
match self { match self {
Self::FreeVar(fv) if fv.is_linked() => fv.unwrap_linked().eliminate_recursion(target), Self::FreeVar(fv) if fv.is_linked() => fv.unwrap_linked().eliminate_recursion(target),
Self::FreeVar(_) => self,
Self::Refinement(mut refine) => { Self::Refinement(mut refine) => {
refine.t = Box::new(refine.t.eliminate_recursion(target)); 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::Refinement(refine)
} }
Self::Record(mut rec) => { Self::Record(mut rec) => {
@ -4052,7 +4202,7 @@ impl Type {
sub: Box::new(sub.eliminate_recursion(target)), sub: Box::new(sub.eliminate_recursion(target)),
sup: Box::new(sup.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(); self = to.clone();
} }
match self { 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) => { Self::FreeVar(fv) => {
let fv_clone = fv.deep_clone(); let fv_clone = fv.deep_clone();
if let Some((sub, sup)) = fv_clone.get_subsup() { if let Some((sub, sup)) = fv_clone.get_subsup() {
@ -4158,6 +4308,7 @@ impl Type {
} }
Self::Refinement(mut refine) => { Self::Refinement(mut refine) => {
refine.t = Box::new(refine.t._replace(target, to)); refine.t = Box::new(refine.t._replace(target, to));
refine.pred = Box::new(refine.pred._replace_t(target, to));
Self::Refinement(refine) Self::Refinement(refine)
} }
Self::Record(mut rec) => { Self::Record(mut rec) => {
@ -4219,13 +4370,13 @@ impl Type {
sub: Box::new(sub._replace(target, to)), sub: Box::new(sub._replace(target, to)),
sup: Box::new(sup._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 { fn _replace_tp(self, target: &TyParam, to: &TyParam) -> Type {
match self { 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) => { Self::FreeVar(fv) => {
let fv_clone = fv.deep_clone(); let fv_clone = fv.deep_clone();
if let Some((sub, sup)) = fv_clone.get_subsup() { if let Some((sub, sup)) = fv_clone.get_subsup() {
@ -4246,7 +4397,7 @@ impl Type {
} }
Self::Refinement(mut refine) => { Self::Refinement(mut refine) => {
refine.t = Box::new(refine.t._replace_tp(target, to)); 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::Refinement(refine)
} }
Self::Record(mut rec) => { Self::Record(mut rec) => {
@ -4305,13 +4456,180 @@ impl Type {
sub: Box::new(sub._replace_tp(target, to)), sub: Box::new(sub._replace_tp(target, to)),
sup: Box::new(sup._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 { fn replace_param(self, target: &str, to: &str) -> Self {
match 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) => { Self::Refinement(mut refine) => {
*refine.t = refine.t.replace_param(target, to); *refine.t = refine.t.replace_param(target, to);
Self::Refinement(refine) Self::Refinement(refine)
@ -4336,11 +4654,17 @@ impl Type {
/// TyParam::Value(ValueObj::Type(_)) => TyParam::Type /// TyParam::Value(ValueObj::Type(_)) => TyParam::Type
pub fn normalize(self) -> Self { pub fn normalize(self) -> Self {
match 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 } => { Self::Poly { name, params } => {
let params = params.into_iter().map(|tp| tp.normalize()).collect(); let params = params.into_iter().map(|tp| tp.normalize()).collect();
Self::Poly { name, params } 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) => { Self::Subr(mut subr) => {
for nd in subr.non_default_params.iter_mut() { for nd in subr.non_default_params.iter_mut() {
*nd.typ_mut() = std::mem::take(nd.typ_mut()).normalize(); *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::Or(l, r) => l.normalize() | r.normalize(),
Self::Not(ty) => !ty.normalize(), Self::Not(ty) => !ty.normalize(),
Self::Structural(ty) => ty.normalize().structuralize(), Self::Structural(ty) => ty.normalize().structuralize(),
Self::Quantified(quant) => quant.normalize().quantify(),
Self::Guard(guard) => Self::Guard(GuardType::new( Self::Guard(guard) => Self::Guard(GuardType::new(
guard.namespace, guard.namespace,
guard.target, guard.target,
@ -4396,7 +4721,12 @@ impl Type {
sub: Box::new(sub.normalize()), sub: Box::new(sub.normalize()),
sup: Box::new(sup.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; return;
} }
let to = to.clone().eliminate_sub(self).eliminate_recursion(self);
match self { match self {
Self::FreeVar(fv) => fv.link(&to), Self::FreeVar(fv) => {
Self::Refinement(refine) => refine.t.destructive_link(&to), let to = to.clone().eliminate_subsup(self).eliminate_recursion(self);
_ => panic!("{self} is not a free variable"), 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; return;
} }
match self { 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), 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()) .union(&sup.contained_ts())
}) })
} }
Self::FreeVar(_) => set! { self.clone() },
Self::Refinement(refine) => refine.t.contained_ts(), Self::Refinement(refine) => refine.t.contained_ts(),
Self::Ref(t) => t.contained_ts(), Self::Ref(t) => t.contained_ts(),
Self::RefMut { before, .. } => before.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.extend(params.iter().flat_map(|tp| tp.contained_ts()));
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() => { Self::FreeVar(fv) if fv.is_generalized() => {
fv.update_init(); fv.update_init();
} }
Self::FreeVar(_) => {}
// TODO: T(:> X, <: Y).dereference() // TODO: T(:> X, <: Y).dereference()
Self::Refinement(refine) => refine.t.dereference(), Self::Refinement(refine) => {
refine.t.dereference();
refine.pred.dereference();
}
Self::Ref(t) => { Self::Ref(t) => {
t.dereference(); t.dereference();
} }
@ -4725,7 +5074,7 @@ impl Type {
Self::Guard(guard) => { Self::Guard(guard) => {
guard.to.dereference(); 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::free::{Constraint, HasLevel};
use super::typaram::TyParam; use super::typaram::TyParam;
use super::value::ValueObj; use super::value::ValueObj;
use super::Type;
#[derive(Debug, Clone, PartialEq, Eq, Hash)] #[derive(Debug, Clone, PartialEq, Eq, Hash, Default)]
pub enum Predicate { pub enum Predicate {
Value(ValueObj), // True/False Value(ValueObj), // True/False
Const(Str), Const(Str),
@ -63,6 +64,7 @@ pub enum Predicate {
Or(Box<Predicate>, Box<Predicate>), Or(Box<Predicate>, Box<Predicate>),
And(Box<Predicate>, Box<Predicate>), And(Box<Predicate>, Box<Predicate>),
Not(Box<Predicate>), Not(Box<Predicate>),
#[default]
Failure, Failure,
} }
@ -860,7 +862,7 @@ impl Predicate {
pub fn contains_value(&self, value: &ValueObj) -> bool { pub fn contains_value(&self, value: &ValueObj) -> bool {
match self { match self {
Self::Value(v) => v == value, Self::Value(v) => v.contains(value),
Self::Const(_) => false, Self::Const(_) => false,
Self::Call { receiver, args, .. } => { Self::Call { receiver, args, .. } => {
receiver.contains_value(value) || args.iter().any(|a| a.contains_value(value)) 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 { pub fn contains_tp(&self, tp: &TyParam) -> bool {
match self { match self {
Self::Value(_) | Self::Failure => false, Self::Value(v) => v.contains_tp(tp),
Self::Const(_) => false,
Self::Call { receiver, args, .. } => { Self::Call { receiver, args, .. } => {
receiver.contains_tp(tp) || args.iter().any(|a| a.contains_tp(tp)) 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::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::And(lhs, rhs) | Self::Or(lhs, rhs) => lhs.contains_tp(tp) || rhs.contains_tp(tp),
Self::Not(pred) => pred.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 { 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::Const(_) => self,
Self::Call { Self::Call {
receiver, receiver,
args, args,
name, name,
} => Self::Call { } => Self::Call {
receiver: receiver.replace(target, to), receiver: receiver.map_t(f),
args: args.into_iter().map(|a| a.replace(target, to)).collect(), args: args.into_iter().map(|a| a.map_t(f)).collect(),
name, name,
}, },
Self::Attr { receiver, name } => Self::Attr { Self::Attr { receiver, name } => Self::Attr {
receiver: receiver.replace(target, to), receiver: receiver.map_t(f),
name, name,
}, },
Self::Equal { lhs, rhs } => Self::Equal { Self::Equal { lhs, rhs } => Self::Equal {
lhs, lhs,
rhs: rhs.replace(target, to), rhs: rhs.map_t(f),
}, },
Self::GreaterEqual { lhs, rhs } => Self::GreaterEqual { Self::GreaterEqual { lhs, rhs } => Self::GreaterEqual {
lhs, lhs,
rhs: rhs.replace(target, to), rhs: rhs.map_t(f),
}, },
Self::LessEqual { lhs, rhs } => Self::LessEqual { Self::LessEqual { lhs, rhs } => Self::LessEqual {
lhs, lhs,
rhs: rhs.replace(target, to), rhs: rhs.map_t(f),
}, },
Self::NotEqual { lhs, rhs } => Self::NotEqual { Self::NotEqual { lhs, rhs } => Self::NotEqual {
lhs, lhs,
rhs: rhs.replace(target, to), rhs: rhs.map_t(f),
}, },
Self::GeneralEqual { lhs, rhs } => Self::GeneralEqual { Self::GeneralEqual { lhs, rhs } => Self::GeneralEqual {
lhs: Box::new(lhs.replace_tp(target, to)), lhs: Box::new(lhs.map_t(f)),
rhs: Box::new(rhs.replace_tp(target, to)), rhs: Box::new(rhs.map_t(f)),
}, },
Self::GeneralLessEqual { lhs, rhs } => Self::GeneralLessEqual { Self::GeneralLessEqual { lhs, rhs } => Self::GeneralLessEqual {
lhs: Box::new(lhs.replace_tp(target, to)), lhs: Box::new(lhs.map_t(f)),
rhs: Box::new(rhs.replace_tp(target, to)), rhs: Box::new(rhs.map_t(f)),
}, },
Self::GeneralGreaterEqual { lhs, rhs } => Self::GeneralGreaterEqual { Self::GeneralGreaterEqual { lhs, rhs } => Self::GeneralGreaterEqual {
lhs: Box::new(lhs.replace_tp(target, to)), lhs: Box::new(lhs.map_t(f)),
rhs: Box::new(rhs.replace_tp(target, to)), rhs: Box::new(rhs.map_t(f)),
}, },
Self::GeneralNotEqual { lhs, rhs } => Self::GeneralNotEqual { Self::GeneralNotEqual { lhs, rhs } => Self::GeneralNotEqual {
lhs: Box::new(lhs.replace_tp(target, to)), lhs: Box::new(lhs.map_t(f)),
rhs: Box::new(rhs.replace_tp(target, to)), rhs: Box::new(rhs.map_t(f)),
}, },
Self::And(lhs, rhs) => Self::And( Self::And(lhs, rhs) => Self::And(Box::new(lhs.map_t(f)), Box::new(rhs.map_t(f))),
Box::new(lhs.replace_tp(target, to)), Self::Or(lhs, rhs) => Self::Or(Box::new(lhs.map_t(f)), Box::new(rhs.map_t(f))),
Box::new(rhs.replace_tp(target, to)), Self::Not(pred) => Self::Not(Box::new(pred.map_t(f))),
), _ => self,
Self::Or(lhs, rhs) => Self::Or( }
Box::new(lhs.replace_tp(target, to)), }
Box::new(rhs.replace_tp(target, to)),
), pub fn map_tp(self, f: &mut impl FnMut(TyParam) -> TyParam) -> Self {
Self::Not(pred) => Self::Not(Box::new(pred.replace_tp(target, to))), 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::cmp::Ordering;
use std::fmt; use std::fmt;
use std::ops::{Add, Div, Mul, Neg, Range, RangeInclusive, Sub}; use std::ops::{Add, Div, Mul, Neg, Range, RangeInclusive, Sub};
use std::sync::Arc;
use erg_common::consts::DEBUG_MODE; use erg_common::consts::DEBUG_MODE;
use erg_common::dict::Dict; use erg_common::dict::Dict;
use erg_common::set::Set; use erg_common::set::Set;
use erg_common::traits::{LimitedDisplay, StructuralEq}; 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::ast::ConstLambda;
use erg_parser::token::TokenKind; use erg_parser::token::TokenKind;
@ -19,7 +18,7 @@ use super::free::{
CanbeFree, Constraint, FreeKind, FreeTyParam, FreeTyVar, HasLevel, Level, GENERIC_LEVEL, CanbeFree, Constraint, FreeKind, FreeTyParam, FreeTyVar, HasLevel, Level, GENERIC_LEVEL,
}; };
use super::value::ValueObj; use super::value::ValueObj;
use super::{ConstSubr, Field, ParamTy, ReplaceTable, UserConstSubr}; use super::{Field, ParamTy, ReplaceTable};
use super::{Type, CONTAINER_OMIT_THRESHOLD}; use super::{Type, CONTAINER_OMIT_THRESHOLD};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] #[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> { impl TryFrom<TyParam> for Dict<TyParam, TyParam> {
type Error = (); type Error = ();
fn try_from(tp: TyParam) -> Result<Self, ()> { fn try_from(tp: TyParam) -> Result<Self, ()> {
@ -1197,11 +1125,16 @@ impl TyParam {
base base
} }
} }
Self::FreeVar(_) => set! {},
Self::Type(t) => t.qvars(), Self::Type(t) => t.qvars(),
Self::Proj { obj, .. } => obj.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) => { Self::List(ts) | Self::Tuple(ts) => {
ts.iter().fold(set! {}, |acc, t| acc.concat(t.qvars())) 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::Set(ts) => ts.iter().fold(set! {}, |acc, t| acc.concat(t.qvars())),
Self::Dict(ts) => ts.iter().fold(set! {}, |acc, (k, v)| { Self::Dict(ts) => ts.iter().fold(set! {}, |acc, (k, v)| {
acc.concat(k.qvars().concat(v.qvars())) acc.concat(k.qvars().concat(v.qvars()))
@ -1217,8 +1150,8 @@ impl TyParam {
Self::BinOp { lhs, rhs, .. } => lhs.qvars().concat(rhs.qvars()), Self::BinOp { lhs, rhs, .. } => lhs.qvars().concat(rhs.qvars()),
Self::App { args, .. } => args.iter().fold(set! {}, |acc, p| acc.concat(p.qvars())), Self::App { args, .. } => args.iter().fold(set! {}, |acc, p| acc.concat(p.qvars())),
Self::Erased(t) => t.qvars(), Self::Erased(t) => t.qvars(),
Self::Value(ValueObj::Type(t)) => t.typ().qvars(), Self::Value(val) => val.qvars(),
_ => set! {}, Self::Mono(_) | Self::Failure => set! {},
} }
} }
@ -1226,9 +1159,12 @@ impl TyParam {
match self { match self {
Self::FreeVar(fv) if fv.is_unbound() && fv.is_generalized() => true, Self::FreeVar(fv) if fv.is_unbound() && fv.is_generalized() => true,
Self::FreeVar(fv) if fv.is_linked() => fv.crack().has_qvar(), Self::FreeVar(fv) if fv.is_linked() => fv.crack().has_qvar(),
Self::FreeVar(_) => false,
Self::Type(t) => t.has_qvar(), Self::Type(t) => t.has_qvar(),
Self::Proj { obj, .. } => obj.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::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::Set(tps) => tps.iter().any(|tp| tp.has_qvar()),
Self::Dict(tps) => tps.iter().any(|(k, v)| k.has_qvar() || v.has_qvar()), Self::Dict(tps) => tps.iter().any(|(k, v)| k.has_qvar() || v.has_qvar()),
Self::Record(rec) | Self::DataClass { fields: rec, .. } => { Self::Record(rec) | Self::DataClass { fields: rec, .. } => {
@ -1239,8 +1175,8 @@ impl TyParam {
Self::BinOp { lhs, rhs, .. } => lhs.has_qvar() || rhs.has_qvar(), Self::BinOp { lhs, rhs, .. } => lhs.has_qvar() || rhs.has_qvar(),
Self::App { args, .. } => args.iter().any(|p| p.has_qvar()), Self::App { args, .. } => args.iter().any(|p| p.has_qvar()),
Self::Erased(t) => t.has_qvar(), Self::Erased(t) => t.has_qvar(),
Self::Value(ValueObj::Type(t)) => t.typ().has_qvar(), Self::Value(val) => val.has_qvar(),
_ => false, Self::Mono(_) | Self::Failure => false,
} }
} }
@ -1250,7 +1186,11 @@ impl TyParam {
Self::Type(t) => t.contains_tvar(target), Self::Type(t) => t.contains_tvar(target),
Self::Erased(t) => t.contains_tvar(target), Self::Erased(t) => t.contains_tvar(target),
Self::Proj { obj, .. } => obj.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::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::Set(ts) => ts.iter().any(|t| t.contains_tvar(target)),
Self::Dict(ts) => ts Self::Dict(ts) => ts
.iter() .iter()
@ -1262,7 +1202,7 @@ impl TyParam {
Self::UnaryOp { val, .. } => val.contains_tvar(target), Self::UnaryOp { val, .. } => val.contains_tvar(target),
Self::BinOp { lhs, rhs, .. } => lhs.contains_tvar(target) || rhs.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::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, _ => false,
} }
} }
@ -1289,7 +1229,7 @@ impl TyParam {
Self::UnaryOp { val, .. } => val.contains_type(target), Self::UnaryOp { val, .. } => val.contains_type(target),
Self::BinOp { lhs, rhs, .. } => lhs.contains_type(target) || rhs.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::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, _ => false,
} }
} }
@ -1319,7 +1259,7 @@ impl TyParam {
Self::UnaryOp { val, .. } => val.contains_tp(target), Self::UnaryOp { val, .. } => val.contains_tp(target),
Self::BinOp { lhs, rhs, .. } => lhs.contains_tp(target) || rhs.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::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, _ => false,
} }
} }
@ -1381,7 +1321,7 @@ impl TyParam {
.iter() .iter()
.any(|(k, v)| k.contains_tp(self) || v.contains_tp(self)), .any(|(k, v)| k.contains_tp(self) || v.contains_tp(self)),
Self::Type(t) => t.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), Self::Erased(t) => t.contains_tp(self),
_ => false, _ => false,
} }
@ -1418,7 +1358,7 @@ impl TyParam {
Self::BinOp { lhs, rhs, .. } => lhs.has_unbound_var() || rhs.has_unbound_var(), Self::BinOp { lhs, rhs, .. } => lhs.has_unbound_var() || rhs.has_unbound_var(),
Self::App { args, .. } => args.iter().any(|p| p.has_unbound_var()), Self::App { args, .. } => args.iter().any(|p| p.has_unbound_var()),
Self::Erased(t) => t.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, _ => false,
} }
} }
@ -1451,7 +1391,7 @@ impl TyParam {
} }
Self::App { args, .. } => args.iter().any(|p| p.has_undoable_linked_var()), Self::App { args, .. } => args.iter().any(|p| p.has_undoable_linked_var()),
Self::Erased(t) => t.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, _ => false,
} }
} }
@ -1531,7 +1471,7 @@ impl TyParam {
if self.qual_name().is_some_and(|n| n == var) { if self.qual_name().is_some_and(|n| n == var) {
return to.clone(); 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 { pub fn replace(self, target: &TyParam, to: &TyParam) -> TyParam {
@ -1546,7 +1486,7 @@ impl TyParam {
match self { match self {
TyParam::Type(t) => TyParam::t(t._replace_tp(target, to)), TyParam::Type(t) => TyParam::t(t._replace_tp(target, to)),
TyParam::Value(val) => TyParam::value(val.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::Type(t) => Self::t(t._replace(target, to)),
Self::Erased(t) => Self::erased(t._replace(target, to)), Self::Erased(t) => Self::erased(t._replace(target, to)),
Self::Value(ValueObj::Type(t)) => { Self::Value(val) => Self::Value(val.replace_t(target, to)),
Self::value(ValueObj::Type(t.mapped_t(|t| t._replace(target, to)))) _ => self.map(&mut |tp| tp.replace_t(target, to)),
}
_ => self.map(|tp| tp.replace_t(target, to)),
} }
} }
@ -1594,11 +1532,21 @@ impl TyParam {
if self.addr_eq(to) { if self.addr_eq(to) {
return; return;
} }
if DEBUG_MODE && self.level() == Some(GENERIC_LEVEL) { if self.level() == Some(GENERIC_LEVEL) {
if DEBUG_MODE {
panic!("{self} is fixed"); panic!("{self} is fixed");
} }
return;
}
match self { 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) => { Self::Type(t) => {
if let Ok(to) = <&Type>::try_from(to) { if let Ok(to) = <&Type>::try_from(to) {
t.destructive_link(to); t.destructive_link(to);
@ -1625,7 +1573,28 @@ impl TyParam {
return; return;
} }
match self { 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"), _ => panic!("{self} is not a free variable"),
} }
} }
@ -1695,7 +1664,7 @@ impl TyParam {
match self { match self {
Self::FreeVar(fv) if fv.is_linked() => fv.crack().typarams(), Self::FreeVar(fv) if fv.is_linked() => fv.crack().typarams(),
Self::Type(t) => t.typarams(), Self::Type(t) => t.typarams(),
Self::Value(ValueObj::Type(t)) => t.typ().typarams(), Self::Value(val) => val.typarams(),
Self::App { args, .. } => args.clone(), Self::App { args, .. } => args.clone(),
_ => vec![], _ => vec![],
} }
@ -1705,7 +1674,7 @@ impl TyParam {
match self { match self {
Self::FreeVar(fv) if fv.is_linked() => fv.crack().contained_ts(), Self::FreeVar(fv) if fv.is_linked() => fv.crack().contained_ts(),
Self::Type(t) => t.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 Self::App { args, .. } => args
.iter() .iter()
.fold(set! {}, |acc, p| acc.concat(p.contained_ts())), .fold(set! {}, |acc, p| acc.concat(p.contained_ts())),
@ -1723,8 +1692,9 @@ impl TyParam {
Self::FreeVar(fv) if fv.is_generalized() => { Self::FreeVar(fv) if fv.is_generalized() => {
fv.update_init(); fv.update_init();
} }
Self::FreeVar(_) => {}
Self::Type(t) => t.dereference(), Self::Type(t) => t.dereference(),
Self::Value(ValueObj::Type(t)) => t.typ_mut().dereference(), Self::Value(val) => val.dereference(),
Self::App { args, .. } => { Self::App { args, .. } => {
for arg in args { for arg in args {
arg.dereference(); arg.dereference();
@ -1780,7 +1750,7 @@ impl TyParam {
rhs.dereference(); rhs.dereference();
} }
Self::Erased(t) => t.dereference(), Self::Erased(t) => t.dereference(),
_ => {} Self::Mono(_) | Self::Failure => {}
} }
} }
@ -1807,6 +1777,7 @@ impl TyParam {
match self { match self {
Self::FreeVar(fv) if fv.is_linked() => fv.crack().variables(), 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(fv) if fv.get_type().is_some() => fv.get_type().unwrap().variables(),
Self::FreeVar(_) => set! {},
Self::Mono(name) => set! { name.clone() }, Self::Mono(name) => set! { name.clone() },
Self::App { name, args } => { Self::App { name, args } => {
let mut set = set! { name.clone() }; let mut set = set! { name.clone() };
@ -1841,14 +1812,21 @@ impl TyParam {
set set
} }
Self::Type(t) | Self::Erased(t) => t.variables(), Self::Type(t) | Self::Erased(t) => t.variables(),
Self::Value(ValueObj::Type(t)) => t.typ().variables(), Self::Value(val) => val.variables(),
_ => set! {}, 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 { match self {
TyParam::FreeVar(fv) if fv.is_linked() => f(fv.unwrap_linked()), 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 } => { TyParam::App { name, args } => {
let new_args = args.into_iter().map(f).collect::<Vec<_>>(); let new_args = args.into_iter().map(f).collect::<Vec<_>>();
TyParam::app(name, new_args) TyParam::app(name, new_args)
@ -1889,17 +1867,87 @@ impl TyParam {
obj: Box::new(f(*obj)), obj: Box::new(f(*obj)),
attr, attr,
}, },
TyParam::ProjCall { obj, attr, args } => { TyParam::ProjCall { obj, attr, args } => TyParam::ProjCall {
let new_args = args.into_iter().map(&f).collect::<Vec<_>>();
TyParam::ProjCall {
obj: Box::new(f(*obj)), obj: Box::new(f(*obj)),
attr, 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(|tp| tp.map_t(f)).collect::<Vec<_>>();
TyParam::ProjCall {
obj: Box::new(obj.map_t(f)),
attr,
args: new_args, 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)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]

View file

@ -7,6 +7,7 @@ use std::hash::{Hash, Hasher};
use std::ops::Neg; use std::ops::Neg;
use std::sync::Arc; use std::sync::Arc;
use erg_common::consts::DEBUG_MODE;
use erg_common::dict::Dict; use erg_common::dict::Dict;
use erg_common::error::{ErrorCore, ErrorKind, Location}; use erg_common::error::{ErrorCore, ErrorKind, Location};
use erg_common::fresh::FRESH_GEN; use erg_common::fresh::FRESH_GEN;
@ -15,7 +16,7 @@ use erg_common::python_util::PythonVersion;
use erg_common::serialize::*; use erg_common::serialize::*;
use erg_common::set::Set; use erg_common::set::Set;
use erg_common::traits::LimitedDisplay; 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_common::{ArcArray, Str};
use erg_parser::ast::{ConstArgs, ConstExpr}; 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::codeobj::{tuple_into_bytes, CodeObj};
use super::constructors::{dict_t, list_t, refinement, set_t, tuple_t, unsized_list_t}; 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::typaram::{OpKind, TyParam};
use super::{ConstSubr, Field, HasType, Predicate, Type}; use super::{ConstSubr, Field, HasType, Predicate, Type};
use super::{CONTAINER_OMIT_THRESHOLD, STR_OMIT_THRESHOLD}; use super::{CONTAINER_OMIT_THRESHOLD, STR_OMIT_THRESHOLD};
@ -220,15 +222,27 @@ pub enum GenTypeObj {
impl fmt::Display for GenTypeObj { impl fmt::Display for GenTypeObj {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 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 { impl LimitedDisplay for GenTypeObj {
fn limited_fmt<W: std::fmt::Write>(&self, f: &mut W, limit: isize) -> std::fmt::Result { fn limited_fmt<W: std::fmt::Write>(&self, f: &mut W, limit: isize) -> std::fmt::Result {
if DEBUG_MODE {
write!(f, "<")?; write!(f, "<")?;
}
self.typ().limited_fmt(f, limit)?; 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) { 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> { 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(()) 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 { fn limited_fmt<W: std::fmt::Write>(&self, f: &mut W, limit: isize) -> std::fmt::Result {
match self { match self {
TypeObj::Builtin { t, .. } => { TypeObj::Builtin { t, .. } => {
if cfg!(feature = "debug") { if DEBUG_MODE {
write!(f, "<type ")?; write!(f, "<type ")?;
t.limited_fmt(f, limit - 1)?; t.limited_fmt(f, limit - 1)?;
write!(f, ">") write!(f, ">")
@ -419,7 +445,7 @@ impl LimitedDisplay for TypeObj {
} }
} }
TypeObj::Generated(t) => { TypeObj::Generated(t) => {
if cfg!(feature = "debug") { if DEBUG_MODE {
write!(f, "<user type ")?; write!(f, "<user type ")?;
t.limited_fmt(f, limit - 1)?; t.limited_fmt(f, limit - 1)?;
write!(f, ">") write!(f, ">")
@ -483,25 +509,66 @@ impl TypeObj {
pub fn map_t(&mut self, f: impl FnOnce(Type) -> Type) { pub fn map_t(&mut self, f: impl FnOnce(Type) -> Type) {
match self { 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), 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 { pub fn mapped_t(mut self, f: impl FnOnce(Type) -> Type) -> Self {
self.map_t(f); self.map_t(f);
self 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 { match self {
TypeObj::Builtin { t, .. } => { TypeObj::Builtin { t, .. } => {
*t = f(t.clone())?; *t = f(std::mem::take(t))?;
Ok(()) Ok(())
} }
TypeObj::Generated(t) => t.try_map_t(f), 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 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 { impl fmt::Debug for ValueObj {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self { match self {
Self::Int(i) => { Self::Int(i) => {
if cfg!(feature = "debug") { if DEBUG_MODE {
write!(f, "Int({i})") write!(f, "Int({i})")
} else { } else {
write!(f, "{i}") write!(f, "{i}")
} }
} }
Self::Nat(n) => { Self::Nat(n) => {
if cfg!(feature = "debug") { if DEBUG_MODE {
write!(f, "Nat({n})") write!(f, "Nat({n})")
} else { } else {
write!(f, "{n}") write!(f, "{n}")
@ -560,7 +645,7 @@ impl fmt::Debug for ValueObj {
} else { } else {
write!(f, "{fl}")?; write!(f, "{fl}")?;
} }
if cfg!(feature = "debug") { if DEBUG_MODE {
write!(f, "f64")?; write!(f, "f64")?;
} }
Ok(()) Ok(())
@ -608,8 +693,8 @@ impl fmt::Debug for ValueObj {
} }
write!(f, "}}") write!(f, "}}")
} }
Self::Subr(subr) => write!(f, "{subr}"), Self::Subr(subr) => subr.fmt(f),
Self::Type(t) => write!(f, "{t}"), Self::Type(t) => t.fmt(f),
Self::None => write!(f, "None"), Self::None => write!(f, "None"),
Self::Ellipsis => write!(f, "Ellipsis"), Self::Ellipsis => write!(f, "Ellipsis"),
Self::NotImplemented => write!(f, "NotImplemented"), 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 { impl LimitedDisplay for ValueObj {
fn limited_fmt<W: std::fmt::Write>(&self, f: &mut W, limit: isize) -> std::fmt::Result { 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 { match self {
ValueObj::Type(obj) => ValueObj::Type(obj.mapped_t(|t| t._replace(target, to))), ValueObj::Type(obj) => ValueObj::Type(obj.mapped_t(f)),
ValueObj::List(lis) => ValueObj::List( ValueObj::List(lis) => ValueObj::List(lis.iter().map(|v| v.clone().map_t(f)).collect()),
lis.iter() ValueObj::Tuple(tup) => {
.map(|v| v.clone().replace_t(target, to)) ValueObj::Tuple(tup.iter().map(|v| v.clone().map_t(f)).collect())
.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::Set(st) => ValueObj::Set(st.into_iter().map(|v| v.map_t(f)).collect()),
ValueObj::Dict(dict) => ValueObj::Dict( ValueObj::Dict(dict) => ValueObj::Dict(
dict.iter() dict.into_iter()
.map(|(k, v)| { .map(|(k, v)| (k.map_t(f), v.map_t(f)))
(
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)))
.collect(), .collect(),
), ),
ValueObj::Record(rec) => {
ValueObj::Record(rec.into_iter().map(|(k, v)| (k, v.map_t(f))).collect())
}
ValueObj::DataClass { name, fields } => ValueObj::DataClass { ValueObj::DataClass { name, fields } => ValueObj::DataClass {
name, name,
fields: fields fields: fields.into_iter().map(|(k, v)| (k, v.map_t(f))).collect(),
.iter()
.map(|(k, v)| (k.clone(), v.clone().replace_t(target, to)))
.collect(),
}, },
ValueObj::UnsizedList(elem) => { ValueObj::UnsizedList(elem) => ValueObj::UnsizedList(Box::new(elem.map_t(f))),
ValueObj::UnsizedList(Box::new(elem.clone().replace_t(target, to)))
}
self_ => self_, 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 { match self {
ValueObj::Type(obj) => ValueObj::Type(obj.mapped_t(|t| t._replace_tp(target, to))), ValueObj::Type(obj) => Ok(ValueObj::Type(obj.try_mapped_t(f)?)),
ValueObj::List(lis) => ValueObj::List( ValueObj::List(lis) => Ok(ValueObj::List(
lis.iter() lis.iter()
.map(|v| v.clone().replace_tp(target, to)) .map(|v| v.clone().try_map_t(f))
.collect(), .collect::<Result<Arc<_>, _>>()?,
), )),
ValueObj::Tuple(tup) => ValueObj::Tuple( ValueObj::Tuple(tup) => Ok(ValueObj::Tuple(
tup.iter() tup.iter()
.map(|v| v.clone().replace_tp(target, to)) .map(|v| v.clone().try_map_t(f))
.collect(), .collect::<Result<Arc<_>, _>>()?,
), )),
ValueObj::Set(st) => ValueObj::Set( ValueObj::Set(st) => Ok(ValueObj::Set(
st.iter() st.into_iter()
.map(|v| v.clone().replace_tp(target, to)) .map(|v| v.try_map_t(f))
.collect(), .collect::<Result<Set<_>, _>>()?,
), )),
ValueObj::Dict(dict) => ValueObj::Dict( ValueObj::Dict(dict) => Ok(ValueObj::Dict(
dict.iter() dict.into_iter()
.map(|(k, v)| { .map(|(k, v)| Ok((k.try_map_t(f)?, v.try_map_t(f)?)))
( .collect::<Result<Dict<_, _>, _>>()?,
k.clone().replace_tp(target, to), )),
v.clone().replace_tp(target, to), ValueObj::Record(rec) => Ok(ValueObj::Record(
) rec.into_iter()
}) .map(|(k, v)| Ok((k, v.try_map_t(f)?)))
.collect(), .collect::<Result<Dict<_, _>, _>>()?,
), )),
ValueObj::Record(rec) => ValueObj::Record( ValueObj::DataClass { name, fields } => Ok(ValueObj::DataClass {
rec.iter()
.map(|(k, v)| (k.clone(), v.clone().replace_tp(target, to)))
.collect(),
),
ValueObj::DataClass { name, fields } => ValueObj::DataClass {
name, name,
fields: fields fields: fields
.iter() .into_iter()
.map(|(k, v)| (k.clone(), v.clone().replace_tp(target, to))) .map(|(k, v)| Ok((k, v.try_map_t(f)?)))
.collect(), .collect::<Result<Dict<_, _>, _>>()?,
}, }),
ValueObj::UnsizedList(elem) => { ValueObj::UnsizedList(elem) => Ok(ValueObj::UnsizedList(Box::new(elem.try_map_t(f)?))),
ValueObj::UnsizedList(Box::new(elem.clone().replace_tp(target, to))) 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_, 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 { pub fn contains(&self, val: &ValueObj) -> bool {
match self { match self {
ValueObj::List(lis) => lis.iter().any(|v| v.contains(val)), ValueObj::List(lis) => lis.iter().any(|v| v.contains(val)),
@ -1714,6 +1932,165 @@ impl ValueObj {
_ => self == val, _ => 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 { pub mod value_set {