hash less

This commit is contained in:
Folkert 2021-10-29 21:28:11 +02:00
parent 05b5cd3429
commit d35686f3a8

View file

@ -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<Symbol, MutSet<SolvedType>>,
/// Not a bumpalo vec because bumpalo is not thread safe
pub specs: BumpMap<Symbol, std::vec::Vec<SolvedType>>,
_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<Symbol, MutMap<ProcLayout<'a>, PendingSpecialization<'a>>>,
specializations_for_host: BumpMap<Symbol, MutMap<ProcLayout<'a>, 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(),