diff --git a/crates/els/completion.rs b/crates/els/completion.rs index 8b725e4f2..9debd8b84 100644 --- a/crates/els/completion.rs +++ b/crates/els/completion.rs @@ -297,7 +297,7 @@ fn load_modules(cfg: ErgConfig, cache: Cache) { cache.insert("".into(), module_completions()); } let std_path = erg_pystd_path().display().to_string().replace('\\', "/"); - for (path, entry) in shared.py_mod_cache.iter() { + for (path, entry) in shared.py_mod_cache.ref_inner().iter() { let dir = entry.module.context.local_dir(); let mod_name = path.display().to_string().replace('\\', "/"); let mod_name = mod_name diff --git a/crates/els/rename.rs b/crates/els/rename.rs index 603493335..ba479d52a 100644 --- a/crates/els/rename.rs +++ b/crates/els/rename.rs @@ -149,6 +149,7 @@ impl Server { graph.sort().unwrap(); let self_node = graph.get_node(&path).unwrap(); graph + .ref_inner() .iter() .filter(|node| node.id == path || self_node.depends_on(&node.id)) .map(|node| NormalizedUrl::new(Url::from_file_path(&node.id).unwrap())) @@ -160,6 +161,7 @@ impl Server { let graph = &self.get_shared().unwrap().graph; let path = util::uri_to_path(uri); graph + .ref_inner() .iter() .filter(|node| node.depends_on(&path)) .map(|node| NormalizedUrl::new(Url::from_file_path(&node.id).unwrap())) diff --git a/crates/els/server.rs b/crates/els/server.rs index 952b23785..df6db2fd6 100644 --- a/crates/els/server.rs +++ b/crates/els/server.rs @@ -651,7 +651,7 @@ impl Server { pub(crate) fn get_builtin_module(&self) -> Option<&Context> { self.get_shared() - .and_then(|mode| mode.mod_cache.ref_ctx(Path::new(""))) + .and_then(|mode| mode.mod_cache.raw_ref_ctx(Path::new(""))) .map(|mc| &mc.context) } diff --git a/crates/erg_common/spawn.rs b/crates/erg_common/spawn.rs index 00bfaf624..e9a2f9899 100644 --- a/crates/erg_common/spawn.rs +++ b/crates/erg_common/spawn.rs @@ -29,7 +29,10 @@ where .spawn(run) .unwrap(); // Wait for thread to join - child.join().unwrap() + child.join().unwrap_or_else(|err| { + eprintln!("Thread panicked: {err:?}"); + std::process::exit(1); + }) } else { run() } diff --git a/crates/erg_compiler/context/generalize.rs b/crates/erg_compiler/context/generalize.rs index 27cfd63ec..f4dbe73dc 100644 --- a/crates/erg_compiler/context/generalize.rs +++ b/crates/erg_compiler/context/generalize.rs @@ -135,7 +135,7 @@ impl Generalizer { /// ``` fn generalize_t(&mut self, free_type: Type, uninit: bool) -> Type { match free_type { - FreeVar(fv) if fv.is_linked() => self.generalize_t(fv.crack().clone(), uninit), + FreeVar(fv) if fv.is_linked() => self.generalize_t(fv.unsafe_crack().clone(), uninit), FreeVar(fv) if fv.is_generalized() => Type::FreeVar(fv), // TODO: Polymorphic generalization FreeVar(fv) if fv.level().unwrap() > self.level => { diff --git a/crates/erg_compiler/context/initialize/mod.rs b/crates/erg_compiler/context/initialize/mod.rs index b20cb3176..145c34728 100644 --- a/crates/erg_compiler/context/initialize/mod.rs +++ b/crates/erg_compiler/context/initialize/mod.rs @@ -772,7 +772,7 @@ impl Context { ); self.consts.insert(name.clone(), val); for impl_trait in ctx.super_traits.iter() { - if let Some(impls) = self.trait_impls().get_mut(&impl_trait.qual_name()) { + if let Some(mut impls) = self.trait_impls().get_mut(&impl_trait.qual_name()) { impls.insert(TraitImpl::new(t.clone(), impl_trait.clone())); } else { self.trait_impls().register( @@ -848,7 +848,7 @@ impl Context { } self.consts.insert(name.clone(), val); for impl_trait in ctx.super_traits.iter() { - if let Some(impls) = self.trait_impls().get_mut(&impl_trait.qual_name()) { + if let Some(mut impls) = self.trait_impls().get_mut(&impl_trait.qual_name()) { impls.insert(TraitImpl::new(t.clone(), impl_trait.clone())); } else { self.trait_impls().register( @@ -912,7 +912,8 @@ impl Context { } } if let ContextKind::GluePatch(tr_impl) = &ctx.kind { - if let Some(impls) = self.trait_impls().get_mut(&tr_impl.sup_trait.qual_name()) { + if let Some(mut impls) = self.trait_impls().get_mut(&tr_impl.sup_trait.qual_name()) + { impls.insert(tr_impl.clone()); } else { self.trait_impls() diff --git a/crates/erg_compiler/context/inquire.rs b/crates/erg_compiler/context/inquire.rs index 7a71f0aa6..aa199517f 100644 --- a/crates/erg_compiler/context/inquire.rs +++ b/crates/erg_compiler/context/inquire.rs @@ -55,8 +55,8 @@ impl Context { return Some(self.get_module().unwrap()) } self.opt_mod_cache()? - .ref_ctx(path) - .or_else(|| self.opt_py_mod_cache()?.ref_ctx(path)) + .raw_ref_ctx(path) + .or_else(|| self.opt_py_mod_cache()?.raw_ref_ctx(path)) .map(|mod_ctx| &mod_ctx.context) } @@ -2463,7 +2463,10 @@ impl Context { pub(crate) fn get_mod_with_path(&self, path: &Path) -> Option<&Context> { (self.cfg.input.path() == Some(path)) // module itself .then_some(self) - .or(self.mod_cache().get(path).map(|ent| &ent.module.context)) + .or(self + .mod_cache() + .raw_ref_ctx(path) + .map(|mod_ctx| &mod_ctx.context)) } // FIXME: 現在の実装だとimportしたモジュールはどこからでも見れる diff --git a/crates/erg_compiler/context/mod.rs b/crates/erg_compiler/context/mod.rs index fb04345a7..c61daccc5 100644 --- a/crates/erg_compiler/context/mod.rs +++ b/crates/erg_compiler/context/mod.rs @@ -977,7 +977,12 @@ impl Context { if self.kind != ContextKind::Module || &self.path()[..] != "" { self.shared .as_ref() - .map(|shared| shared.mod_cache.ref_ctx(Path::new("")).unwrap()) + .map(|shared| { + shared + .mod_cache + .raw_ref_ctx(Path::new("")) + .unwrap() + }) .map(|mod_ctx| &mod_ctx.context) } else { None diff --git a/crates/erg_compiler/context/register.rs b/crates/erg_compiler/context/register.rs index 084865a36..0a2ed1f1a 100644 --- a/crates/erg_compiler/context/register.rs +++ b/crates/erg_compiler/context/register.rs @@ -1653,7 +1653,7 @@ impl Context { self.decls.insert(name.clone(), vi); self.consts.insert(name.clone(), val); for impl_trait in ctx.super_traits.iter() { - if let Some(impls) = self.trait_impls().get_mut(&impl_trait.qual_name()) { + if let Some(mut impls) = self.trait_impls().get_mut(&impl_trait.qual_name()) { impls.insert(TraitImpl::new(t.clone(), impl_trait.clone())); } else { self.trait_impls().register( @@ -1733,7 +1733,7 @@ impl Context { self.consts .insert(name.clone(), ValueObj::Type(TypeObj::Generated(gen))); for impl_trait in ctx.super_traits.iter() { - if let Some(impls) = self.trait_impls().get_mut(&impl_trait.qual_name()) { + if let Some(mut impls) = self.trait_impls().get_mut(&impl_trait.qual_name()) { impls.insert(TraitImpl::new(t.clone(), impl_trait.clone())); } else { self.trait_impls().register( diff --git a/crates/erg_compiler/lint.rs b/crates/erg_compiler/lint.rs index db47423ee..03cd5a09c 100644 --- a/crates/erg_compiler/lint.rs +++ b/crates/erg_compiler/lint.rs @@ -169,7 +169,7 @@ impl ASTLowerer { if mode == "eval" { return; } - for (referee, value) in self.module.context.index().iter() { + for (referee, value) in self.module.context.index().members().iter() { let code = referee.code(); let name = code.as_ref().map(|s| &s[..]).unwrap_or(""); let name_is_auto = diff --git a/crates/erg_compiler/lower.rs b/crates/erg_compiler/lower.rs index 6326064cb..e9bde6fd0 100644 --- a/crates/erg_compiler/lower.rs +++ b/crates/erg_compiler/lower.rs @@ -1892,7 +1892,7 @@ impl ASTLowerer { trait_loc: &impl Locational, ) -> LowerResult<()> { // TODO: polymorphic trait - if let Some(impls) = self + if let Some(mut impls) = self .module .context .trait_impls() diff --git a/crates/erg_compiler/module/cache.rs b/crates/erg_compiler/module/cache.rs index a25c532e6..9aa9eb073 100644 --- a/crates/erg_compiler/module/cache.rs +++ b/crates/erg_compiler/module/cache.rs @@ -1,4 +1,5 @@ use std::borrow::Borrow; +use std::cell::{Ref, RefMut}; use std::fmt; use std::hash::Hash; use std::path::PathBuf; @@ -173,20 +174,28 @@ impl SharedModuleCache { self.0.borrow().cache.len() } - pub fn get(&self, path: &Q) -> Option<&ModuleEntry> + pub fn get(&self, path: &Q) -> Option> where PathBuf: Borrow, { - let ref_ = unsafe { self.0.as_ptr().as_ref().unwrap() }; - ref_.get(path) + if self.0.borrow().get(path).is_some() { + Some(Ref::map(self.0.borrow(), |cache| cache.get(path).unwrap())) + } else { + None + } } - pub fn get_mut(&self, path: &Q) -> Option<&mut ModuleEntry> + pub fn get_mut(&self, path: &Q) -> Option> where PathBuf: Borrow, { - let ref_ = unsafe { self.0.as_ptr().as_mut().unwrap() }; - ref_.get_mut(path) + if self.0.borrow().get(path).is_some() { + Some(RefMut::map(self.0.borrow_mut(), |cache| { + cache.get_mut(path).unwrap() + })) + } else { + None + } } pub fn get_ctx(&self, path: &Q) -> Option> @@ -196,7 +205,20 @@ impl SharedModuleCache { self.0.borrow().get(path).map(|entry| entry.module.clone()) } - pub fn ref_ctx(&self, path: &Q) -> Option<&ModuleContext> + pub fn ref_ctx(&self, path: &Q) -> Option> + where + PathBuf: Borrow, + { + if self.0.borrow().get(path).is_some() { + Some(Ref::map(self.0.borrow(), |cache| { + cache.get(path).unwrap().module.as_ref() + })) + } else { + None + } + } + + pub fn raw_ref_ctx(&self, path: &Q) -> Option<&ModuleContext> where PathBuf: Borrow, { @@ -223,18 +245,13 @@ impl SharedModuleCache { self.0.borrow().get_similar_name(name) } - pub fn keys(&self) -> impl Iterator { - let ref_ = unsafe { self.0.as_ptr().as_ref().unwrap() }; - ref_.cache.keys().cloned() - } - pub fn initialize(&self) { let builtin_path = PathBuf::from(""); let Some(builtin) = self.remove(&builtin_path) else { return; }; - for path in self.keys() { - self.remove(&path); + for path in self.ref_inner().keys() { + self.remove(path); } self.register(builtin_path, None, Rc::try_unwrap(builtin.module).unwrap()); } @@ -243,8 +260,7 @@ impl SharedModuleCache { self.0.borrow_mut().rename_path(path, new); } - pub fn iter(&self) -> impl Iterator { - let ref_ = unsafe { self.0.as_ptr().as_ref().unwrap() }; - ref_.iter() + pub fn ref_inner(&self) -> Ref> { + Ref::map(self.0.borrow(), |mc| &mc.cache) } } diff --git a/crates/erg_compiler/module/graph.rs b/crates/erg_compiler/module/graph.rs index 53f966df1..b4c7c0cbc 100644 --- a/crates/erg_compiler/module/graph.rs +++ b/crates/erg_compiler/module/graph.rs @@ -1,3 +1,4 @@ +use std::cell::Ref; use std::fmt; use std::path::{Path, PathBuf}; @@ -109,10 +110,14 @@ impl SharedModuleGraph { Self(Shared::new(ModuleGraph::new())) } - /// SAFETY: don't hold this reference before sorting - pub fn get_node(&self, path: &Path) -> Option<&Node> { - let ref_graph = unsafe { self.0.as_ptr().as_ref().unwrap() }; - ref_graph.get_node(path) + pub fn get_node(&self, path: &Path) -> Option>> { + if self.0.borrow().get_node(path).is_some() { + Some(Ref::map(self.0.borrow(), |graph| { + graph.get_node(path).unwrap() + })) + } else { + None + } } pub fn add_node_if_none(&self, path: &Path) { @@ -123,10 +128,8 @@ impl SharedModuleGraph { self.0.borrow_mut().inc_ref(referrer, depends_on); } - /// SAFETY: don't hold this iterator before sorting - pub fn iter(&self) -> impl Iterator> { - let ref_graph = unsafe { self.0.as_ptr().as_ref().unwrap() }; - ref_graph.iter() + pub fn ref_inner(&self) -> Ref { + self.0.borrow() } pub fn remove(&self, path: &Path) { diff --git a/crates/erg_compiler/module/impls.rs b/crates/erg_compiler/module/impls.rs index e5fb77f75..3702f1852 100644 --- a/crates/erg_compiler/module/impls.rs +++ b/crates/erg_compiler/module/impls.rs @@ -1,4 +1,5 @@ use std::borrow::Borrow; +use std::cell::{Ref, RefMut}; use std::fmt; use std::hash::Hash; @@ -76,20 +77,28 @@ impl SharedTraitImpls { Self(Shared::new(TraitImpls::new())) } - pub fn get(&self, path: &Q) -> Option<&Set> + pub fn get(&self, path: &Q) -> Option>> where Str: Borrow, { - let ref_ = unsafe { self.0.as_ptr().as_ref().unwrap() }; - ref_.get(path) + if self.0.borrow().get(path).is_some() { + Some(Ref::map(self.0.borrow(), |tis| tis.get(path).unwrap())) + } else { + None + } } - pub fn get_mut(&self, path: &Q) -> Option<&mut Set> + pub fn get_mut(&self, path: &Q) -> Option>> where Str: Borrow, { - let ref_ = unsafe { self.0.as_ptr().as_mut().unwrap() }; - ref_.get_mut(path) + if self.0.borrow().get(path).is_some() { + Some(RefMut::map(self.0.borrow_mut(), |tis| { + tis.get_mut(path).unwrap() + })) + } else { + None + } } pub fn register(&self, name: Str, impls: Set) { @@ -103,9 +112,8 @@ impl SharedTraitImpls { self.0.borrow_mut().remove(path) } - pub fn keys(&self) -> impl Iterator { - let ref_ = unsafe { self.0.as_ptr().as_ref().unwrap() }; - ref_.cache.keys().cloned() + pub fn ref_inner(&self) -> Ref>> { + Ref::map(self.0.borrow(), |tis| &tis.cache) } pub fn initialize(&self) { diff --git a/crates/erg_compiler/module/index.rs b/crates/erg_compiler/module/index.rs index d87226cd7..1cc531b45 100644 --- a/crates/erg_compiler/module/index.rs +++ b/crates/erg_compiler/module/index.rs @@ -1,3 +1,4 @@ +use std::cell::Ref; use std::collections::hash_map::{Iter, Keys, Values}; use std::fmt; use std::path::Path; @@ -9,6 +10,22 @@ use erg_common::shared::Shared; use crate::varinfo::{AbsLocation, VarInfo}; +pub struct Members<'a>(Ref<'a, Dict>); + +impl<'a> Members<'a> { + pub fn iter(&self) -> Iter { + self.0.iter() + } + + pub fn keys(&self) -> Keys { + self.0.keys() + } + + pub fn values(&self) -> Values { + self.0.values() + } +} + #[derive(Debug, Clone, Default)] pub struct ModuleIndexValue { pub vi: VarInfo, @@ -101,20 +118,18 @@ impl SharedModuleIndex { self.0.borrow_mut().register(vi); } - pub fn get_refs(&self, referee: &AbsLocation) -> Option<&ModuleIndexValue> { - unsafe { self.0.as_ptr().as_ref().unwrap().get_refs(referee) } - } - - pub fn referees(&self) -> Keys { - unsafe { self.0.as_ptr().as_ref().unwrap().members.keys() } - } - - pub fn referrers(&self) -> Values { - unsafe { self.0.as_ptr().as_ref().unwrap().members.values() } + pub fn get_refs(&self, referee: &AbsLocation) -> Option> { + if self.0.borrow().get_refs(referee).is_some() { + Some(Ref::map(self.0.borrow(), |index| { + index.get_refs(referee).unwrap() + })) + } else { + None + } } - pub fn iter(&self) -> Iter { - unsafe { self.0.as_ptr().as_ref().unwrap().members.iter() } + pub fn members(&self) -> Members { + Members(Ref::map(self.0.borrow(), |mi| &mi.members)) } pub fn initialize(&self) { diff --git a/crates/erg_compiler/ty/free.rs b/crates/erg_compiler/ty/free.rs index 6caddb3ac..a75a5bc12 100644 --- a/crates/erg_compiler/ty/free.rs +++ b/crates/erg_compiler/ty/free.rs @@ -666,26 +666,25 @@ impl Free { impl HasLevel for Free { fn set_level(&self, level: Level) { - match unsafe { &mut *self.as_ptr() as &mut FreeKind } { + match &mut *self.borrow_mut() { FreeKind::Unbound { lev, .. } | FreeKind::NamedUnbound { lev, .. } => { if addr_eq!(*lev, level) { return; } *lev = level; - if let Some((sub, sup)) = self.get_subsup() { - self.dummy_link(); - sub.set_level(level); - sup.set_level(level); - self.undo(); - } else if let Some(t) = self.get_type() { - t.set_level(level); - } - } - FreeKind::Linked(t) => { - t.set_level(level); } _ => {} } + if let Some(linked) = self.raw_get_linked() { + linked.set_level(level); + } else if let Some((sub, sup)) = self.get_subsup() { + self.dummy_link(); + sub.set_level(level); + sup.set_level(level); + self.undo(); + } else if let Some(t) = self.get_type() { + t.set_level(level); + } } fn level(&self) -> Option { @@ -698,21 +697,20 @@ impl HasLevel for Free { impl HasLevel for Free { fn set_level(&self, level: Level) { - match unsafe { &mut *self.as_ptr() as &mut FreeKind } { + match &mut *self.borrow_mut() { FreeKind::Unbound { lev, .. } | FreeKind::NamedUnbound { lev, .. } => { if addr_eq!(*lev, level) { return; } *lev = level; - if let Some(t) = self.get_type() { - t.set_level(level); - } - } - FreeKind::Linked(t) => { - t.set_level(level); } _ => {} } + if let Some(linked) = self.raw_get_linked() { + linked.set_level(level); + } else if let Some(t) = self.get_type() { + t.set_level(level); + } } fn level(&self) -> Option { @@ -866,17 +864,50 @@ impl Free { } } - pub fn get_linked(&self) -> Option { - match &*self.borrow() { - FreeKind::Linked(t) | FreeKind::UndoableLinked { t, .. } => Some(t.clone()), - FreeKind::Unbound { .. } | FreeKind::NamedUnbound { .. } => None, + pub fn raw_get_linked(&self) -> Option<&T> { + if !self.is_linked() { + None + } else { + Some(self.unsafe_crack()) } } - pub fn get_previous(&self) -> Option> { - match &*self.borrow() { - FreeKind::UndoableLinked { previous, .. } => Some(*previous.clone()), - _other => None, + #[track_caller] + pub fn get_linked_ref(&self) -> Option> { + if !self.is_linked() { + None + } else { + let mapped = Ref::map(self.borrow(), |f| match f { + FreeKind::Linked(t) | FreeKind::UndoableLinked { t, .. } => t, + FreeKind::Unbound { .. } | FreeKind::NamedUnbound { .. } => unreachable!(), + }); + Some(mapped) + } + } + + #[track_caller] + pub fn get_linked_refmut(&self) -> Option> { + if !self.is_linked() { + None + } else { + let mapped = RefMut::map(self.borrow_mut(), |f| match f { + FreeKind::Linked(t) | FreeKind::UndoableLinked { t, .. } => t, + FreeKind::Unbound { .. } | FreeKind::NamedUnbound { .. } => unreachable!(), + }); + Some(mapped) + } + } + + #[track_caller] + pub fn get_previous(&self) -> Option>>> { + if !self.is_undoable_linked() { + None + } else { + let mapped = RefMut::map(self.borrow_mut(), |f| match f { + FreeKind::UndoableLinked { previous, .. } => previous, + _ => unreachable!(), + }); + Some(mapped) } } @@ -939,7 +970,7 @@ impl Free { /// 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) { - match unsafe { &mut *self.as_ptr() as &mut FreeKind } { + match &mut *self.borrow_mut() { FreeKind::Unbound { lev, constraint, .. } @@ -985,13 +1016,9 @@ impl Free { where F: Fn(TyParam) -> TyParam, { - match unsafe { &mut *self.as_ptr() as &mut FreeKind } { - FreeKind::Unbound { .. } | FreeKind::NamedUnbound { .. } => { - panic!("the value is unbounded") - } - FreeKind::Linked(t) | FreeKind::UndoableLinked { t, .. } => { - *t = f(mem::take(t)); - } + if let Some(mut linked) = self.get_linked_refmut() { + let mapped = f(mem::take(&mut *linked)); + *linked = mapped; } } } diff --git a/crates/erg_compiler/ty/mod.rs b/crates/erg_compiler/ty/mod.rs index 0754e9fc9..57b704a48 100644 --- a/crates/erg_compiler/ty/mod.rs +++ b/crates/erg_compiler/ty/mod.rs @@ -2570,10 +2570,9 @@ impl Type { pub fn self_t(&self) -> Option<&Type> { match self { - Self::FreeVar(fv) if fv.is_linked() => unsafe { fv.as_ptr().as_ref() } - .unwrap() - .linked() - .and_then(|t| t.self_t()), + Self::FreeVar(fv) if fv.is_linked() => { + fv.forced_as_ref().linked().and_then(|t| t.self_t()) + } Self::Refinement(refine) => refine.t.self_t(), Self::Subr(subr) => subr.self_t(), Self::Quantified(quant) => quant.self_t(), @@ -2583,8 +2582,8 @@ impl Type { pub fn non_default_params(&self) -> Option<&Vec> { match self { - Self::FreeVar(fv) if fv.is_linked() => unsafe { fv.as_ptr().as_ref() } - .unwrap() + Self::FreeVar(fv) if fv.is_linked() => fv + .forced_as_ref() .linked() .and_then(|t| t.non_default_params()), Self::Refinement(refine) => refine.t.non_default_params(), @@ -2599,10 +2598,9 @@ impl Type { pub fn var_params(&self) -> Option<&ParamTy> { match self { - Self::FreeVar(fv) if fv.is_linked() => unsafe { fv.as_ptr().as_ref() } - .unwrap() - .linked() - .and_then(|t| t.var_params()), + Self::FreeVar(fv) if fv.is_linked() => { + fv.forced_as_ref().linked().and_then(|t| t.var_params()) + } Self::Refinement(refine) => refine.t.var_params(), Self::Subr(SubrType { var_params: var_args, @@ -2616,10 +2614,9 @@ impl Type { pub fn default_params(&self) -> Option<&Vec> { match self { - Self::FreeVar(fv) if fv.is_linked() => unsafe { fv.as_ptr().as_ref() } - .unwrap() - .linked() - .and_then(|t| t.default_params()), + Self::FreeVar(fv) if fv.is_linked() => { + fv.forced_as_ref().linked().and_then(|t| t.default_params()) + } Self::Refinement(refine) => refine.t.default_params(), Self::Subr(SubrType { default_params, .. }) => Some(default_params), Self::Quantified(quant) => quant.default_params(), @@ -2629,10 +2626,9 @@ impl Type { pub fn non_var_params(&self) -> Option + Clone> { match self { - Self::FreeVar(fv) if fv.is_linked() => unsafe { fv.as_ptr().as_ref() } - .unwrap() - .linked() - .and_then(|t| t.non_var_params()), + Self::FreeVar(fv) if fv.is_linked() => { + fv.forced_as_ref().linked().and_then(|t| t.non_var_params()) + } Self::Refinement(refine) => refine.t.non_var_params(), Self::Subr(subr) => Some(subr.non_var_params()), Self::Quantified(quant) => quant.non_var_params(), @@ -2642,10 +2638,9 @@ impl Type { pub fn return_t(&self) -> Option<&Type> { match self { - Self::FreeVar(fv) if fv.is_linked() => unsafe { fv.as_ptr().as_ref() } - .unwrap() - .linked() - .and_then(|t| t.return_t()), + Self::FreeVar(fv) if fv.is_linked() => { + fv.forced_as_ref().linked().and_then(|t| t.return_t()) + } Self::Refinement(refine) => refine.t.return_t(), Self::Subr(SubrType { return_t, .. }) | Self::Callable { return_t, .. } => { Some(return_t)