diff --git a/compiler/mono/src/ir.rs b/compiler/mono/src/ir.rs index b598eb48a9..379a26fa58 100644 --- a/compiler/mono/src/ir.rs +++ b/compiler/mono/src/ir.rs @@ -9,7 +9,7 @@ use crate::layout::{ use bumpalo::collections::Vec; use bumpalo::Bump; use hashbrown::hash_map::Entry; -use roc_collections::all::{default_hasher, BumpMap, BumpMapDefault, MutMap, MutSet}; +use roc_collections::all::{default_hasher, BumpMap, BumpMapDefault, MutMap}; use roc_module::ident::{ForeignSymbol, Lowercase, TagName}; use roc_module::low_level::LowLevel; use roc_module::symbol::{IdentIds, ModuleId, Symbol}; @@ -378,7 +378,8 @@ impl<'a> Proc<'a> { #[derive(Clone, Debug)] pub struct ExternalSpecializations<'a> { - pub specs: BumpMap>, + /// Not a bumpalo vec because bumpalo is not thread safe + pub specs: BumpMap>, _lifetime: std::marker::PhantomData<&'a u8>, } @@ -394,11 +395,11 @@ impl<'a> ExternalSpecializations<'a> { use hashbrown::hash_map::Entry::{Occupied, Vacant}; let existing = match self.specs.entry(symbol) { - Vacant(entry) => entry.insert(MutSet::default()), + Vacant(entry) => entry.insert(std::vec::Vec::new()), Occupied(entry) => entry.into_mut(), }; - existing.insert(typ); + existing.push(typ); } pub fn extend(&mut self, other: Self) { @@ -406,7 +407,7 @@ impl<'a> ExternalSpecializations<'a> { for (symbol, solved_types) in other.specs { let existing = match self.specs.entry(symbol) { - Vacant(entry) => entry.insert(MutSet::default()), + Vacant(entry) => entry.insert(std::vec::Vec::new()), Occupied(entry) => entry.into_mut(), }; @@ -514,9 +515,12 @@ impl<'a> Procs<'a> { // by the surrounding context, so we can add pending specializations // for them immediately. - let tuple = (symbol, top_level); - let already_specialized = self.specialized.contains_key(&tuple); - let (symbol, layout) = tuple; + let already_specialized = self + .specialized + .keys() + .any(|(s, t)| *s == symbol && *t == top_level); + + let layout = top_level; // if we've already specialized this one, no further work is needed. if !already_specialized { @@ -778,8 +782,6 @@ impl<'a, 'i> Env<'a, 'i> { pub fn unique_symbol(&mut self) -> Symbol { let ident_id = self.ident_ids.gen_unique(); - self.home.register_debug_idents(self.ident_ids); - Symbol::new(self.home, ident_id) } @@ -1695,19 +1697,16 @@ pub fn specialize_all<'a>( env: &mut Env<'a, '_>, mut procs: Procs<'a>, externals_others_need: ExternalSpecializations<'a>, - pending_specializations: BumpMap, PendingSpecialization<'a>>>, + specializations_for_host: BumpMap, PendingSpecialization<'a>>>, layout_cache: &mut LayoutCache<'a>, ) -> Procs<'a> { - specialize_all_help(env, &mut procs, externals_others_need, layout_cache); + specialize_externals_others_need(env, &mut procs, externals_others_need, layout_cache); // When calling from_can, pending_specializations should be unavailable. // This must be a single pass, and we must not add any more entries to it! - - // observation: specialize_all_help does add to pending_specializations, but does not reference - // any existing values in it. let opt_pending_specializations = std::mem::replace(&mut procs.pending_specializations, None); - let it = pending_specializations + let it = specializations_for_host .into_iter() .chain(opt_pending_specializations.into_iter().flatten()); @@ -1774,33 +1773,35 @@ pub fn specialize_all<'a>( procs } -fn specialize_all_help<'a>( +fn specialize_externals_others_need<'a>( env: &mut Env<'a, '_>, procs: &mut Procs<'a>, externals_others_need: ExternalSpecializations<'a>, layout_cache: &mut LayoutCache<'a>, ) { for (symbol, solved_types) in externals_others_need.specs.iter() { - // for some unclear reason, the MutSet does not deduplicate according to the hash - // instance. So we do it manually here + // de-duplicate by the Hash instance (set only deduplicates by Eq instance) use std::collections::hash_map::DefaultHasher; use std::hash::{Hash, Hasher}; + let mut seen_hashes = Vec::with_capacity_in(solved_types.len(), env.arena); + let hash_the_thing = |x: &SolvedType| { let mut hasher = DefaultHasher::new(); x.hash(&mut hasher); hasher.finish() }; - let mut as_vec = Vec::from_iter_in( - solved_types.iter().map(|x| (hash_the_thing(x), x)), - env.arena, - ); + for solved_type in solved_types { + let hash = hash_the_thing(solved_type); - as_vec.sort_by_key(|(k, _)| *k); - as_vec.dedup_by_key(|(k, _)| *k); + if seen_hashes.iter().any(|h| *h == hash) { + // we've seen this one already + continue; + } + + seen_hashes.push(hash); - for (_, solved_type) in as_vec { let name = *symbol; let partial_proc = match procs.partial_procs.get(&name) { @@ -6535,7 +6536,8 @@ fn call_by_name_help<'a>( // If we've already specialized this one, no further work is needed. if procs .specialized - .contains_key(&(proc_name, top_level_layout)) + .keys() + .any(|x| x == &(proc_name, top_level_layout)) { debug_assert_eq!( argument_layouts.len(),