fix: borrow error

This commit is contained in:
Shunsuke Shibayama 2024-08-16 15:00:12 +09:00
parent 2ff3194d69
commit e1ffa2d739
7 changed files with 63 additions and 51 deletions

View file

@ -81,3 +81,7 @@ inst = "install --path . --features els"
dinst = "install --path . --features debug --features els" dinst = "install --path . --features debug --features els"
ntest = "nextest run" ntest = "nextest run"
# +nightly
# you must specify the --target option
drc_r = "r -Zbuild-std -Zbuild-std-features=core/debug_refcell"

View file

@ -378,7 +378,7 @@ impl<T: Send + Clone> Forkable<T> {
} }
#[cfg(not(any(feature = "backtrace", feature = "debug")))] #[cfg(not(any(feature = "backtrace", feature = "debug")))]
{ {
panic!("Forkable::borrow: {err}") panic!("Forkable::borrow: {err:?}")
} }
} }
} }
@ -417,7 +417,7 @@ impl<T: Send + Clone> Forkable<T> {
} }
#[cfg(not(any(feature = "backtrace", feature = "debug")))] #[cfg(not(any(feature = "backtrace", feature = "debug")))]
{ {
panic!("Forkable::borrow_mut: {err}") panic!("Forkable::borrow_mut: {err:?}")
} }
} }
} }

View file

@ -13,7 +13,7 @@ use erg_common::{Str, Triple};
use crate::context::eval::UndoableLinkedList; use crate::context::eval::UndoableLinkedList;
use crate::context::initialize::const_func::sub_tpdict_get; use crate::context::initialize::const_func::sub_tpdict_get;
use crate::ty::constructors::{self, and, bounded, not, or, poly, refinement}; use crate::ty::constructors::{self, and, bounded, not, or, poly, refinement};
use crate::ty::free::{Constraint, FreeKind, FreeTyVar}; use crate::ty::free::{Constraint, FreeTyVar};
use crate::ty::typaram::{TyParam, TyParamOrdering}; use crate::ty::typaram::{TyParam, TyParamOrdering};
use crate::ty::value::ValueObj; use crate::ty::value::ValueObj;
use crate::ty::value::ValueObj::Inf; use crate::ty::value::ValueObj::Inf;
@ -82,23 +82,19 @@ impl Context {
.zip(rargs.iter()) .zip(rargs.iter())
.all(|(l, r)| self.eq_tp(l, r)) .all(|(l, r)| self.eq_tp(l, r))
} }
(TyParam::FreeVar(fv), other) | (other, TyParam::FreeVar(fv)) => match &*fv.borrow() { (TyParam::FreeVar(fv), other) | (other, TyParam::FreeVar(fv)) if fv.is_linked() => {
FreeKind::Linked(linked) | FreeKind::UndoableLinked { t: linked, .. } => { return self.eq_tp(&fv.get_linked().unwrap(), other)
return self.eq_tp(linked, other);
} }
FreeKind::Unbound { constraint, .. } (TyParam::FreeVar(fv), other) | (other, TyParam::FreeVar(fv))
| FreeKind::NamedUnbound { constraint, .. } => { if fv.get_type().is_some() =>
let Some(t) = constraint.get_type() else { {
log!(err "Invalid type variable: {fv}"); let t = fv.get_type().unwrap();
return false; if DEBUG_MODE && t == Uninited {
};
if DEBUG_MODE && t == &Uninited {
panic!("Uninited type variable: {fv}"); panic!("Uninited type variable: {fv}");
} }
let other_t = self.type_of(other); let other_t = self.type_of(other);
return self.same_type_of(t, &other_t); return self.same_type_of(&t, &other_t);
} }
},
(TyParam::Value(ValueObj::Type(l)), TyParam::Type(r)) => { (TyParam::Value(ValueObj::Type(l)), TyParam::Type(r)) => {
return self.same_type_of(l.typ(), r.as_ref()); return self.same_type_of(l.typ(), r.as_ref());
} }
@ -864,7 +860,7 @@ impl Context {
pub fn fields(&self, t: &Type) -> Dict<Field, Type> { pub fn fields(&self, t: &Type) -> Dict<Field, Type> {
match t { match t {
Type::FreeVar(fv) if fv.is_linked() => self.fields(&fv.crack()), Type::FreeVar(fv) if fv.is_linked() => self.fields(fv.unsafe_crack()),
Type::Record(fields) => fields.clone(), Type::Record(fields) => fields.clone(),
Type::NamedTuple(fields) => fields.iter().cloned().collect(), Type::NamedTuple(fields) => fields.iter().cloned().collect(),
Type::Refinement(refine) => self.fields(&refine.t), Type::Refinement(refine) => self.fields(&refine.t),
@ -1239,10 +1235,10 @@ impl Context {
} else { Some(Any) } } else { Some(Any) }
}, },
(TyParam::FreeVar(fv), p) if fv.is_linked() => { (TyParam::FreeVar(fv), p) if fv.is_linked() => {
self.try_cmp(&fv.crack(), p) self.try_cmp(fv.unsafe_crack(), p)
} }
(p, TyParam::FreeVar(fv)) if fv.is_linked() => { (p, TyParam::FreeVar(fv)) if fv.is_linked() => {
self.try_cmp(p, &fv.crack()) self.try_cmp(p, fv.unsafe_crack())
} }
( (
l @ (TyParam::FreeVar(_) | TyParam::Erased(_)), l @ (TyParam::FreeVar(_) | TyParam::Erased(_)),
@ -1353,7 +1349,7 @@ impl Context {
} }
match (lhs, rhs) { match (lhs, rhs) {
(FreeVar(fv), other) | (other, FreeVar(fv)) if fv.is_linked() => { (FreeVar(fv), other) | (other, FreeVar(fv)) if fv.is_linked() => {
self.union(&fv.crack(), other) self.union(fv.unsafe_crack(), other)
} }
(Refinement(l), Refinement(r)) => Type::Refinement(self.union_refinement(l, r)), (Refinement(l), Refinement(r)) => Type::Refinement(self.union_refinement(l, r)),
(Refinement(refine), other) | (other, Refinement(refine)) (Refinement(refine), other) | (other, Refinement(refine))
@ -1592,7 +1588,7 @@ impl Context {
} }
match (lhs, rhs) { match (lhs, rhs) {
(FreeVar(fv), other) | (other, FreeVar(fv)) if fv.is_linked() => { (FreeVar(fv), other) | (other, FreeVar(fv)) if fv.is_linked() => {
self.intersection(&fv.crack(), other) self.intersection(fv.unsafe_crack(), other)
} }
(Refinement(l), Refinement(r)) => Type::Refinement(self.intersection_refinement(l, r)), (Refinement(l), Refinement(r)) => Type::Refinement(self.intersection_refinement(l, r)),
(Structural(l), Structural(r)) => self.intersection(l, r).structuralize(), (Structural(l), Structural(r)) => self.intersection(l, r).structuralize(),
@ -1609,7 +1605,7 @@ impl Context {
// {i = Int; j = Int} and not {i = Int} == {j = Int} // {i = Int; j = Int} and not {i = Int} == {j = Int}
// not {i = Int} and {i = Int; j = Int} == {j = Int} // not {i = Int} and {i = Int; j = Int} == {j = Int}
(other @ Record(rec), Not(t)) | (Not(t), other @ Record(rec)) => match t.as_ref() { (other @ Record(rec), Not(t)) | (Not(t), other @ Record(rec)) => match t.as_ref() {
Type::FreeVar(fv) => self.intersection(&fv.crack(), other), Type::FreeVar(fv) => self.intersection(fv.unsafe_crack(), other),
Type::Record(rec2) => Type::Record(rec.clone().diff(rec2)), Type::Record(rec2) => Type::Record(rec.clone().diff(rec2)),
_ => Type::Never, _ => Type::Never,
}, },
@ -1837,7 +1833,7 @@ impl Context {
#[allow(clippy::only_used_in_recursion)] #[allow(clippy::only_used_in_recursion)]
pub(crate) fn complement(&self, ty: &Type) -> Type { pub(crate) fn complement(&self, ty: &Type) -> Type {
match ty { match ty {
FreeVar(fv) if fv.is_linked() => self.complement(&fv.crack()), FreeVar(fv) if fv.is_linked() => self.complement(fv.unsafe_crack()),
Not(t) => *t.clone(), Not(t) => *t.clone(),
Refinement(r) => Type::Refinement(r.clone().invert()), Refinement(r) => Type::Refinement(r.clone().invert()),
Guard(guard) => Type::Guard(GuardType::new( Guard(guard) => Type::Guard(GuardType::new(
@ -1862,7 +1858,7 @@ impl Context {
_ => {} _ => {}
} }
match lhs { match lhs {
Type::FreeVar(fv) if fv.is_linked() => self.diff(&fv.crack(), rhs), Type::FreeVar(fv) if fv.is_linked() => self.diff(fv.unsafe_crack(), rhs),
// Type::And(l, r) => self.intersection(&self.diff(l, rhs), &self.diff(r, rhs)), // Type::And(l, r) => self.intersection(&self.diff(l, rhs), &self.diff(r, rhs)),
Type::Or(l, r) => self.union(&self.diff(l, rhs), &self.diff(r, rhs)), Type::Or(l, r) => self.union(&self.diff(l, rhs), &self.diff(r, rhs)),
_ => lhs.clone(), _ => lhs.clone(),

View file

@ -3466,7 +3466,7 @@ impl Context {
match p { match p {
TyParam::Value(v) => Ok(v_enum(set![v])), TyParam::Value(v) => Ok(v_enum(set![v])),
TyParam::Erased(t) => Ok((*t).clone()), TyParam::Erased(t) => Ok((*t).clone()),
TyParam::FreeVar(fv) if fv.is_linked() => self.get_tp_t(&fv.crack()), TyParam::FreeVar(fv) if fv.is_linked() => self.get_tp_t(fv.unsafe_crack()),
TyParam::FreeVar(fv) => { TyParam::FreeVar(fv) => {
if let Some(t) = fv.get_type() { if let Some(t) = fv.get_type() {
Ok(t) Ok(t)

View file

@ -983,7 +983,7 @@ impl Context {
// (obj: Failure).foo: Failure // (obj: Failure).foo: Failure
Type::Failure => Triple::Ok(VarInfo::ILLEGAL), Type::Failure => Triple::Ok(VarInfo::ILLEGAL),
Type::FreeVar(fv) if fv.is_linked() => { Type::FreeVar(fv) if fv.is_linked() => {
self.get_attr_info_from_attributive(&fv.crack(), ident, namespace) self.get_attr_info_from_attributive(fv.unsafe_crack(), ident, namespace)
} }
Type::FreeVar(fv) if fv.get_super().is_some() => { Type::FreeVar(fv) if fv.get_super().is_some() => {
let sup = fv.get_super().unwrap(); let sup = fv.get_super().unwrap();
@ -1781,9 +1781,14 @@ impl Context {
namespace: &Context, namespace: &Context,
) -> TyCheckResult<SubstituteResult> { ) -> TyCheckResult<SubstituteResult> {
match instance { match instance {
Type::FreeVar(fv) if fv.is_linked() => { Type::FreeVar(fv) if fv.is_linked() => self.substitute_call(
self.substitute_call(obj, attr_name, &fv.crack(), pos_args, kw_args, namespace) obj,
} attr_name,
fv.unsafe_crack(),
pos_args,
kw_args,
namespace,
),
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")) { if !self.subtype_of(&sub, &mono("GenericCallable")) {
@ -2792,7 +2797,9 @@ impl Context {
pub fn get_nominal_super_type_ctxs<'a>(&'a self, t: &Type) -> Option<Vec<&'a TypeContext>> { pub fn get_nominal_super_type_ctxs<'a>(&'a self, t: &Type) -> Option<Vec<&'a TypeContext>> {
match t { match t {
Type::FreeVar(fv) if fv.is_linked() => self.get_nominal_super_type_ctxs(&fv.crack()), Type::FreeVar(fv) if fv.is_linked() => {
self.get_nominal_super_type_ctxs(fv.unsafe_crack())
}
Type::FreeVar(fv) => { Type::FreeVar(fv) => {
if let Some(sup) = fv.get_super() { if let Some(sup) = fv.get_super() {
self.get_nominal_super_type_ctxs(&sup) self.get_nominal_super_type_ctxs(&sup)
@ -2898,7 +2905,7 @@ impl Context {
pub(crate) fn get_nominal_type_ctx<'a>(&'a self, typ: &Type) -> Option<&'a TypeContext> { pub(crate) fn get_nominal_type_ctx<'a>(&'a self, typ: &Type) -> Option<&'a TypeContext> {
match typ { match typ {
Type::FreeVar(fv) if fv.is_linked() => { Type::FreeVar(fv) if fv.is_linked() => {
if let Some(res) = self.get_nominal_type_ctx(&fv.crack()) { if let Some(res) = self.get_nominal_type_ctx(fv.unsafe_crack()) {
return Some(res); return Some(res);
} }
} }
@ -3075,7 +3082,7 @@ impl Context {
) -> Option<&'a mut TypeContext> { ) -> Option<&'a mut TypeContext> {
match typ { match typ {
Type::FreeVar(fv) if fv.is_linked() => { Type::FreeVar(fv) if fv.is_linked() => {
if let Some(res) = self.get_mut_nominal_type_ctx(&fv.crack()) { if let Some(res) = self.get_mut_nominal_type_ctx(fv.unsafe_crack()) {
return Some(res); return Some(res);
} }
} }
@ -3681,7 +3688,7 @@ impl Context {
match typ { match typ {
Type::And(_l, _r) => false, Type::And(_l, _r) => false,
Type::Never => true, Type::Never => true,
Type::FreeVar(fv) if fv.is_linked() => self.is_class(&fv.crack()), Type::FreeVar(fv) if fv.is_linked() => self.is_class(fv.unsafe_crack()),
Type::FreeVar(_) => false, Type::FreeVar(_) => false,
Type::Or(l, r) => self.is_class(l) && self.is_class(r), Type::Or(l, r) => self.is_class(l) && self.is_class(r),
Type::Proj { lhs, rhs } => self Type::Proj { lhs, rhs } => self
@ -3704,7 +3711,7 @@ impl Context {
pub fn is_trait(&self, typ: &Type) -> bool { pub fn is_trait(&self, typ: &Type) -> bool {
match typ { match typ {
Type::Never => false, Type::Never => false,
Type::FreeVar(fv) if fv.is_linked() => self.is_class(&fv.crack()), Type::FreeVar(fv) if fv.is_linked() => self.is_class(fv.unsafe_crack()),
Type::FreeVar(_) => false, Type::FreeVar(_) => false,
Type::And(l, r) | Type::Or(l, r) => self.is_trait(l) && self.is_trait(r), Type::And(l, r) | Type::Or(l, r) => self.is_trait(l) && self.is_trait(r),
Type::Proj { lhs, rhs } => self Type::Proj { lhs, rhs } => self

View file

@ -84,8 +84,8 @@ impl<'c, 'l, 'u, L: Locational> Unifier<'c, 'l, 'u, L> {
} }
} }
match (maybe_sub, maybe_sup) { match (maybe_sub, maybe_sup) {
(FreeVar(fv), _) if fv.is_linked() => self.occur(&fv.crack(), maybe_sup), (FreeVar(fv), _) if fv.is_linked() => self.occur(fv.unsafe_crack(), maybe_sup),
(_, FreeVar(fv)) if fv.is_linked() => self.occur(maybe_sub, &fv.crack()), (_, FreeVar(fv)) if fv.is_linked() => self.occur(maybe_sub, fv.unsafe_crack()),
(Subr(subr), FreeVar(fv)) if fv.is_unbound() => { (Subr(subr), FreeVar(fv)) if fv.is_unbound() => {
for default_t in subr.default_params.iter().map(|pt| pt.typ()) { for default_t in subr.default_params.iter().map(|pt| pt.typ()) {
self.occur_inner(default_t, maybe_sup)?; self.occur_inner(default_t, maybe_sup)?;
@ -173,8 +173,8 @@ impl<'c, 'l, 'u, L: Locational> Unifier<'c, 'l, 'u, L> {
fn occur_inner(&self, maybe_sub: &Type, maybe_sup: &Type) -> TyCheckResult<()> { fn occur_inner(&self, maybe_sub: &Type, maybe_sup: &Type) -> TyCheckResult<()> {
match (maybe_sub, maybe_sup) { match (maybe_sub, maybe_sup) {
(FreeVar(fv), _) if fv.is_linked() => self.occur_inner(&fv.crack(), maybe_sup), (FreeVar(fv), _) if fv.is_linked() => self.occur_inner(fv.unsafe_crack(), maybe_sup),
(_, FreeVar(fv)) if fv.is_linked() => self.occur_inner(maybe_sub, &fv.crack()), (_, FreeVar(fv)) if fv.is_linked() => self.occur_inner(maybe_sub, fv.unsafe_crack()),
(FreeVar(sub), FreeVar(sup)) => { (FreeVar(sub), FreeVar(sup)) => {
if sub.addr_eq(sup) { if sub.addr_eq(sup) {
Err(TyCheckErrors::from(TyCheckError::subtyping_error( Err(TyCheckErrors::from(TyCheckError::subtyping_error(
@ -404,12 +404,9 @@ impl<'c, 'l, 'u, L: Locational> Unifier<'c, 'l, 'u, L> {
Ok(()) Ok(())
} }
(TyParam::FreeVar(sub_fv), sup_tp) => { (TyParam::FreeVar(sub_fv), sup_tp) => {
match &*sub_fv.borrow() { if let Some(l) = sub_fv.get_linked() {
FreeKind::Linked(l) | FreeKind::UndoableLinked { t: l, .. } => { return self.sub_unify_tp(&l, sup_tp, _variance, allow_divergence);
return self.sub_unify_tp(l, sup_tp, _variance, allow_divergence);
} }
FreeKind::Unbound { .. } | FreeKind::NamedUnbound { .. } => {}
} // &fv is dropped
// sub_fvを参照しないようcloneする(あとでborrow_mutするため) // sub_fvを参照しないようcloneする(あとでborrow_mutするため)
let Some(fv_t) = sub_fv.constraint().unwrap().get_type().cloned() else { let Some(fv_t) = sub_fv.constraint().unwrap().get_type().cloned() else {
return Err(TyCheckErrors::from(TyCheckError::feature_error( return Err(TyCheckErrors::from(TyCheckError::feature_error(
@ -1817,8 +1814,8 @@ impl<'c, 'l, 'u, L: Locational> Unifier<'c, 'l, 'u, L> {
} }
return None; return None;
} }
(Type::FreeVar(fv), _) if fv.is_linked() => return self.unify(&fv.crack(), rhs), (Type::FreeVar(fv), _) if fv.is_linked() => return self.unify(fv.unsafe_crack(), rhs),
(_, Type::FreeVar(fv)) if fv.is_linked() => return self.unify(lhs, &fv.crack()), (_, Type::FreeVar(fv)) if fv.is_linked() => return self.unify(lhs, fv.unsafe_crack()),
// TODO: unify(?T, ?U) ? // TODO: unify(?T, ?U) ?
(Type::FreeVar(_), Type::FreeVar(_)) => {} (Type::FreeVar(_), Type::FreeVar(_)) => {}
(Type::FreeVar(fv), _) if fv.constraint_is_sandwiched() => { (Type::FreeVar(fv), _) if fv.constraint_is_sandwiched() => {

View file

@ -1,4 +1,4 @@
use std::cell::{Ref, RefMut}; use std::cell::{BorrowError, BorrowMutError, Ref, RefMut};
use std::fmt; use std::fmt;
use std::hash::{Hash, Hasher}; use std::hash::{Hash, Hasher};
use std::mem; use std::mem;
@ -666,6 +666,14 @@ impl<T: Send + Clone> Free<T> {
pub fn borrow_mut(&self) -> RefMut<'_, FreeKind<T>> { pub fn borrow_mut(&self) -> RefMut<'_, FreeKind<T>> {
self.0.borrow_mut() self.0.borrow_mut()
} }
#[track_caller]
pub fn try_borrow(&self) -> Result<Ref<'_, FreeKind<T>>, BorrowError> {
self.0.try_borrow()
}
#[track_caller]
pub fn try_borrow_mut(&self) -> Result<RefMut<'_, FreeKind<T>>, BorrowMutError> {
self.0.try_borrow_mut()
}
/// very unsafe, use `force_replace` instead whenever possible /// very unsafe, use `force_replace` instead whenever possible
pub fn as_ptr(&self) -> *mut FreeKind<T> { pub fn as_ptr(&self) -> *mut FreeKind<T> {
self.0.as_ptr() self.0.as_ptr()