mirror of
https://github.com/erg-lang/erg.git
synced 2025-09-30 21:01:10 +00:00
merge
This commit is contained in:
parent
0e42ab03ca
commit
0bb8856f19
5 changed files with 62 additions and 111 deletions
|
@ -65,11 +65,13 @@ impl<T: ?Sized> Shared<T> {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
#[track_caller]
|
||||
pub fn borrow(&self) -> Ref<'_, T> {
|
||||
RefCell::borrow(&self.0)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[track_caller]
|
||||
pub fn borrow_mut(&self) -> RefMut<'_, T> {
|
||||
RefCell::borrow_mut(&self.0)
|
||||
}
|
||||
|
|
|
@ -459,54 +459,46 @@ impl Context {
|
|||
// => ?P.undoable_link(Int)
|
||||
// => Mul Int :> Int
|
||||
(FreeVar(lfv), rhs) => {
|
||||
match &*lfv.borrow() {
|
||||
FreeKind::Linked(t) | FreeKind::UndoableLinked { t, .. } => {
|
||||
self.supertype_of(t, rhs)
|
||||
}
|
||||
FreeKind::Unbound { constraint: _, .. }
|
||||
| FreeKind::NamedUnbound { constraint: _, .. } => {
|
||||
if let Some((_sub, sup)) = lfv.get_subsup() {
|
||||
lfv.forced_undoable_link(rhs);
|
||||
let res = self.supertype_of(&sup, rhs);
|
||||
lfv.undo();
|
||||
res
|
||||
} else if let Some(lfvt) = lfv.get_type() {
|
||||
// e.g. lfv: ?L(: Int) is unreachable
|
||||
// but
|
||||
// ?L(: Array(Type, 3)) :> Array(Int, 3)
|
||||
// => Array(Type, 3) :> Array(Typeof(Int), 3)
|
||||
// => true
|
||||
let rhs_meta = self.meta_type(rhs);
|
||||
self.supertype_of(&lfvt, &rhs_meta)
|
||||
} else {
|
||||
// constraint is uninitialized
|
||||
log!(err "constraint is uninitialized: {lfv}/{rhs}");
|
||||
true
|
||||
}
|
||||
}
|
||||
if let FreeKind::Linked(t) | FreeKind::UndoableLinked { t, .. } = &*lfv.borrow() {
|
||||
return self.supertype_of(t, rhs);
|
||||
}
|
||||
if let Some((_sub, sup)) = lfv.get_subsup() {
|
||||
lfv.undoable_link(rhs);
|
||||
let res = self.supertype_of(&sup, rhs);
|
||||
lfv.undo();
|
||||
res
|
||||
} else if let Some(lfvt) = lfv.get_type() {
|
||||
// e.g. lfv: ?L(: Int) is unreachable
|
||||
// but
|
||||
// ?L(: Array(Type, 3)) :> Array(Int, 3)
|
||||
// => Array(Type, 3) :> Array(Typeof(Int), 3)
|
||||
// => true
|
||||
let rhs_meta = self.meta_type(rhs);
|
||||
self.supertype_of(&lfvt, &rhs_meta)
|
||||
} else {
|
||||
// constraint is uninitialized
|
||||
log!(err "constraint is uninitialized: {lfv}/{rhs}");
|
||||
true
|
||||
}
|
||||
}
|
||||
(lhs, FreeVar(rfv)) => match &*rfv.borrow() {
|
||||
FreeKind::Linked(t) | FreeKind::UndoableLinked { t, .. } => {
|
||||
self.supertype_of(lhs, t)
|
||||
(lhs, FreeVar(rfv)) => {
|
||||
if let FreeKind::Linked(t) | FreeKind::UndoableLinked { t, .. } = &*rfv.borrow() {
|
||||
return self.supertype_of(lhs, t);
|
||||
}
|
||||
FreeKind::Unbound { constraint: _, .. }
|
||||
| FreeKind::NamedUnbound { constraint: _, .. } => {
|
||||
if let Some((sub, _sup)) = rfv.get_subsup() {
|
||||
rfv.forced_undoable_link(lhs);
|
||||
let res = self.supertype_of(lhs, &sub);
|
||||
rfv.undo();
|
||||
res
|
||||
} else if let Some(rfvt) = rfv.get_type() {
|
||||
let lhs_meta = self.meta_type(lhs);
|
||||
self.supertype_of(&lhs_meta, &rfvt)
|
||||
} else {
|
||||
// constraint is uninitialized
|
||||
log!(err "constraint is uninitialized: {lhs}/{rfv}");
|
||||
true
|
||||
}
|
||||
if let Some((sub, _sup)) = rfv.get_subsup() {
|
||||
rfv.undoable_link(lhs);
|
||||
let res = self.supertype_of(lhs, &sub);
|
||||
rfv.undo();
|
||||
res
|
||||
} else if let Some(rfvt) = rfv.get_type() {
|
||||
let lhs_meta = self.meta_type(lhs);
|
||||
self.supertype_of(&lhs_meta, &rfvt)
|
||||
} else {
|
||||
// constraint is uninitialized
|
||||
log!(err "constraint is uninitialized: {lhs}/{rfv}");
|
||||
true
|
||||
}
|
||||
},
|
||||
}
|
||||
(Record(lhs), Record(rhs)) => {
|
||||
for (l_k, l_t) in lhs.iter() {
|
||||
if let Some((r_k, r_t)) = rhs.get_key_value(l_k) {
|
||||
|
|
|
@ -148,7 +148,7 @@ impl Generalizer {
|
|||
if sub == sup {
|
||||
let t = self.generalize_t(sub, uninit);
|
||||
let res = FreeVar(fv);
|
||||
res.forced_link(&t);
|
||||
res.link(&t);
|
||||
res
|
||||
} else if sup != Obj
|
||||
&& !self.qnames.contains(&fv.unbound_name().unwrap())
|
||||
|
@ -532,10 +532,10 @@ impl<'c, 'q, 'l, L: Locational> Dereferencer<'c, 'q, 'l, L> {
|
|||
fv.dummy_link();
|
||||
}
|
||||
(true, false) => {
|
||||
fv.forced_undoable_link(&super_t);
|
||||
fv.undoable_link(&super_t);
|
||||
}
|
||||
(false, true | false) => {
|
||||
fv.forced_undoable_link(&sub_t);
|
||||
fv.undoable_link(&sub_t);
|
||||
}
|
||||
}
|
||||
let res = self.validate_subsup(sub_t, super_t);
|
||||
|
|
|
@ -5,6 +5,7 @@ use std::mem;
|
|||
|
||||
use erg_common::fresh::VAR_ID;
|
||||
use erg_common::shared::Shared;
|
||||
use erg_common::shared::{MappedRwLockReadGuard, RwLockReadGuard, RwLockWriteGuard};
|
||||
use erg_common::traits::{LimitedDisplay, StructuralEq};
|
||||
use erg_common::Str;
|
||||
use erg_common::{addr_eq, log};
|
||||
|
@ -596,10 +597,12 @@ impl<T: LimitedDisplay> LimitedDisplay for Free<T> {
|
|||
}
|
||||
|
||||
impl<T> Free<T> {
|
||||
pub fn borrow(&self) -> erg_common::shared::RwLockReadGuard<'_, FreeKind<T>> {
|
||||
#[track_caller]
|
||||
pub fn borrow(&self) -> RwLockReadGuard<'_, FreeKind<T>> {
|
||||
self.0.borrow()
|
||||
}
|
||||
pub fn borrow_mut(&self) -> erg_common::shared::RwLockWriteGuard<'_, FreeKind<T>> {
|
||||
#[track_caller]
|
||||
pub fn borrow_mut(&self) -> RwLockWriteGuard<'_, FreeKind<T>> {
|
||||
self.0.borrow_mut()
|
||||
}
|
||||
/// very unsafe, use `force_replace` instead whenever possible
|
||||
|
@ -609,16 +612,6 @@ impl<T> Free<T> {
|
|||
pub fn forced_as_ref(&self) -> &FreeKind<T> {
|
||||
unsafe { self.as_ptr().as_ref() }.unwrap()
|
||||
}
|
||||
pub fn force_replace(&self, new: FreeKind<T>) {
|
||||
// prevent linking to self
|
||||
if addr_eq!(*self.borrow(), new) {
|
||||
return;
|
||||
}
|
||||
unsafe {
|
||||
self.0.force_unlock_write();
|
||||
}
|
||||
*self.0.borrow_mut() = new;
|
||||
}
|
||||
pub fn can_borrow(&self) -> bool {
|
||||
self.0.can_borrow()
|
||||
}
|
||||
|
@ -750,6 +743,7 @@ impl<T> Free<T> {
|
|||
Self(Shared::new(FreeKind::Linked(t)))
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
pub fn replace(&self, to: FreeKind<T>) {
|
||||
// prevent linking to self
|
||||
if self.is_linked() && addr_eq!(*self.borrow(), to) {
|
||||
|
@ -760,8 +754,9 @@ impl<T> Free<T> {
|
|||
|
||||
/// returns linked type (panic if self is unbounded)
|
||||
/// NOTE: check by `.is_linked` before call
|
||||
pub fn crack(&self) -> erg_common::shared::MappedRwLockReadGuard<'_, T> {
|
||||
erg_common::shared::RwLockReadGuard::map(self.borrow(), |f| match f {
|
||||
#[track_caller]
|
||||
pub fn crack(&self) -> MappedRwLockReadGuard<'_, T> {
|
||||
RwLockReadGuard::map(self.borrow(), |f| match f {
|
||||
FreeKind::Linked(t) | FreeKind::UndoableLinked { t, .. } => t,
|
||||
FreeKind::Unbound { .. } | FreeKind::NamedUnbound { .. } => {
|
||||
panic!("the value is unbounded")
|
||||
|
@ -769,8 +764,9 @@ impl<T> Free<T> {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn crack_constraint(&self) -> erg_common::shared::MappedRwLockReadGuard<'_, Constraint> {
|
||||
erg_common::shared::RwLockReadGuard::map(self.borrow(), |f| match f {
|
||||
#[track_caller]
|
||||
pub fn crack_constraint(&self) -> MappedRwLockReadGuard<'_, Constraint> {
|
||||
RwLockReadGuard::map(self.borrow(), |f| match f {
|
||||
FreeKind::Linked(_) | FreeKind::UndoableLinked { .. } => panic!("the value is linked"),
|
||||
FreeKind::Unbound { constraint, .. } | FreeKind::NamedUnbound { constraint, .. } => {
|
||||
constraint
|
||||
|
@ -811,6 +807,7 @@ impl<T> Free<T> {
|
|||
impl<T: Clone + fmt::Debug> Free<T> {
|
||||
/// SAFETY: use `Type/TyParam::link` instead of this.
|
||||
/// This method may cause circular references.
|
||||
#[track_caller]
|
||||
pub(super) fn link(&self, to: &T) {
|
||||
// prevent linking to self
|
||||
if self.is_linked() && addr_eq!(*self.crack(), *to) {
|
||||
|
@ -819,19 +816,7 @@ impl<T: Clone + fmt::Debug> Free<T> {
|
|||
self.borrow_mut().replace(to.clone());
|
||||
}
|
||||
|
||||
/// NOTE: Do not use this except to rewrite circular references.
|
||||
/// No reference to any type variable may be left behind when rewriting.
|
||||
/// However, `get_subsup` is safe because it does not return references.
|
||||
pub(super) fn forced_link(&self, to: &T) {
|
||||
// prevent linking to self
|
||||
if self.is_linked() && addr_eq!(*self.crack(), *to) {
|
||||
return;
|
||||
}
|
||||
unsafe {
|
||||
self.as_ptr().as_mut().unwrap().replace(to.clone());
|
||||
}
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
pub fn undoable_link(&self, to: &T) {
|
||||
if self.is_linked() && addr_eq!(*self.crack(), *to) {
|
||||
panic!("link to self");
|
||||
|
@ -844,29 +829,12 @@ impl<T: Clone + fmt::Debug> Free<T> {
|
|||
*self.borrow_mut() = new;
|
||||
}
|
||||
|
||||
/// NOTE: Do not use this except to rewrite circular references.
|
||||
/// No reference to any type variable may be left behind when rewriting.
|
||||
/// However, `get_subsup` is safe because it does not return references.
|
||||
pub fn forced_undoable_link(&self, to: &T) {
|
||||
if self.is_linked() && addr_eq!(*self.crack(), *to) {
|
||||
panic!("link to self");
|
||||
}
|
||||
let prev = self.clone_inner();
|
||||
let new = FreeKind::UndoableLinked {
|
||||
t: to.clone(),
|
||||
previous: Box::new(prev),
|
||||
};
|
||||
self.force_replace(new);
|
||||
}
|
||||
|
||||
pub fn undo(&self) {
|
||||
match &*self.borrow() {
|
||||
FreeKind::UndoableLinked { previous, .. } => {
|
||||
let prev = *previous.clone();
|
||||
self.force_replace(prev);
|
||||
}
|
||||
_other => panic!("cannot undo: {_other:?}"),
|
||||
}
|
||||
let prev = match &*self.borrow() {
|
||||
FreeKind::UndoableLinked { previous, .. } => *previous.clone(),
|
||||
_other => panic!("cannot undo"),
|
||||
};
|
||||
self.replace(prev);
|
||||
}
|
||||
|
||||
pub fn unwrap_unbound(self) -> (Option<Str>, usize, Constraint) {
|
||||
|
@ -916,7 +884,7 @@ impl<T: Clone + fmt::Debug> Free<T> {
|
|||
|
||||
impl<T: Default + Clone + fmt::Debug> Free<T> {
|
||||
pub fn dummy_link(&self) {
|
||||
self.forced_undoable_link(&T::default());
|
||||
self.undoable_link(&T::default());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2326,7 +2326,7 @@ impl Type {
|
|||
|
||||
pub fn qvars(&self) -> Set<(Str, Constraint)> {
|
||||
match self {
|
||||
Self::FreeVar(fv) if fv.is_linked() => fv.crack().qvars(),
|
||||
Self::FreeVar(fv) if fv.is_linked() => fv.unsafe_crack().qvars(),
|
||||
Self::FreeVar(fv) if !fv.constraint_is_uninited() => {
|
||||
let base = set! {(fv.unbound_name().unwrap(), fv.constraint().unwrap())};
|
||||
if let Some((sub, sup)) = fv.get_subsup() {
|
||||
|
@ -2973,17 +2973,6 @@ impl Type {
|
|||
_ => panic!("{self} is not a free variable"),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn forced_link(&self, to: &Type) {
|
||||
if self.addr_eq(to) {
|
||||
return;
|
||||
}
|
||||
match self {
|
||||
Self::FreeVar(fv) => fv.forced_link(to),
|
||||
Self::Refinement(refine) => refine.t.forced_link(to),
|
||||
_ => panic!("{self} is not a free variable"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ReplaceTable<'t> {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue