Skip to content

Commit

Permalink
fix: recursion bugs of structural types
Browse files Browse the repository at this point in the history
  • Loading branch information
mtshiba committed Sep 10, 2024
1 parent 948a14b commit beee3b8
Show file tree
Hide file tree
Showing 5 changed files with 27 additions and 5 deletions.
6 changes: 3 additions & 3 deletions crates/erg_common/shared.rs
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,8 @@ impl<T: ?Sized> Shared<T> {
#[track_caller]
pub fn borrow(&self) -> RwLockReadGuard<'_, T> {
self.wait_until_unlocked();
#[cfg(any(feature = "backtrace", feature = "debug"))]
let first_catcher = self.data.try_write_for(GET_TIMEOUT).is_some();
let res = self.data.try_read_for(GET_TIMEOUT).unwrap_or_else(|| {
#[cfg(any(feature = "backtrace", feature = "debug"))]
{
Expand All @@ -159,7 +161,7 @@ impl<T: ?Sized> Shared<T> {
}
});
#[cfg(any(feature = "backtrace", feature = "debug"))]
{
if first_catcher {
*self.last_borrowed_at.try_write_for(GET_TIMEOUT).unwrap() =
BorrowInfo::new(Some(std::panic::Location::caller()));
}
Expand Down Expand Up @@ -187,8 +189,6 @@ impl<T: ?Sized> Shared<T> {
#[cfg(any(feature = "backtrace", feature = "debug"))]
{
let caller = std::panic::Location::caller();
*self.last_borrowed_at.try_write_for(SET_TIMEOUT).unwrap() =
BorrowInfo::new(Some(caller));
*self
.last_mut_borrowed_at
.try_write_for(SET_TIMEOUT)
Expand Down
3 changes: 2 additions & 1 deletion crates/erg_compiler/context/compare.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use erg_common::dict::Dict;
use erg_common::set::Set;
use erg_common::style::colors::DEBUG_ERROR;
use erg_common::traits::StructuralEq;
use erg_common::{assume_unreachable, log};
use erg_common::{assume_unreachable, log, set_recursion_limit};
use erg_common::{Str, Triple};

use crate::context::eval::UndoableLinkedList;
Expand Down Expand Up @@ -355,6 +355,7 @@ impl Context {
/// 単一化、評価等はここでは行わない、スーパータイプになる **可能性があるか** だけ判定する
/// ので、lhsが(未連携)型変数の場合は単一化せずにtrueを返す
pub(crate) fn structural_supertype_of(&self, lhs: &Type, rhs: &Type) -> bool {
set_recursion_limit!(false, 128);
match (lhs, rhs) {
// Proc :> Func if params are compatible
// * default params can be omitted (e.g. (Int, x := Int) -> Int <: (Int) -> Int)
Expand Down
4 changes: 3 additions & 1 deletion crates/erg_compiler/context/inquire.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1294,9 +1294,11 @@ impl Context {
})
.collect::<Vec<_>>();
let return_t = free_var(self.level, Constraint::new_type_of(Type));
let subr_t = fn_met(obj.t(), nd_params, None, d_params, None, return_t);
let mut subr_t = fn_met(obj.t(), nd_params, None, d_params, None, return_t);
if let Some(fv) = obj.ref_t().as_free() {
if let Some((_sub, sup)) = fv.get_subsup() {
// avoid recursion
*subr_t.mut_self_t().unwrap() = Never;
let vis = self
.instantiate_vis_modifier(&attr_name.vis)
.unwrap_or(VisibilityModifier::Public);
Expand Down
3 changes: 3 additions & 0 deletions crates/erg_compiler/ty/free.rs
Original file line number Diff line number Diff line change
Expand Up @@ -739,6 +739,9 @@ impl<T: Send + Clone> Free<T> {
pub fn forced_as_ref(&self) -> &FreeKind<T> {
unsafe { self.as_ptr().as_ref() }.unwrap()
}
pub fn forced_as_mut(&mut self) -> &mut FreeKind<T> {
unsafe { self.as_ptr().as_mut() }.unwrap()
}
}

impl Free<Type> {
Expand Down
16 changes: 16 additions & 0 deletions crates/erg_compiler/ty/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3886,6 +3886,18 @@ impl Type {
}
}

pub fn mut_self_t(&mut self) -> Option<&mut Type> {
match self {
Self::FreeVar(fv) if fv.is_linked() => {
fv.forced_as_mut().linked_mut().and_then(|t| t.mut_self_t())
}
Self::Refinement(refine) => refine.t.mut_self_t(),
Self::Subr(subr) => subr.mut_self_t(),
Self::Quantified(quant) => quant.mut_self_t(),
_ => None,
}
}

pub fn non_default_params(&self) -> Option<&Vec<ParamTy>> {
match self {
Self::FreeVar(fv) if fv.is_linked() => fv
Expand Down Expand Up @@ -3999,6 +4011,10 @@ impl Type {

pub fn mut_return_t(&mut self) -> Option<&mut Type> {
match self {
Self::FreeVar(fv) if fv.is_linked() => fv
.forced_as_mut()
.linked_mut()
.and_then(|t| t.mut_return_t()),
Self::Refinement(refine) => refine.t.mut_return_t(),
Self::Subr(SubrType { return_t, .. }) | Self::Callable { return_t, .. } => {
Some(return_t)
Expand Down

0 comments on commit beee3b8

Please sign in to comment.