special hash and dedup for SolvedType

This commit is contained in:
Folkert 2020-11-06 23:12:47 +01:00
parent 7faab5d857
commit 7a8e9fe343
4 changed files with 129 additions and 8 deletions

View file

@ -15,7 +15,7 @@ pub struct Symbol(u64);
// Set it to false if you want to see the raw ModuleId and IdentId ints, // Set it to false if you want to see the raw ModuleId and IdentId ints,
// but please set it back to true before checking in the result! // but please set it back to true before checking in the result!
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
const PRETTY_PRINT_DEBUG_SYMBOLS: bool = false; const PRETTY_PRINT_DEBUG_SYMBOLS: bool = true;
/// In Debug builds only, Symbol has a name() method that lets /// In Debug builds only, Symbol has a name() method that lets
/// you look up its name in a global intern table. This table is /// you look up its name in a global intern table. This table is

View file

@ -444,7 +444,7 @@ impl<'a> Procs<'a> {
// register the pending specialization, so this gets code genned later // register the pending specialization, so this gets code genned later
add_pending(pending_specializations, symbol, layout.clone(), pending); add_pending(pending_specializations, symbol, layout.clone(), pending);
debug_assert!(!self.partial_procs.contains_key(&symbol), "Procs was told to insert a value for symbol {:?}, but there was already an entry for that key! Procs should never attempt to insert duplicates.", symbol); debug_assert!(!self.partial_procs.contains_key(&symbol), "Procs was told to insert a value for symbol {:?}, but there was already an entry for that key! The same PartialProc should never be added twice", symbol);
self.partial_procs.insert( self.partial_procs.insert(
symbol, symbol,
@ -1336,10 +1336,26 @@ pub fn specialize_all<'a>(
mut procs: Procs<'a>, mut procs: Procs<'a>,
layout_cache: &mut LayoutCache<'a>, layout_cache: &mut LayoutCache<'a>,
) -> Procs<'a> { ) -> Procs<'a> {
dbg!(&procs.externals_others_need);
let it = procs.externals_others_need.specs.clone(); let it = procs.externals_others_need.specs.clone();
let it = it let it = it
.into_iter() .into_iter()
.map(|(symbol, solved_types)| solved_types.into_iter().map(move |s| (symbol, s))) .map(|(symbol, solved_types)| {
let mut as_vec: std::vec::Vec<_> = solved_types.into_iter().collect();
use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher};
let hash_the_thing = |x: &SolvedType| {
let mut hasher = DefaultHasher::new();
x.hash(&mut hasher);
(hasher.finish());
};
as_vec.sort_by_key(|x| hash_the_thing(x));
as_vec.dedup_by_key(|x| hash_the_thing(x));
as_vec.into_iter().map(move |s| (symbol, s))
})
.flatten(); .flatten();
for (name, solved_type) in it.into_iter() { for (name, solved_type) in it.into_iter() {
let partial_proc = match procs.partial_procs.get(&name) { let partial_proc = match procs.partial_procs.get(&name) {

View file

@ -5,6 +5,7 @@ use roc_collections::all::{ImMap, MutSet, SendMap};
use roc_module::ident::{Lowercase, TagName}; use roc_module::ident::{Lowercase, TagName};
use roc_module::symbol::Symbol; use roc_module::symbol::Symbol;
use roc_region::all::{Located, Region}; use roc_region::all::{Located, Region};
use std::hash::{Hash, Hasher};
/// A marker that a given Subs has been solved. /// A marker that a given Subs has been solved.
/// The only way to obtain a Solved<Subs> is by running the solver on it. /// The only way to obtain a Solved<Subs> is by running the solver on it.
@ -25,8 +26,114 @@ impl<T> Solved<T> {
} }
} }
impl Hash for SolvedType {
fn hash<H: Hasher>(&self, state: &mut H) {
hash_solved_type_help(self, &mut Vec::new(), state);
}
}
fn hash_solved_type_help<H: Hasher>(
solved_type: &SolvedType,
flex_vars: &mut Vec<VarId>,
state: &mut H,
) {
use SolvedType::*;
match solved_type {
Flex(var_id) => {
var_id_hash_help(*var_id, flex_vars, state);
}
Wildcard => "wildcard".hash(state),
EmptyRecord => "empty_record".hash(state),
EmptyTagUnion => "empty_tag_union".hash(state),
Error => "error".hash(state),
Func(arguments, closure, result) => {
for x in arguments {
hash_solved_type_help(x, flex_vars, state);
}
hash_solved_type_help(closure, flex_vars, state);
hash_solved_type_help(result, flex_vars, state);
}
Apply(name, arguments) => {
name.hash(state);
for x in arguments {
hash_solved_type_help(x, flex_vars, state);
}
}
Rigid(name) => name.hash(state),
Erroneous(problem) => problem.hash(state),
Boolean(solved_bool) => solved_bool.hash(state),
Record { fields, ext } => {
for (name, x) in fields {
name.hash(state);
"record_field".hash(state);
hash_solved_type_help(x.as_inner(), flex_vars, state);
}
hash_solved_type_help(ext, flex_vars, state);
}
TagUnion(tags, ext) => {
for (name, arguments) in tags {
name.hash(state);
for x in arguments {
hash_solved_type_help(x, flex_vars, state);
}
}
hash_solved_type_help(ext, flex_vars, state);
}
RecursiveTagUnion(rec, tags, ext) => {
var_id_hash_help(*rec, flex_vars, state);
for (name, arguments) in tags {
name.hash(state);
for x in arguments {
hash_solved_type_help(x, flex_vars, state);
}
}
hash_solved_type_help(ext, flex_vars, state);
}
Alias(name, arguments, actual) => {
name.hash(state);
for (name, x) in arguments {
name.hash(state);
hash_solved_type_help(x, flex_vars, state);
}
hash_solved_type_help(actual, flex_vars, state);
}
HostExposedAlias {
name,
arguments,
actual,
actual_var,
} => {
name.hash(state);
for (name, x) in arguments {
name.hash(state);
hash_solved_type_help(x, flex_vars, state);
}
hash_solved_type_help(actual, flex_vars, state);
var_id_hash_help(*actual_var, flex_vars, state);
}
}
}
fn var_id_hash_help<H: Hasher>(var_id: VarId, flex_vars: &mut Vec<VarId>, state: &mut H) {
let opt_index = flex_vars.iter().position(|x| *x == var_id);
match opt_index {
Some(index) => index.hash(state),
None => {
flex_vars.len().hash(state);
flex_vars.push(var_id);
}
}
}
/// This is a fully solved type, with no Variables remaining in it. /// This is a fully solved type, with no Variables remaining in it.
#[derive(Debug, Clone, PartialEq, Eq, Hash)] #[derive(Debug, Clone, PartialEq, Eq)]
pub enum SolvedType { pub enum SolvedType {
/// A function. The types of its arguments, then the type of its return value. /// A function. The types of its arguments, then the type of its return value.
Func(Vec<SolvedType>, Box<SolvedType>, Box<SolvedType>), Func(Vec<SolvedType>, Box<SolvedType>, Box<SolvedType>),

View file

@ -1,10 +1,8 @@
app Main provides [ main ] imports [ Effect ] app Main provides [ main ] imports [ Effect ]
main : Effect.Effect {} as Fx main : Effect.Effect {} as Fx
main = main =
d = Effect.putChar 68
e = Effect.putChar 69 e = Effect.putChar 69
d = Effect.putChar 68
e |> Effect.after \{} -> e e |> Effect.after \{} -> d