mirror of
https://github.com/erg-lang/erg.git
synced 2025-07-07 21:25:31 +00:00
fix: infinite recursion bug
add `Immutable` trait (Type: !Immutable)
This commit is contained in:
parent
de92e295dc
commit
f9eb562848
26 changed files with 415 additions and 163 deletions
|
@ -83,5 +83,5 @@ dinst = "install --path . --features debug --features els"
|
||||||
ntest = "nextest run"
|
ntest = "nextest run"
|
||||||
|
|
||||||
# +nightly
|
# +nightly
|
||||||
# you must specify the --target option
|
# you must specify the --target option (e.g. x86_64-unknown-linux-gnu, aarch64-apple-darwin, x86_64-pc-windows-msvc)
|
||||||
drc_r = "r -Zbuild-std -Zbuild-std-features=core/debug_refcell"
|
drc_r = "r -Zbuild-std -Zbuild-std-features=core/debug_refcell"
|
||||||
|
|
|
@ -5,7 +5,7 @@ use std::str::FromStr;
|
||||||
|
|
||||||
use erg_common::consts::CASE_SENSITIVE;
|
use erg_common::consts::CASE_SENSITIVE;
|
||||||
use erg_common::normalize_path;
|
use erg_common::normalize_path;
|
||||||
use erg_common::traits::{DequeStream, Locational};
|
use erg_common::traits::{DequeStream, Immutable, Locational};
|
||||||
|
|
||||||
use erg_compiler::erg_parser::token::{Token, TokenStream};
|
use erg_compiler::erg_parser::token::{Token, TokenStream};
|
||||||
|
|
||||||
|
@ -18,6 +18,8 @@ use crate::server::ELSResult;
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
pub struct NormalizedUrl(Url);
|
pub struct NormalizedUrl(Url);
|
||||||
|
|
||||||
|
impl Immutable for NormalizedUrl {}
|
||||||
|
|
||||||
impl fmt::Display for NormalizedUrl {
|
impl fmt::Display for NormalizedUrl {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
write!(f, "{}", self.0)
|
write!(f, "{}", self.0)
|
||||||
|
|
|
@ -5,6 +5,7 @@ use std::sync::Arc;
|
||||||
use crate::dict::Dict;
|
use crate::dict::Dict;
|
||||||
use crate::set::Set;
|
use crate::set::Set;
|
||||||
use crate::shared::Shared;
|
use crate::shared::Shared;
|
||||||
|
use crate::traits::Immutable;
|
||||||
use crate::{ArcArray, Str};
|
use crate::{ArcArray, Str};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -45,7 +46,7 @@ impl CacheSet<str> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Hash + Eq + Clone> CacheSet<[T]> {
|
impl<T: Hash + Eq + Clone + Immutable> CacheSet<[T]> {
|
||||||
pub fn get(&self, q: &[T]) -> Arc<[T]> {
|
pub fn get(&self, q: &[T]) -> Arc<[T]> {
|
||||||
if let Some(cached) = self.0.borrow().get(q) {
|
if let Some(cached) = self.0.borrow().get(q) {
|
||||||
return cached.clone();
|
return cached.clone();
|
||||||
|
@ -56,7 +57,18 @@ impl<T: Hash + Eq + Clone> CacheSet<[T]> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Hash + Eq> CacheSet<T> {
|
impl<T: Hash + Eq + Clone> CacheSet<[T]> {
|
||||||
|
pub fn linear_get(&self, q: &[T]) -> Arc<[T]> {
|
||||||
|
if let Some(cached) = self.0.borrow().linear_get(q) {
|
||||||
|
return cached.clone();
|
||||||
|
} // &self.0 is dropped
|
||||||
|
let s = ArcArray::from(q);
|
||||||
|
self.0.borrow_mut().insert(s.clone());
|
||||||
|
s
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Hash + Eq + Immutable> CacheSet<T> {
|
||||||
pub fn get<Q>(&self, q: &Q) -> Arc<T>
|
pub fn get<Q>(&self, q: &Q) -> Arc<T>
|
||||||
where
|
where
|
||||||
Arc<T>: Borrow<Q>,
|
Arc<T>: Borrow<Q>,
|
||||||
|
@ -71,6 +83,21 @@ impl<T: Hash + Eq> CacheSet<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T: Hash + Eq> CacheSet<T> {
|
||||||
|
pub fn linear_get<Q>(&self, q: &Q) -> Arc<T>
|
||||||
|
where
|
||||||
|
Arc<T>: Borrow<Q>,
|
||||||
|
Q: ?Sized + Eq + ToOwned<Owned = T>,
|
||||||
|
{
|
||||||
|
if let Some(cached) = self.0.borrow().linear_get(q) {
|
||||||
|
return cached.clone();
|
||||||
|
} // &self.0 is dropped
|
||||||
|
let s = Arc::from(q.to_owned());
|
||||||
|
self.0.borrow_mut().insert(s.clone());
|
||||||
|
s
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct CacheDict<K, V: ?Sized>(Shared<Dict<K, Arc<V>>>);
|
pub struct CacheDict<K, V: ?Sized>(Shared<Dict<K, Arc<V>>>);
|
||||||
|
|
||||||
|
@ -86,15 +113,26 @@ impl<K: Hash + Eq, V: ?Sized> CacheDict<K, V> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<K: Hash + Eq, V> CacheDict<K, V> {
|
impl<K: Hash + Eq + Immutable, V> CacheDict<K, V> {
|
||||||
pub fn get<Q: ?Sized + Hash + Eq>(&self, k: &Q) -> Option<Arc<V>>
|
pub fn get<Q: ?Sized + Hash + Eq>(&self, k: &Q) -> Option<Arc<V>>
|
||||||
where
|
where
|
||||||
K: Borrow<Q>,
|
K: Borrow<Q>,
|
||||||
{
|
{
|
||||||
self.0.borrow().get(k).cloned()
|
self.0.borrow().get(k).cloned()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<K: Hash + Eq, V> CacheDict<K, V> {
|
||||||
pub fn insert(&self, k: K, v: V) {
|
pub fn insert(&self, k: K, v: V) {
|
||||||
self.0.borrow_mut().insert(k, Arc::new(v));
|
self.0.borrow_mut().insert(k, Arc::new(v));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<K: Eq, V> CacheDict<K, V> {
|
||||||
|
pub fn linear_get<Q: ?Sized + Eq>(&self, k: &Q) -> Option<Arc<V>>
|
||||||
|
where
|
||||||
|
K: Borrow<Q>,
|
||||||
|
{
|
||||||
|
self.0.borrow().linear_get(k).cloned()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ use std::ops::{Index, IndexMut};
|
||||||
|
|
||||||
use crate::fxhash::FxHashMap;
|
use crate::fxhash::FxHashMap;
|
||||||
use crate::get_hash;
|
use crate::get_hash;
|
||||||
|
use crate::traits::Immutable;
|
||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! dict {
|
macro_rules! dict {
|
||||||
|
@ -25,13 +26,13 @@ pub struct Dict<K, V> {
|
||||||
dict: FxHashMap<K, V>,
|
dict: FxHashMap<K, V>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<K: Hash + Eq, V: Hash + Eq> PartialEq for Dict<K, V> {
|
impl<K: Hash + Eq + Immutable, V: Hash + Eq> PartialEq for Dict<K, V> {
|
||||||
fn eq(&self, other: &Dict<K, V>) -> bool {
|
fn eq(&self, other: &Dict<K, V>) -> bool {
|
||||||
self.dict == other.dict
|
self.dict == other.dict
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<K: Hash + Eq, V: Hash + Eq> Eq for Dict<K, V> {}
|
impl<K: Hash + Eq + Immutable, V: Hash + Eq> Eq for Dict<K, V> {}
|
||||||
|
|
||||||
impl<K: Hash, V: Hash> Hash for Dict<K, V> {
|
impl<K: Hash, V: Hash> Hash for Dict<K, V> {
|
||||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||||
|
@ -82,7 +83,7 @@ impl<K: Hash + Eq, V> From<Vec<(K, V)>> for Dict<K, V> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<K: Hash + Eq, V, Q: ?Sized> Index<&Q> for Dict<K, V>
|
impl<K: Hash + Eq + Immutable, V, Q: ?Sized> Index<&Q> for Dict<K, V>
|
||||||
where
|
where
|
||||||
K: Borrow<Q>,
|
K: Borrow<Q>,
|
||||||
Q: Hash + Eq,
|
Q: Hash + Eq,
|
||||||
|
@ -94,7 +95,7 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<K: Hash + Eq, V, Q: ?Sized> IndexMut<&Q> for Dict<K, V>
|
impl<K: Hash + Eq + Immutable, V, Q: ?Sized> IndexMut<&Q> for Dict<K, V>
|
||||||
where
|
where
|
||||||
K: Borrow<Q>,
|
K: Borrow<Q>,
|
||||||
Q: Hash + Eq,
|
Q: Hash + Eq,
|
||||||
|
@ -195,6 +196,15 @@ impl<K, V> Dict<K, V> {
|
||||||
{
|
{
|
||||||
self.dict.retain(f);
|
self.dict.retain(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_by(&self, k: &K, cmp: impl Fn(&K, &K) -> bool) -> Option<&V> {
|
||||||
|
for (k_, v) in self.dict.iter() {
|
||||||
|
if cmp(k, k_) {
|
||||||
|
return Some(v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<K, V> IntoIterator for Dict<K, V> {
|
impl<K, V> IntoIterator for Dict<K, V> {
|
||||||
|
@ -215,7 +225,47 @@ impl<'a, K, V> IntoIterator for &'a Dict<K, V> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<K: Hash + Eq, V> Dict<K, V> {
|
impl<K: Eq, V> Dict<K, V> {
|
||||||
|
/// K: interior-mutable
|
||||||
|
pub fn linear_get<Q>(&self, key: &Q) -> Option<&V>
|
||||||
|
where
|
||||||
|
K: Borrow<Q>,
|
||||||
|
Q: Eq + ?Sized,
|
||||||
|
{
|
||||||
|
self.dict
|
||||||
|
.iter()
|
||||||
|
.find(|(k, _)| (*k).borrow() == key)
|
||||||
|
.map(|(_, v)| v)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn linear_get_mut<Q>(&mut self, key: &Q) -> Option<&mut V>
|
||||||
|
where
|
||||||
|
K: Borrow<Q>,
|
||||||
|
Q: Eq + ?Sized,
|
||||||
|
{
|
||||||
|
self.dict
|
||||||
|
.iter_mut()
|
||||||
|
.find(|(k, _)| (*k).borrow() == key)
|
||||||
|
.map(|(_, v)| v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<K: Eq, V: Eq> Dict<K, V> {
|
||||||
|
/// K: interior-mutable
|
||||||
|
pub fn linear_eq(&self, other: &Self) -> bool {
|
||||||
|
if self.len() != other.len() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (k, v) in self.iter() {
|
||||||
|
if other.linear_get(k) != Some(v) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<K: Hash + Eq + Immutable, V> Dict<K, V> {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get<Q>(&self, k: &Q) -> Option<&V>
|
pub fn get<Q>(&self, k: &Q) -> Option<&V>
|
||||||
where
|
where
|
||||||
|
@ -225,15 +275,6 @@ impl<K: Hash + Eq, V> Dict<K, V> {
|
||||||
self.dict.get(k)
|
self.dict.get(k)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_by(&self, k: &K, cmp: impl Fn(&K, &K) -> bool) -> Option<&V> {
|
|
||||||
for (k_, v) in self.dict.iter() {
|
|
||||||
if cmp(k, k_) {
|
|
||||||
return Some(v);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get_mut<Q>(&mut self, k: &Q) -> Option<&mut V>
|
pub fn get_mut<Q>(&mut self, k: &Q) -> Option<&mut V>
|
||||||
where
|
where
|
||||||
|
@ -260,11 +301,6 @@ impl<K: Hash + Eq, V> Dict<K, V> {
|
||||||
self.dict.contains_key(k)
|
self.dict.contains_key(k)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn insert(&mut self, k: K, v: V) -> Option<V> {
|
|
||||||
self.dict.insert(k, v)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn remove<Q>(&mut self, k: &Q) -> Option<V>
|
pub fn remove<Q>(&mut self, k: &Q) -> Option<V>
|
||||||
where
|
where
|
||||||
|
@ -281,6 +317,13 @@ impl<K: Hash + Eq, V> Dict<K, V> {
|
||||||
{
|
{
|
||||||
self.dict.remove_entry(k)
|
self.dict.remove_entry(k)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<K: Hash + Eq, V> Dict<K, V> {
|
||||||
|
#[inline]
|
||||||
|
pub fn insert(&mut self, k: K, v: V) -> Option<V> {
|
||||||
|
self.dict.insert(k, v)
|
||||||
|
}
|
||||||
|
|
||||||
/// NOTE: This method does not consider pairing with values and keys. That is, a value may be paired with a different key (can be considered equal).
|
/// NOTE: This method does not consider pairing with values and keys. That is, a value may be paired with a different key (can be considered equal).
|
||||||
/// If you need to consider the pairing of the keys and values, use `guaranteed_extend` instead.
|
/// If you need to consider the pairing of the keys and values, use `guaranteed_extend` instead.
|
||||||
|
|
|
@ -6,6 +6,7 @@ use std::path::{Component, Path, PathBuf};
|
||||||
|
|
||||||
use crate::consts::PYTHON_MODE;
|
use crate::consts::PYTHON_MODE;
|
||||||
use crate::env::erg_pkgs_path;
|
use crate::env::erg_pkgs_path;
|
||||||
|
use crate::traits::Immutable;
|
||||||
use crate::{normalize_path, Str};
|
use crate::{normalize_path, Str};
|
||||||
|
|
||||||
/// Guaranteed equivalence path.
|
/// Guaranteed equivalence path.
|
||||||
|
@ -16,6 +17,8 @@ use crate::{normalize_path, Str};
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash, Default, PartialOrd, Ord)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash, Default, PartialOrd, Ord)]
|
||||||
pub struct NormalizedPathBuf(PathBuf);
|
pub struct NormalizedPathBuf(PathBuf);
|
||||||
|
|
||||||
|
impl Immutable for NormalizedPathBuf {}
|
||||||
|
|
||||||
impl fmt::Display for NormalizedPathBuf {
|
impl fmt::Display for NormalizedPathBuf {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
write!(f, "{}", self.display())
|
write!(f, "{}", self.display())
|
||||||
|
|
|
@ -5,6 +5,7 @@ use std::hash::{Hash, Hasher};
|
||||||
use std::iter::FromIterator;
|
use std::iter::FromIterator;
|
||||||
|
|
||||||
use crate::fxhash::FxHashSet;
|
use crate::fxhash::FxHashSet;
|
||||||
|
use crate::traits::Immutable;
|
||||||
use crate::{debug_fmt_iter, fmt_iter, get_hash};
|
use crate::{debug_fmt_iter, fmt_iter, get_hash};
|
||||||
|
|
||||||
#[cfg(feature = "pylib")]
|
#[cfg(feature = "pylib")]
|
||||||
|
@ -46,13 +47,13 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Hash + Eq> PartialEq for Set<T> {
|
impl<T: Hash + Eq + Immutable> PartialEq for Set<T> {
|
||||||
fn eq(&self, other: &Set<T>) -> bool {
|
fn eq(&self, other: &Set<T>) -> bool {
|
||||||
self.elems.eq(&other.elems)
|
self.elems.eq(&other.elems)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Hash + Eq> Eq for Set<T> {}
|
impl<T: Hash + Eq + Immutable> Eq for Set<T> {}
|
||||||
|
|
||||||
impl<T> Default for Set<T> {
|
impl<T> Default for Set<T> {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
|
@ -108,9 +109,15 @@ impl<T> Set<T> {
|
||||||
elems: FxHashSet::default(),
|
elems: FxHashSet::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Hash> Set<T> {
|
pub fn get_by<Q>(&self, value: &Q, cmp: impl Fn(&Q, &Q) -> bool) -> Option<&T>
|
||||||
|
where
|
||||||
|
T: Borrow<Q>,
|
||||||
|
Q: ?Sized,
|
||||||
|
{
|
||||||
|
self.elems.iter().find(|&v| cmp(v.borrow(), value))
|
||||||
|
}
|
||||||
|
|
||||||
pub fn with_capacity(capacity: usize) -> Self {
|
pub fn with_capacity(capacity: usize) -> Self {
|
||||||
Self {
|
Self {
|
||||||
elems: FxHashSet::with_capacity_and_hasher(capacity, Default::default()),
|
elems: FxHashSet::with_capacity_and_hasher(capacity, Default::default()),
|
||||||
|
@ -163,7 +170,50 @@ impl<'a, T> IntoIterator for &'a Set<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Hash + Eq> Set<T> {
|
impl<T: Eq> Set<T> {
|
||||||
|
pub fn linear_get<Q>(&self, value: &Q) -> Option<&T>
|
||||||
|
where
|
||||||
|
T: Borrow<Q>,
|
||||||
|
Q: ?Sized + Eq,
|
||||||
|
{
|
||||||
|
self.elems.iter().find(|x| (*x).borrow() == value)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn linear_contains<Q>(&self, value: &Q) -> bool
|
||||||
|
where
|
||||||
|
T: Borrow<Q>,
|
||||||
|
Q: ?Sized + Eq,
|
||||||
|
{
|
||||||
|
self.elems.iter().any(|x| (*x).borrow() == value)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn linear_eq(&self, other: &Set<T>) -> bool {
|
||||||
|
self.len() == other.len() && self.iter().all(|x| other.linear_contains(x))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn linear_remove<Q>(&mut self, value: &Q) -> bool
|
||||||
|
where
|
||||||
|
T: Borrow<Q>,
|
||||||
|
Q: ?Sized + Eq,
|
||||||
|
{
|
||||||
|
let mut found = false;
|
||||||
|
self.elems.retain(|x| {
|
||||||
|
let eq = (*x).borrow() == value;
|
||||||
|
if eq {
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
!eq
|
||||||
|
});
|
||||||
|
found
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn linear_exclude(mut self, other: &T) -> Set<T> {
|
||||||
|
self.linear_remove(other);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Hash + Eq + Immutable> Set<T> {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get<Q>(&self, value: &Q) -> Option<&T>
|
pub fn get<Q>(&self, value: &Q) -> Option<&T>
|
||||||
where
|
where
|
||||||
|
@ -173,14 +223,6 @@ impl<T: Hash + Eq> Set<T> {
|
||||||
self.elems.get(value)
|
self.elems.get(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_by<Q>(&self, value: &Q, cmp: impl Fn(&Q, &Q) -> bool) -> Option<&T>
|
|
||||||
where
|
|
||||||
T: Borrow<Q>,
|
|
||||||
Q: ?Sized + Hash + Eq,
|
|
||||||
{
|
|
||||||
self.elems.iter().find(|&v| cmp(v.borrow(), value))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn contains<Q>(&self, value: &Q) -> bool
|
pub fn contains<Q>(&self, value: &Q) -> bool
|
||||||
where
|
where
|
||||||
|
@ -190,12 +232,6 @@ impl<T: Hash + Eq> Set<T> {
|
||||||
self.elems.contains(value)
|
self.elems.contains(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// newly inserted: true, already present: false
|
|
||||||
#[inline]
|
|
||||||
pub fn insert(&mut self, value: T) -> bool {
|
|
||||||
self.elems.insert(value)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn remove<Q>(&mut self, value: &Q) -> bool
|
pub fn remove<Q>(&mut self, value: &Q) -> bool
|
||||||
where
|
where
|
||||||
|
@ -205,6 +241,42 @@ impl<T: Hash + Eq> Set<T> {
|
||||||
self.elems.remove(value)
|
self.elems.remove(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn exclude(mut self, other: &T) -> Set<T> {
|
||||||
|
self.remove(other);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Hash + Eq + Clone + Immutable> Set<T> {
|
||||||
|
/// ```
|
||||||
|
/// # use erg_common::set;
|
||||||
|
/// # use erg_common::set::Set;
|
||||||
|
/// assert_eq!(Set::multi_intersection([set!{1, 3}, set!{1, 2}].into_iter()), set!{1});
|
||||||
|
/// assert_eq!(Set::multi_intersection([set!{1, 3}, set!{1, 2}, set!{2}].into_iter()), set!{1, 2});
|
||||||
|
/// assert_eq!(Set::multi_intersection([set!{1, 3}, set!{1, 2}, set!{2, 3}].into_iter()), set!{1, 2, 3});
|
||||||
|
/// ```
|
||||||
|
pub fn multi_intersection<I>(mut i: I) -> Set<T>
|
||||||
|
where
|
||||||
|
I: Iterator<Item = Set<T>> + Clone,
|
||||||
|
{
|
||||||
|
let mut res = set! {};
|
||||||
|
while let Some(s) = i.next() {
|
||||||
|
res = res.union_from_iter(
|
||||||
|
s.into_iter()
|
||||||
|
.filter(|x| i.clone().any(|set| set.contains(x))),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
res
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Hash + Eq> Set<T> {
|
||||||
|
/// newly inserted: true, already present: false
|
||||||
|
#[inline]
|
||||||
|
pub fn insert(&mut self, value: T) -> bool {
|
||||||
|
self.elems.insert(value)
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
|
pub fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
|
||||||
self.elems.extend(iter);
|
self.elems.extend(iter);
|
||||||
|
@ -295,27 +367,6 @@ impl<T: Hash + Eq + Clone> Set<T> {
|
||||||
self.intersection(&iter.collect())
|
self.intersection(&iter.collect())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ```
|
|
||||||
/// # use erg_common::set;
|
|
||||||
/// # use erg_common::set::Set;
|
|
||||||
/// assert_eq!(Set::multi_intersection([set!{1, 3}, set!{1, 2}].into_iter()), set!{1});
|
|
||||||
/// assert_eq!(Set::multi_intersection([set!{1, 3}, set!{1, 2}, set!{2}].into_iter()), set!{1, 2});
|
|
||||||
/// assert_eq!(Set::multi_intersection([set!{1, 3}, set!{1, 2}, set!{2, 3}].into_iter()), set!{1, 2, 3});
|
|
||||||
/// ```
|
|
||||||
pub fn multi_intersection<I>(mut i: I) -> Set<T>
|
|
||||||
where
|
|
||||||
I: Iterator<Item = Set<T>> + Clone,
|
|
||||||
{
|
|
||||||
let mut res = set! {};
|
|
||||||
while let Some(s) = i.next() {
|
|
||||||
res = res.union_from_iter(
|
|
||||||
s.into_iter()
|
|
||||||
.filter(|x| i.clone().any(|set| set.contains(x))),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
res
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn difference(&self, other: &Set<T>) -> Set<T> {
|
pub fn difference(&self, other: &Set<T>) -> Set<T> {
|
||||||
let u = self.elems.difference(&other.elems);
|
let u = self.elems.difference(&other.elems);
|
||||||
Self {
|
Self {
|
||||||
|
@ -331,11 +382,6 @@ impl<T: Hash + Eq + Clone> Set<T> {
|
||||||
self.insert(other);
|
self.insert(other);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn exclude(mut self, other: &T) -> Set<T> {
|
|
||||||
self.remove(other);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Hash + Ord> Set<T> {
|
impl<T: Hash + Ord> Set<T> {
|
||||||
|
|
|
@ -1371,3 +1371,42 @@ impl<T: Clone> OptionalTranspose for Option<Vec<T>> {
|
||||||
pub trait New {
|
pub trait New {
|
||||||
fn new(cfg: ErgConfig) -> Self;
|
fn new(cfg: ErgConfig) -> Self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Indicates that the type has no interior mutability
|
||||||
|
// TODO: auto trait
|
||||||
|
pub trait Immutable {}
|
||||||
|
|
||||||
|
impl Immutable for () {}
|
||||||
|
impl Immutable for bool {}
|
||||||
|
impl Immutable for char {}
|
||||||
|
impl Immutable for u8 {}
|
||||||
|
impl Immutable for u16 {}
|
||||||
|
impl Immutable for u32 {}
|
||||||
|
impl Immutable for u64 {}
|
||||||
|
impl Immutable for u128 {}
|
||||||
|
impl Immutable for usize {}
|
||||||
|
impl Immutable for i8 {}
|
||||||
|
impl Immutable for i16 {}
|
||||||
|
impl Immutable for i32 {}
|
||||||
|
impl Immutable for i64 {}
|
||||||
|
impl Immutable for i128 {}
|
||||||
|
impl Immutable for isize {}
|
||||||
|
impl Immutable for f32 {}
|
||||||
|
impl Immutable for f64 {}
|
||||||
|
impl Immutable for str {}
|
||||||
|
impl Immutable for String {}
|
||||||
|
impl Immutable for crate::Str {}
|
||||||
|
impl Immutable for std::path::PathBuf {}
|
||||||
|
impl Immutable for std::path::Path {}
|
||||||
|
impl Immutable for std::ffi::OsString {}
|
||||||
|
impl Immutable for std::ffi::OsStr {}
|
||||||
|
impl Immutable for std::time::Duration {}
|
||||||
|
impl Immutable for std::time::SystemTime {}
|
||||||
|
impl Immutable for std::time::Instant {}
|
||||||
|
impl<T: Immutable + ?Sized> Immutable for &T {}
|
||||||
|
impl<T: Immutable> Immutable for Option<T> {}
|
||||||
|
impl<T: Immutable> Immutable for Vec<T> {}
|
||||||
|
impl<T: Immutable> Immutable for [T] {}
|
||||||
|
impl<T: Immutable + ?Sized> Immutable for Box<T> {}
|
||||||
|
impl<T: Immutable + ?Sized> Immutable for std::rc::Rc<T> {}
|
||||||
|
impl<T: Immutable + ?Sized> Immutable for std::sync::Arc<T> {}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
//! Topological sort
|
//! Topological sort
|
||||||
use crate::dict::Dict;
|
use crate::dict::Dict;
|
||||||
use crate::set::Set;
|
use crate::set::Set;
|
||||||
|
use crate::traits::Immutable;
|
||||||
|
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
use std::hash::Hash;
|
use std::hash::Hash;
|
||||||
|
@ -48,13 +49,13 @@ impl TopoSortError {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub struct Node<T: Eq + Hash, U> {
|
pub struct Node<T: Eq + Hash + Immutable, U> {
|
||||||
pub id: T,
|
pub id: T,
|
||||||
pub data: U,
|
pub data: U,
|
||||||
pub depends_on: Set<T>,
|
pub depends_on: Set<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Eq + Hash, U> Node<T, U> {
|
impl<T: Eq + Hash + Immutable, U> Node<T, U> {
|
||||||
pub const fn new(id: T, data: U, depends_on: Set<T>) -> Self {
|
pub const fn new(id: T, data: U, depends_on: Set<T>) -> Self {
|
||||||
Node {
|
Node {
|
||||||
id,
|
id,
|
||||||
|
@ -93,12 +94,12 @@ fn _reorder_by_idx<T>(mut v: Vec<T>, idx: Vec<usize>) -> Vec<T> {
|
||||||
v
|
v
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reorder_by_key<T: Eq + Hash, U>(mut g: Graph<T, U>, idx: Vec<T>) -> Graph<T, U> {
|
fn reorder_by_key<T: Eq + Hash + Immutable, U>(mut g: Graph<T, U>, idx: Vec<T>) -> Graph<T, U> {
|
||||||
g.sort_by_key(|node| idx.iter().position(|k| k == &node.id).unwrap());
|
g.sort_by_key(|node| idx.iter().position(|k| k == &node.id).unwrap());
|
||||||
g
|
g
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dfs<T: Eq + Hash + Clone + Debug, U: Debug>(
|
fn dfs<T: Eq + Hash + Clone + Debug + Immutable, U: Debug>(
|
||||||
g: &Graph<T, U>,
|
g: &Graph<T, U>,
|
||||||
v: T,
|
v: T,
|
||||||
used: &mut Set<T>,
|
used: &mut Set<T>,
|
||||||
|
@ -125,7 +126,7 @@ fn dfs<T: Eq + Hash + Clone + Debug, U: Debug>(
|
||||||
|
|
||||||
/// perform topological sort on a graph
|
/// perform topological sort on a graph
|
||||||
#[allow(clippy::result_unit_err)]
|
#[allow(clippy::result_unit_err)]
|
||||||
pub fn tsort<T: Eq + Hash + Clone + Debug, U: Debug>(
|
pub fn tsort<T: Eq + Hash + Clone + Debug + Immutable, U: Debug>(
|
||||||
g: Graph<T, U>,
|
g: Graph<T, U>,
|
||||||
) -> Result<Graph<T, U>, TopoSortError> {
|
) -> Result<Graph<T, U>, TopoSortError> {
|
||||||
let n = g.len();
|
let n = g.len();
|
||||||
|
|
|
@ -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, set_recursion_limit};
|
use erg_common::{assume_unreachable, log};
|
||||||
use erg_common::{Str, Triple};
|
use erg_common::{Str, Triple};
|
||||||
|
|
||||||
use crate::context::eval::UndoableLinkedList;
|
use crate::context::eval::UndoableLinkedList;
|
||||||
|
@ -126,7 +126,6 @@ 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) => {
|
||||||
|
@ -1040,7 +1039,7 @@ impl Context {
|
||||||
}
|
}
|
||||||
for (sub_k, sub_v) in sub_d.iter() {
|
for (sub_k, sub_v) in sub_d.iter() {
|
||||||
if let Some(sup_v) = sup_d
|
if let Some(sup_v) = sup_d
|
||||||
.get(sub_k)
|
.linear_get(sub_k)
|
||||||
.or_else(|| sub_tpdict_get(sup_d, sub_k, self))
|
.or_else(|| sub_tpdict_get(sup_d, sub_k, self))
|
||||||
{
|
{
|
||||||
if !self.supertype_of_tp(sup_v, sub_v, variance) {
|
if !self.supertype_of_tp(sup_v, sub_v, variance) {
|
||||||
|
@ -1794,7 +1793,7 @@ impl Context {
|
||||||
if self.subtype_of(&t, elem) {
|
if self.subtype_of(&t, elem) {
|
||||||
return intersection.clone();
|
return intersection.clone();
|
||||||
} else if self.supertype_of(&t, elem) {
|
} else if self.supertype_of(&t, elem) {
|
||||||
return constructors::ands(ands.exclude(&t).include(elem.clone()));
|
return constructors::ands(ands.linear_exclude(&t).include(elem.clone()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
and(intersection.clone(), elem.clone())
|
and(intersection.clone(), elem.clone())
|
||||||
|
@ -2024,7 +2023,7 @@ impl Context {
|
||||||
"or" => self.is_sub_pred_of(existing, pred),
|
"or" => self.is_sub_pred_of(existing, pred),
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}) {
|
}) {
|
||||||
reduced.remove(old);
|
reduced.linear_remove(old);
|
||||||
}
|
}
|
||||||
// insert if necessary
|
// insert if necessary
|
||||||
if reduced.iter().all(|existing| match mode {
|
if reduced.iter().all(|existing| match mode {
|
||||||
|
|
|
@ -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, set_recursion_limit, Triple};
|
use erg_common::{dict, fmt_vec, fn_name, option_enum_unwrap, set, Triple};
|
||||||
use erg_common::{ArcArray, Str};
|
use erg_common::{ArcArray, Str};
|
||||||
use OpKind::*;
|
use OpKind::*;
|
||||||
|
|
||||||
|
@ -2068,7 +2068,6 @@ 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() => {
|
||||||
|
@ -3943,8 +3942,8 @@ impl Context {
|
||||||
(TyParam::Erased(l), TyParam::Erased(r)) => l == r,
|
(TyParam::Erased(l), TyParam::Erased(r)) => l == r,
|
||||||
(TyParam::List(l), TyParam::List(r)) => l == r,
|
(TyParam::List(l), TyParam::List(r)) => l == r,
|
||||||
(TyParam::Tuple(l), TyParam::Tuple(r)) => l == r,
|
(TyParam::Tuple(l), TyParam::Tuple(r)) => l == r,
|
||||||
(TyParam::Set(l), TyParam::Set(r)) => l == r, // FIXME:
|
(TyParam::Set(l), TyParam::Set(r)) => l.linear_eq(r),
|
||||||
(TyParam::Dict(l), TyParam::Dict(r)) => l == r,
|
(TyParam::Dict(l), TyParam::Dict(r)) => l.linear_eq(r),
|
||||||
(TyParam::Lambda(l), TyParam::Lambda(r)) => l == r,
|
(TyParam::Lambda(l), TyParam::Lambda(r)) => l == r,
|
||||||
(TyParam::FreeVar { .. }, TyParam::FreeVar { .. }) => true,
|
(TyParam::FreeVar { .. }, TyParam::FreeVar { .. }) => true,
|
||||||
(TyParam::Mono(l), TyParam::Mono(r)) => {
|
(TyParam::Mono(l), TyParam::Mono(r)) => {
|
||||||
|
|
|
@ -100,19 +100,19 @@ impl Generalizer {
|
||||||
let nd_params = lambda
|
let nd_params = lambda
|
||||||
.nd_params
|
.nd_params
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|pt| pt.map_type(|t| self.generalize_t(t, uninit)))
|
.map(|pt| pt.map_type(&mut |t| self.generalize_t(t, uninit)))
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
let var_params = lambda
|
let var_params = lambda
|
||||||
.var_params
|
.var_params
|
||||||
.map(|pt| pt.map_type(|t| self.generalize_t(t, uninit)));
|
.map(|pt| pt.map_type(&mut |t| self.generalize_t(t, uninit)));
|
||||||
let d_params = lambda
|
let d_params = lambda
|
||||||
.d_params
|
.d_params
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|pt| pt.map_type(|t| self.generalize_t(t, uninit)))
|
.map(|pt| pt.map_type(&mut |t| self.generalize_t(t, uninit)))
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
let kw_var_params = lambda
|
let kw_var_params = lambda
|
||||||
.kw_var_params
|
.kw_var_params
|
||||||
.map(|pt| pt.map_type(|t| self.generalize_t(t, uninit)));
|
.map(|pt| pt.map_type(&mut |t| self.generalize_t(t, uninit)));
|
||||||
let body = lambda
|
let body = lambda
|
||||||
.body
|
.body
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
|
|
@ -342,7 +342,10 @@ pub(crate) fn __dict_getitem__(mut args: ValueArgs, ctx: &Context) -> EvalValueR
|
||||||
let index = args
|
let index = args
|
||||||
.remove_left_or_key("Index")
|
.remove_left_or_key("Index")
|
||||||
.ok_or_else(|| not_passed("Index"))?;
|
.ok_or_else(|| not_passed("Index"))?;
|
||||||
if let Some(v) = slf.get(&index).or_else(|| sub_vdict_get(&slf, &index, ctx)) {
|
if let Some(v) = slf
|
||||||
|
.linear_get(&index)
|
||||||
|
.or_else(|| sub_vdict_get(&slf, &index, ctx))
|
||||||
|
{
|
||||||
Ok(v.clone().into())
|
Ok(v.clone().into())
|
||||||
} else if let Some(v) = sub_vdict_get(&homogenize_dict(&slf, ctx), &index, ctx).cloned() {
|
} else if let Some(v) = sub_vdict_get(&homogenize_dict(&slf, ctx), &index, ctx).cloned() {
|
||||||
Ok(v.into())
|
Ok(v.into())
|
||||||
|
|
|
@ -1235,11 +1235,11 @@ impl Context {
|
||||||
let non_default_params = subr_t
|
let non_default_params = subr_t
|
||||||
.non_default_params
|
.non_default_params
|
||||||
.iter()
|
.iter()
|
||||||
.map(|pt| pt.clone().map_type(|t| self.readable_type(t)));
|
.map(|pt| pt.clone().map_type(&mut |t| self.readable_type(t)));
|
||||||
let default_params = subr_t
|
let default_params = subr_t
|
||||||
.default_params
|
.default_params
|
||||||
.iter()
|
.iter()
|
||||||
.map(|pt| pt.clone().map_type(|t| self.readable_type(t)));
|
.map(|pt| pt.clone().map_type(&mut |t| self.readable_type(t)));
|
||||||
Err(TyCheckError::overload_error(
|
Err(TyCheckError::overload_error(
|
||||||
self.cfg.input.clone(),
|
self.cfg.input.clone(),
|
||||||
line!() as usize,
|
line!() as usize,
|
||||||
|
|
|
@ -596,7 +596,7 @@ impl Context {
|
||||||
}
|
}
|
||||||
if let Some(var_params) = &mut params.var_params {
|
if let Some(var_params) = &mut params.var_params {
|
||||||
if let Some(pt) = &subr_t.var_params {
|
if let Some(pt) = &subr_t.var_params {
|
||||||
let pt = pt.clone().map_type(unknown_len_list_t);
|
let pt = pt.clone().map_type(&mut unknown_len_list_t);
|
||||||
if let Err(es) =
|
if let Err(es) =
|
||||||
self.assign_param(var_params, Some(&pt), tmp_tv_cache, ParamKind::VarParams)
|
self.assign_param(var_params, Some(&pt), tmp_tv_cache, ParamKind::VarParams)
|
||||||
{
|
{
|
||||||
|
@ -620,7 +620,7 @@ impl Context {
|
||||||
}
|
}
|
||||||
if let Some(kw_var_params) = &mut params.kw_var_params {
|
if let Some(kw_var_params) = &mut params.kw_var_params {
|
||||||
if let Some(pt) = &subr_t.var_params {
|
if let Some(pt) = &subr_t.var_params {
|
||||||
let pt = pt.clone().map_type(str_dict_t);
|
let pt = pt.clone().map_type(&mut str_dict_t);
|
||||||
if let Err(es) = self.assign_param(
|
if let Err(es) = self.assign_param(
|
||||||
kw_var_params,
|
kw_var_params,
|
||||||
Some(&pt),
|
Some(&pt),
|
||||||
|
|
|
@ -302,7 +302,7 @@ impl<'c, 'l, 'u, L: Locational> Unifier<'c, 'l, 'u, L> {
|
||||||
return Ok(());
|
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.linear_get(sub_k) {
|
||||||
self.sub_unify_value(sub_v, sup_v)?;
|
self.sub_unify_value(sub_v, sup_v)?;
|
||||||
} else {
|
} else {
|
||||||
log!(err "{sup} does not have key {sub_k}");
|
log!(err "{sup} does not have key {sub_k}");
|
||||||
|
@ -628,7 +628,7 @@ impl<'c, 'l, 'u, L: Locational> Unifier<'c, 'l, 'u, L> {
|
||||||
(TyParam::Dict(sub), TyParam::Dict(sup)) => {
|
(TyParam::Dict(sub), TyParam::Dict(sup)) => {
|
||||||
for (sub_k, sub_v) in sub.iter() {
|
for (sub_k, sub_v) in sub.iter() {
|
||||||
if let Some(sup_v) = sup
|
if let Some(sup_v) = sup
|
||||||
.get(sub_k)
|
.linear_get(sub_k)
|
||||||
.or_else(|| sub_tpdict_get(sup, sub_k, self.ctx))
|
.or_else(|| sub_tpdict_get(sup, sub_k, self.ctx))
|
||||||
{
|
{
|
||||||
// self.sub_unify_tp(sub_k, sup_k, _variance, loc, allow_divergence)?;
|
// self.sub_unify_tp(sub_k, sup_k, _variance, loc, allow_divergence)?;
|
||||||
|
|
|
@ -2098,7 +2098,8 @@ impl Params {
|
||||||
|
|
||||||
pub type Decorator = Expr;
|
pub type Decorator = Expr;
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[allow(clippy::derived_hash_with_manual_eq)]
|
||||||
|
#[derive(Debug, Clone, Hash)]
|
||||||
pub struct SubrSignature {
|
pub struct SubrSignature {
|
||||||
pub decorators: HashSet<Decorator>,
|
pub decorators: HashSet<Decorator>,
|
||||||
pub ident: Identifier,
|
pub ident: Identifier,
|
||||||
|
@ -2108,6 +2109,19 @@ pub struct SubrSignature {
|
||||||
pub captured_names: Vec<Identifier>,
|
pub captured_names: Vec<Identifier>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl PartialEq for SubrSignature {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
self.ident == other.ident
|
||||||
|
&& self.bounds == other.bounds
|
||||||
|
&& self.params == other.params
|
||||||
|
&& self.return_t_spec == other.return_t_spec
|
||||||
|
&& self.captured_names == other.captured_names
|
||||||
|
&& self.decorators.linear_eq(&other.decorators)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Eq for SubrSignature {}
|
||||||
|
|
||||||
impl NestedDisplay for SubrSignature {
|
impl NestedDisplay for SubrSignature {
|
||||||
fn fmt_nest(&self, f: &mut fmt::Formatter<'_>, _level: usize) -> fmt::Result {
|
fn fmt_nest(&self, f: &mut fmt::Formatter<'_>, _level: usize) -> fmt::Result {
|
||||||
write!(
|
write!(
|
||||||
|
|
|
@ -874,7 +874,7 @@ impl<A: ASTBuildable> GenericASTLowerer<A> {
|
||||||
};
|
};
|
||||||
if let Some(popped_val_t) = union.insert(key.t(), value.t()) {
|
if let Some(popped_val_t) = union.insert(key.t(), value.t()) {
|
||||||
if PYTHON_MODE {
|
if PYTHON_MODE {
|
||||||
if let Some(val_t) = union.get_mut(key.ref_t()) {
|
if let Some(val_t) = union.linear_get_mut(key.ref_t()) {
|
||||||
*val_t = self.module.context.union(&mem::take(val_t), &popped_val_t);
|
*val_t = self.module.context.union(&mem::take(val_t), &popped_val_t);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -443,6 +443,6 @@ impl SharedGeneralizationCache {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get(&self, key: &FreeTyVar) -> Option<GeneralizationResult> {
|
pub fn get(&self, key: &FreeTyVar) -> Option<GeneralizationResult> {
|
||||||
self.0.borrow().get(key).cloned()
|
self.0.borrow().linear_get(key).cloned()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -140,7 +140,7 @@ impl Deserializer {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_cached_arr(&mut self, arr: &[ValueObj]) -> ValueObj {
|
fn get_cached_arr(&mut self, arr: &[ValueObj]) -> ValueObj {
|
||||||
ValueObj::List(self.arr_cache.get(arr))
|
ValueObj::List(self.arr_cache.linear_get(arr))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn vec_to_bytes<const LEN: usize>(vector: Vec<u8>) -> [u8; LEN] {
|
pub fn vec_to_bytes<const LEN: usize>(vector: Vec<u8>) -> [u8; LEN] {
|
||||||
|
|
|
@ -781,12 +781,12 @@ impl Free<Type> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// interior-mut
|
/// interior-mut
|
||||||
pub fn do_avoiding_recursion<O, F: FnOnce() -> O>(&self, f: F) -> O {
|
pub fn do_avoiding_recursion<O>(&self, f: impl FnOnce() -> O) -> O {
|
||||||
self._do_avoiding_recursion(None, f)
|
self._do_avoiding_recursion(None, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// interior-mut
|
/// interior-mut
|
||||||
pub fn do_avoiding_recursion_with<O, F: FnOnce() -> O>(&self, placeholder: &Type, f: F) -> O {
|
pub fn do_avoiding_recursion_with<O>(&self, placeholder: &Type, f: impl FnOnce() -> O) -> O {
|
||||||
self._do_avoiding_recursion(Some(placeholder), f)
|
self._do_avoiding_recursion(Some(placeholder), f)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -868,8 +868,10 @@ impl<T: StructuralEq + CanbeFree + Clone + Default + fmt::Debug + Send + Sync +
|
||||||
fn structural_eq(&self, other: &Self) -> bool {
|
fn structural_eq(&self, other: &Self) -> bool {
|
||||||
if let (Some((l, r)), Some((l2, r2))) = (self.get_subsup(), other.get_subsup()) {
|
if let (Some((l, r)), Some((l2, r2))) = (self.get_subsup(), other.get_subsup()) {
|
||||||
self.dummy_link();
|
self.dummy_link();
|
||||||
|
other.dummy_link();
|
||||||
let res = l.structural_eq(&l2) && r.structural_eq(&r2);
|
let res = l.structural_eq(&l2) && r.structural_eq(&r2);
|
||||||
self.undo();
|
self.undo();
|
||||||
|
other.undo();
|
||||||
res
|
res
|
||||||
} else if let (Some(l), Some(r)) = (self.get_type(), other.get_type()) {
|
} else if let (Some(l), Some(r)) = (self.get_type(), other.get_type()) {
|
||||||
l.structural_eq(&r)
|
l.structural_eq(&r)
|
||||||
|
|
|
@ -288,7 +288,7 @@ impl ParamTy {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn map_type(self, f: impl FnOnce(Type) -> Type) -> Self {
|
pub fn map_type(self, f: &mut impl FnMut(Type) -> Type) -> Self {
|
||||||
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) },
|
||||||
|
@ -300,7 +300,7 @@ impl ParamTy {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn map_default_type(self, f: impl FnOnce(Type) -> Type) -> Self {
|
pub fn map_default_type(self, f: &mut impl FnMut(Type) -> Type) -> Self {
|
||||||
match self {
|
match self {
|
||||||
Self::KwWithDefault { name, ty, default } => Self::KwWithDefault {
|
Self::KwWithDefault { name, ty, default } => Self::KwWithDefault {
|
||||||
name,
|
name,
|
||||||
|
@ -581,7 +581,7 @@ impl SubrType {
|
||||||
|| self.return_t.contains_tp(target)
|
|| self.return_t.contains_tp(target)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn map(self, f: impl Fn(Type) -> Type + Copy) -> Self {
|
pub fn map(self, f: &mut impl FnMut(Type) -> Type) -> Self {
|
||||||
Self::new(
|
Self::new(
|
||||||
self.kind,
|
self.kind,
|
||||||
self.non_default_params
|
self.non_default_params
|
||||||
|
@ -859,25 +859,25 @@ impl SubrType {
|
||||||
let non_default_params = self
|
let non_default_params = self
|
||||||
.non_default_params
|
.non_default_params
|
||||||
.iter()
|
.iter()
|
||||||
.map(|pt| pt.clone().map_type(|t| t.derefine()))
|
.map(|pt| pt.clone().map_type(&mut |t| t.derefine()))
|
||||||
.collect();
|
.collect();
|
||||||
let var_params = self
|
let var_params = self
|
||||||
.var_params
|
.var_params
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|pt| pt.clone().map_type(|t| t.derefine()));
|
.map(|pt| pt.clone().map_type(&mut |t| t.derefine()));
|
||||||
let default_params = self
|
let default_params = self
|
||||||
.default_params
|
.default_params
|
||||||
.iter()
|
.iter()
|
||||||
.map(|pt| {
|
.map(|pt| {
|
||||||
pt.clone()
|
pt.clone()
|
||||||
.map_type(|t| t.derefine())
|
.map_type(&mut |t| t.derefine())
|
||||||
.map_default_type(|t| t.derefine())
|
.map_default_type(&mut |t| t.derefine())
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
let kw_var_params = self
|
let kw_var_params = self
|
||||||
.kw_var_params
|
.kw_var_params
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|pt| pt.clone().map_type(|t| t.derefine()));
|
.map(|pt| pt.clone().map_type(&mut |t| t.derefine()));
|
||||||
Self::new(
|
Self::new(
|
||||||
self.kind,
|
self.kind,
|
||||||
non_default_params,
|
non_default_params,
|
||||||
|
@ -1016,13 +1016,34 @@ impl SubrType {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, Hash)]
|
||||||
pub enum RefineKind {
|
pub enum RefineKind {
|
||||||
Interval { min: TyParam, max: TyParam }, // e.g. {I: Int | I >= 2; I <= 10} 2..10
|
Interval { min: TyParam, max: TyParam }, // e.g. {I: Int | I >= 2; I <= 10} 2..10
|
||||||
Enum(Set<TyParam>), // e.g. {I: Int | I == 1 or I == 2} {1, 2}
|
Enum(Set<TyParam>), // e.g. {I: Int | I == 1 or I == 2} {1, 2}
|
||||||
Complex,
|
Complex,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl PartialEq for RefineKind {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
match (self, other) {
|
||||||
|
(
|
||||||
|
Self::Interval {
|
||||||
|
min: lmin,
|
||||||
|
max: lmax,
|
||||||
|
},
|
||||||
|
Self::Interval {
|
||||||
|
min: rmin,
|
||||||
|
max: rmax,
|
||||||
|
},
|
||||||
|
) => lmin == rmin && lmax == rmax,
|
||||||
|
(Self::Enum(lset), Self::Enum(rset)) => lset.linear_eq(rset),
|
||||||
|
(Self::Complex, Self::Complex) => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Eq for RefineKind {}
|
||||||
|
|
||||||
/// e.g.
|
/// e.g.
|
||||||
/// ```erg
|
/// ```erg
|
||||||
/// {I: Int | I >= 0}
|
/// {I: Int | I >= 0}
|
||||||
|
@ -1483,8 +1504,8 @@ impl PartialEq for Type {
|
||||||
(Self::NamedTuple(lhs), Self::NamedTuple(rhs)) => lhs == rhs,
|
(Self::NamedTuple(lhs), Self::NamedTuple(rhs)) => lhs == rhs,
|
||||||
(Self::Refinement(l), Self::Refinement(r)) => l == r,
|
(Self::Refinement(l), Self::Refinement(r)) => l == r,
|
||||||
(Self::Quantified(l), Self::Quantified(r)) => l == r,
|
(Self::Quantified(l), Self::Quantified(r)) => l == r,
|
||||||
(Self::And(_, _), Self::And(_, _)) => self.ands() == other.ands(),
|
(Self::And(_, _), Self::And(_, _)) => self.ands().linear_eq(&other.ands()),
|
||||||
(Self::Or(_, _), Self::Or(_, _)) => self.ors() == other.ors(),
|
(Self::Or(_, _), Self::Or(_, _)) => self.ors().linear_eq(&other.ors()),
|
||||||
(Self::Not(l), Self::Not(r)) => l == r,
|
(Self::Not(l), Self::Not(r)) => l == r,
|
||||||
(
|
(
|
||||||
Self::Poly {
|
Self::Poly {
|
||||||
|
@ -4160,7 +4181,7 @@ impl Type {
|
||||||
}
|
}
|
||||||
Self::NamedTuple(r)
|
Self::NamedTuple(r)
|
||||||
}
|
}
|
||||||
Self::Subr(subr) => Self::Subr(subr.map(|t| t.eliminate_recursion(target))),
|
Self::Subr(subr) => Self::Subr(subr.map(&mut |t| t.eliminate_recursion(target))),
|
||||||
Self::Callable { param_ts, return_t } => {
|
Self::Callable { param_ts, return_t } => {
|
||||||
let param_ts = param_ts
|
let param_ts = param_ts
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
@ -4228,20 +4249,20 @@ impl Type {
|
||||||
.iter()
|
.iter()
|
||||||
.map(|pt| {
|
.map(|pt| {
|
||||||
pt.clone()
|
pt.clone()
|
||||||
.map_type(|t| t.replace(&Self::Failure, &Self::Obj))
|
.map_type(&mut |t| t.replace(&Self::Failure, &Self::Obj))
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
let var_params = subr.var_params.as_ref().map(|pt| {
|
let var_params = subr.var_params.as_ref().map(|pt| {
|
||||||
pt.clone()
|
pt.clone()
|
||||||
.map_type(|t| t.replace(&Self::Failure, &Self::Obj))
|
.map_type(&mut |t| t.replace(&Self::Failure, &Self::Obj))
|
||||||
});
|
});
|
||||||
let default_params = subr
|
let default_params = subr
|
||||||
.default_params
|
.default_params
|
||||||
.iter()
|
.iter()
|
||||||
.map(|pt| {
|
.map(|pt| {
|
||||||
pt.clone()
|
pt.clone()
|
||||||
.map_type(|t| t.replace(&Self::Failure, &Self::Obj))
|
.map_type(&mut |t| t.replace(&Self::Failure, &Self::Obj))
|
||||||
.map_default_type(|t| {
|
.map_default_type(&mut |t| {
|
||||||
let typ = pt.typ().clone().replace(&Self::Failure, &Self::Obj);
|
let typ = pt.typ().clone().replace(&Self::Failure, &Self::Obj);
|
||||||
t.replace(&Self::Failure, &typ) & typ
|
t.replace(&Self::Failure, &typ) & typ
|
||||||
})
|
})
|
||||||
|
@ -4249,8 +4270,8 @@ impl Type {
|
||||||
.collect();
|
.collect();
|
||||||
let kw_var_params = subr.kw_var_params.as_ref().map(|pt| {
|
let kw_var_params = subr.kw_var_params.as_ref().map(|pt| {
|
||||||
pt.clone()
|
pt.clone()
|
||||||
.map_type(|t| t.replace(&Self::Failure, &Self::Obj))
|
.map_type(&mut |t| t.replace(&Self::Failure, &Self::Obj))
|
||||||
.map_default_type(|t| {
|
.map_default_type(&mut |t| {
|
||||||
let typ = pt.typ().clone().replace(&Self::Failure, &Self::Obj);
|
let typ = pt.typ().clone().replace(&Self::Failure, &Self::Obj);
|
||||||
t.replace(&Self::Failure, &typ) & typ
|
t.replace(&Self::Failure, &typ) & typ
|
||||||
})
|
})
|
||||||
|
@ -4285,97 +4306,91 @@ impl Type {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Unlike `replace`, this does not make a look-up table.
|
fn map(self, f: &mut impl FnMut(Type) -> Type) -> Type {
|
||||||
fn _replace(mut self, target: &Type, to: &Type) -> Type {
|
|
||||||
if self.structural_eq(target) {
|
|
||||||
self = to.clone();
|
|
||||||
}
|
|
||||||
match self {
|
match self {
|
||||||
Self::FreeVar(fv) if fv.is_linked() => fv.unwrap_linked()._replace(target, to),
|
Self::FreeVar(fv) if fv.is_linked() => fv.unwrap_linked().map(f),
|
||||||
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() {
|
||||||
fv.dummy_link();
|
fv.dummy_link();
|
||||||
fv_clone.dummy_link();
|
fv_clone.dummy_link();
|
||||||
let sub = sub._replace(target, to);
|
let sub = sub.map(f);
|
||||||
let sup = sup._replace(target, to);
|
let sup = sup.map(f);
|
||||||
fv.undo();
|
fv.undo();
|
||||||
fv_clone.undo();
|
fv_clone.undo();
|
||||||
fv_clone.update_constraint(Constraint::new_sandwiched(sub, sup), true);
|
fv_clone.update_constraint(Constraint::new_sandwiched(sub, sup), true);
|
||||||
} else if let Some(ty) = fv_clone.get_type() {
|
} else if let Some(ty) = fv_clone.get_type() {
|
||||||
fv_clone
|
fv_clone.update_constraint(Constraint::new_type_of(ty.map(f)), true);
|
||||||
.update_constraint(Constraint::new_type_of(ty._replace(target, to)), true);
|
|
||||||
}
|
}
|
||||||
Self::FreeVar(fv_clone)
|
Self::FreeVar(fv_clone)
|
||||||
}
|
}
|
||||||
Self::Refinement(mut refine) => {
|
Self::Refinement(mut refine) => {
|
||||||
refine.t = Box::new(refine.t._replace(target, to));
|
refine.t = Box::new(refine.t.map(f));
|
||||||
refine.pred = Box::new(refine.pred._replace_t(target, to));
|
refine.pred = Box::new(refine.pred.map_t(f));
|
||||||
Self::Refinement(refine)
|
Self::Refinement(refine)
|
||||||
}
|
}
|
||||||
Self::Record(mut rec) => {
|
Self::Record(mut rec) => {
|
||||||
for v in rec.values_mut() {
|
for v in rec.values_mut() {
|
||||||
*v = std::mem::take(v)._replace(target, to);
|
*v = std::mem::take(v).map(f);
|
||||||
}
|
}
|
||||||
Self::Record(rec)
|
Self::Record(rec)
|
||||||
}
|
}
|
||||||
Self::NamedTuple(mut r) => {
|
Self::NamedTuple(mut r) => {
|
||||||
for (_, v) in r.iter_mut() {
|
for (_, v) in r.iter_mut() {
|
||||||
*v = std::mem::take(v)._replace(target, to);
|
*v = std::mem::take(v).map(f);
|
||||||
}
|
}
|
||||||
Self::NamedTuple(r)
|
Self::NamedTuple(r)
|
||||||
}
|
}
|
||||||
Self::Subr(subr) => Self::Subr(subr._replace(target, to)),
|
Self::Subr(subr) => Self::Subr(subr.map(f)),
|
||||||
Self::Callable { param_ts, return_t } => {
|
Self::Callable { param_ts, return_t } => {
|
||||||
let param_ts = param_ts
|
let param_ts = param_ts.into_iter().map(|t| t.map(f)).collect();
|
||||||
.into_iter()
|
let return_t = Box::new(return_t.map(f));
|
||||||
.map(|t| t._replace(target, to))
|
|
||||||
.collect();
|
|
||||||
let return_t = Box::new(return_t._replace(target, to));
|
|
||||||
Self::Callable { param_ts, return_t }
|
Self::Callable { param_ts, return_t }
|
||||||
}
|
}
|
||||||
Self::Quantified(quant) => quant._replace(target, to).quantify(),
|
Self::Quantified(quant) => quant.map(f).quantify(),
|
||||||
Self::Poly { name, params } => {
|
Self::Poly { name, params } => {
|
||||||
let params = params
|
let params = params.into_iter().map(|tp| tp.map_t(f)).collect();
|
||||||
.into_iter()
|
|
||||||
.map(|tp| tp.replace_t(target, to))
|
|
||||||
.collect();
|
|
||||||
Self::Poly { name, params }
|
Self::Poly { name, params }
|
||||||
}
|
}
|
||||||
Self::Ref(t) => Self::Ref(Box::new(t._replace(target, to))),
|
Self::Ref(t) => Self::Ref(Box::new(t.map(f))),
|
||||||
Self::RefMut { before, after } => Self::RefMut {
|
Self::RefMut { before, after } => Self::RefMut {
|
||||||
before: Box::new(before._replace(target, to)),
|
before: Box::new(before.map(f)),
|
||||||
after: after.map(|t| Box::new(t._replace(target, to))),
|
after: after.map(|t| Box::new(t.map(f))),
|
||||||
},
|
},
|
||||||
Self::And(l, r) => l._replace(target, to) & r._replace(target, to),
|
Self::And(l, r) => l.map(f) & r.map(f),
|
||||||
Self::Or(l, r) => l._replace(target, to) | r._replace(target, to),
|
Self::Or(l, r) => l.map(f) | r.map(f),
|
||||||
Self::Not(ty) => !ty._replace(target, to),
|
Self::Not(ty) => !ty.map(f),
|
||||||
Self::Proj { lhs, rhs } => lhs._replace(target, to).proj(rhs),
|
Self::Proj { lhs, rhs } => lhs.map(f).proj(rhs),
|
||||||
Self::ProjCall {
|
Self::ProjCall {
|
||||||
lhs,
|
lhs,
|
||||||
attr_name,
|
attr_name,
|
||||||
args,
|
args,
|
||||||
} => {
|
} => {
|
||||||
let args = args
|
let args = args.into_iter().map(|tp| tp.map_t(f)).collect();
|
||||||
.into_iter()
|
proj_call(lhs.map_t(f), attr_name, args)
|
||||||
.map(|tp| tp.replace_t(target, to))
|
|
||||||
.collect();
|
|
||||||
proj_call(lhs.replace_t(target, to), attr_name, args)
|
|
||||||
}
|
}
|
||||||
Self::Structural(ty) => ty._replace(target, to).structuralize(),
|
Self::Structural(ty) => ty.map(f).structuralize(),
|
||||||
Self::Guard(guard) => Self::Guard(GuardType::new(
|
Self::Guard(guard) => Self::Guard(GuardType::new(
|
||||||
guard.namespace,
|
guard.namespace,
|
||||||
guard.target.clone(),
|
guard.target.clone(),
|
||||||
guard.to._replace(target, to),
|
guard.to.map(f),
|
||||||
)),
|
)),
|
||||||
Self::Bounded { sub, sup } => Self::Bounded {
|
Self::Bounded { sub, sup } => Self::Bounded {
|
||||||
sub: Box::new(sub._replace(target, to)),
|
sub: Box::new(sub.map(f)),
|
||||||
sup: Box::new(sup._replace(target, to)),
|
sup: Box::new(sup.map(f)),
|
||||||
},
|
},
|
||||||
mono_type_pattern!() => self,
|
mono_type_pattern!() => self,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Unlike `replace`, this does not make a look-up table.
|
||||||
|
fn _replace(mut self, target: &Type, to: &Type) -> Type {
|
||||||
|
if self.structural_eq(target) {
|
||||||
|
self = to.clone();
|
||||||
|
}
|
||||||
|
self.map(&mut |t| t._replace(target, to))
|
||||||
|
}
|
||||||
|
|
||||||
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.unwrap_linked()._replace_tp(target, to),
|
Self::FreeVar(fv) if fv.is_linked() => fv.unwrap_linked()._replace_tp(target, to),
|
||||||
|
|
|
@ -298,7 +298,7 @@ impl PartialEq for TyParam {
|
||||||
(Self::List(l), Self::List(r)) => l == r,
|
(Self::List(l), Self::List(r)) => l == r,
|
||||||
(Self::UnsizedList(l), Self::UnsizedList(r)) => l == r,
|
(Self::UnsizedList(l), Self::UnsizedList(r)) => l == r,
|
||||||
(Self::Tuple(l), Self::Tuple(r)) => l == r,
|
(Self::Tuple(l), Self::Tuple(r)) => l == r,
|
||||||
(Self::Dict(l), Self::Dict(r)) => l == r,
|
(Self::Dict(l), Self::Dict(r)) => l.linear_eq(r),
|
||||||
(Self::Record(l), Self::Record(r)) => l == r,
|
(Self::Record(l), Self::Record(r)) => l == r,
|
||||||
(
|
(
|
||||||
Self::DataClass {
|
Self::DataClass {
|
||||||
|
@ -310,7 +310,7 @@ impl PartialEq for TyParam {
|
||||||
fields: rfs,
|
fields: rfs,
|
||||||
},
|
},
|
||||||
) => ln == rn && lfs == rfs,
|
) => ln == rn && lfs == rfs,
|
||||||
(Self::Set(l), Self::Set(r)) => l == r,
|
(Self::Set(l), Self::Set(r)) => l.linear_eq(r),
|
||||||
(Self::Lambda(l), Self::Lambda(r)) => l == r,
|
(Self::Lambda(l), Self::Lambda(r)) => l == r,
|
||||||
(Self::Mono(l), Self::Mono(r)) => l == r,
|
(Self::Mono(l), Self::Mono(r)) => l == r,
|
||||||
(
|
(
|
||||||
|
|
|
@ -641,7 +641,7 @@ impl Rem for Float {
|
||||||
|
|
||||||
/// 値オブジェクト
|
/// 値オブジェクト
|
||||||
/// コンパイル時評価ができ、シリアライズも可能(Typeなどはシリアライズ不可)
|
/// コンパイル時評価ができ、シリアライズも可能(Typeなどはシリアライズ不可)
|
||||||
#[derive(Clone, PartialEq, Default, Hash)]
|
#[derive(Clone, Default, Hash)]
|
||||||
pub enum ValueObj {
|
pub enum ValueObj {
|
||||||
Int(i32),
|
Int(i32),
|
||||||
Nat(u64),
|
Nat(u64),
|
||||||
|
@ -970,6 +970,44 @@ impl LimitedDisplay for ValueObj {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl PartialEq for ValueObj {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
match (self, other) {
|
||||||
|
(Self::Int(i1), Self::Int(i2)) => i1 == i2,
|
||||||
|
(Self::Nat(n1), Self::Nat(n2)) => n1 == n2,
|
||||||
|
(Self::Float(f1), Self::Float(f2)) => f1 == f2,
|
||||||
|
(Self::Str(s1), Self::Str(s2)) => s1 == s2,
|
||||||
|
(Self::Bool(b1), Self::Bool(b2)) => b1 == b2,
|
||||||
|
(Self::List(l1), Self::List(l2)) => l1 == l2,
|
||||||
|
(Self::UnsizedList(l1), Self::UnsizedList(l2)) => l1 == l2,
|
||||||
|
(Self::Set(s1), Self::Set(s2)) => s1.linear_eq(s2),
|
||||||
|
(Self::Dict(d1), Self::Dict(d2)) => d1.linear_eq(d2),
|
||||||
|
(Self::Tuple(t1), Self::Tuple(t2)) => t1 == t2,
|
||||||
|
(Self::Record(r1), Self::Record(r2)) => r1 == r2,
|
||||||
|
(
|
||||||
|
Self::DataClass {
|
||||||
|
name: n1,
|
||||||
|
fields: f1,
|
||||||
|
},
|
||||||
|
Self::DataClass {
|
||||||
|
name: n2,
|
||||||
|
fields: f2,
|
||||||
|
},
|
||||||
|
) => n1 == n2 && f1 == f2,
|
||||||
|
(Self::Code(c1), Self::Code(c2)) => c1 == c2,
|
||||||
|
(Self::Subr(s1), Self::Subr(s2)) => s1 == s2,
|
||||||
|
(Self::Type(t1), Self::Type(t2)) => t1 == t2,
|
||||||
|
(Self::None, Self::None)
|
||||||
|
| (Self::Ellipsis, Self::Ellipsis)
|
||||||
|
| (Self::NotImplemented, Self::NotImplemented)
|
||||||
|
| (Self::NegInf, Self::NegInf)
|
||||||
|
| (Self::Inf, Self::Inf)
|
||||||
|
| (Self::Failure, Self::Failure) => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Eq for ValueObj {}
|
impl Eq for ValueObj {}
|
||||||
|
|
||||||
impl Neg for ValueObj {
|
impl Neg for ValueObj {
|
||||||
|
|
|
@ -4,6 +4,7 @@ use std::fmt;
|
||||||
#[allow(unused_imports)]
|
#[allow(unused_imports)]
|
||||||
use erg_common::log;
|
use erg_common::log;
|
||||||
use erg_common::set::Set;
|
use erg_common::set::Set;
|
||||||
|
use erg_common::traits::Immutable;
|
||||||
use erg_common::{switch_lang, Str};
|
use erg_common::{switch_lang, Str};
|
||||||
|
|
||||||
use erg_parser::ast::AccessModifier;
|
use erg_parser::ast::AccessModifier;
|
||||||
|
@ -170,6 +171,8 @@ pub struct Field {
|
||||||
pub symbol: Str,
|
pub symbol: Str,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Immutable for Field {}
|
||||||
|
|
||||||
impl PartialEq for Field {
|
impl PartialEq for Field {
|
||||||
fn eq(&self, other: &Self) -> bool {
|
fn eq(&self, other: &Self) -> bool {
|
||||||
self.symbol == other.symbol
|
self.symbol == other.symbol
|
||||||
|
|
|
@ -4,6 +4,7 @@ use std::path::Path;
|
||||||
use erg_common::error::Location;
|
use erg_common::error::Location;
|
||||||
use erg_common::pathutil::NormalizedPathBuf;
|
use erg_common::pathutil::NormalizedPathBuf;
|
||||||
use erg_common::set::Set;
|
use erg_common::set::Set;
|
||||||
|
use erg_common::traits::Immutable;
|
||||||
use erg_common::{switch_lang, Str};
|
use erg_common::{switch_lang, Str};
|
||||||
|
|
||||||
use erg_parser::ast::DefId;
|
use erg_parser::ast::DefId;
|
||||||
|
@ -141,6 +142,8 @@ pub struct AbsLocation {
|
||||||
pub loc: Location,
|
pub loc: Location,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Immutable for AbsLocation {}
|
||||||
|
|
||||||
impl fmt::Display for AbsLocation {
|
impl fmt::Display for AbsLocation {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
if let Some(module) = &self.module {
|
if let Some(module) = &self.module {
|
||||||
|
|
|
@ -8,7 +8,7 @@ use erg_common::error::Location;
|
||||||
use erg_common::io::Input;
|
use erg_common::io::Input;
|
||||||
use erg_common::set::Set as HashSet;
|
use erg_common::set::Set as HashSet;
|
||||||
// use erg_common::dict::Dict as HashMap;
|
// use erg_common::dict::Dict as HashMap;
|
||||||
use erg_common::traits::{Locational, NestedDisplay, Stream};
|
use erg_common::traits::{Immutable, Locational, NestedDisplay, Stream};
|
||||||
use erg_common::{
|
use erg_common::{
|
||||||
fmt_option, fmt_vec, impl_display_for_enum, impl_display_from_nested,
|
fmt_option, fmt_vec, impl_display_for_enum, impl_display_from_nested,
|
||||||
impl_displayable_stream_for_wrapper, impl_from_trait_for_enum, impl_locational,
|
impl_displayable_stream_for_wrapper, impl_from_trait_for_enum, impl_locational,
|
||||||
|
@ -3806,6 +3806,8 @@ impl Locational for TypeBoundSpecs {
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
pub struct Decorator(pub Expr);
|
pub struct Decorator(pub Expr);
|
||||||
|
|
||||||
|
impl Immutable for Decorator {}
|
||||||
|
|
||||||
impl Decorator {
|
impl Decorator {
|
||||||
pub const fn new(expr: Expr) -> Self {
|
pub const fn new(expr: Expr) -> Self {
|
||||||
Self(expr)
|
Self(expr)
|
||||||
|
@ -3825,6 +3827,8 @@ impl Decorator {
|
||||||
#[derive(Debug, Clone, Eq)]
|
#[derive(Debug, Clone, Eq)]
|
||||||
pub struct VarName(Token);
|
pub struct VarName(Token);
|
||||||
|
|
||||||
|
impl Immutable for VarName {}
|
||||||
|
|
||||||
impl PartialEq for VarName {
|
impl PartialEq for VarName {
|
||||||
fn eq(&self, other: &Self) -> bool {
|
fn eq(&self, other: &Self) -> bool {
|
||||||
self.0 == other.0
|
self.0 == other.0
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue