diff --git a/compiler/build/src/program.rs b/compiler/build/src/program.rs index 56b9ac8421..3e769c86bf 100644 --- a/compiler/build/src/program.rs +++ b/compiler/build/src/program.rs @@ -244,7 +244,7 @@ pub fn build( // Add all the Proc headers to the module. // We have to do this in a separate pass first, // because their bodies may reference each other. - for (symbol, layout, proc) in specializations.drain(..) { + for ((symbol, layout), proc) in specializations.drain() { let (fn_val, arg_basic_types) = build_proc_header(&env, &mut layout_ids, symbol, &layout, &proc); diff --git a/compiler/gen/tests/helpers/eval.rs b/compiler/gen/tests/helpers/eval.rs index a5ec5014bc..124cbfa47a 100644 --- a/compiler/gen/tests/helpers/eval.rs +++ b/compiler/gen/tests/helpers/eval.rs @@ -92,7 +92,7 @@ macro_rules! assert_llvm_evals_to { // Add all the Proc headers to the module. // We have to do this in a separate pass first, // because their bodies may reference each other. - for (symbol, layout, proc) in specializations.drain(..) { + for ((symbol, layout), proc) in specializations.drain() { let (fn_val, arg_basic_types) = build_proc_header(&env, &mut layout_ids, symbol, &layout, &proc); @@ -263,7 +263,7 @@ macro_rules! assert_opt_evals_to { // Add all the Proc headers to the module. // We have to do this in a separate pass first, // because their bodies may reference each other. - for (symbol, layout, proc) in specializations.drain(..) { + for ((symbol, layout), proc) in specializations.drain() { let (fn_val, arg_basic_types) = build_proc_header(&env, &mut layout_ids, symbol, &layout, &proc); diff --git a/compiler/mono/src/expr.rs b/compiler/mono/src/expr.rs index e9fbc82cc8..69b0b02dbe 100644 --- a/compiler/mono/src/expr.rs +++ b/compiler/mono/src/expr.rs @@ -1383,8 +1383,9 @@ pub fn specialize_all<'a>( env: &mut Env<'a, '_>, mut procs: Procs<'a>, layout_cache: &mut LayoutCache<'a>, -) -> (Vec<'a, (Symbol, Layout<'a>, Proc<'a>)>, MutSet) { - let mut answer = Vec::with_capacity_in(procs.pending_specializations.len(), env.arena); +) -> (MutMap<(Symbol, Layout<'a>), Proc<'a>>, MutSet) { + let mut answer = + HashMap::with_capacity_and_hasher(procs.pending_specializations.len(), default_hasher()); let mut runtime_errors = MutSet::default(); let mut is_finished = procs.pending_specializations.is_empty(); @@ -1409,19 +1410,23 @@ pub fn specialize_all<'a>( for (name, mut by_layout) in pending_specializations.drain() { for (layout, pending) in by_layout.drain() { - // TODO should pending_procs hold a Rc? - let partial_proc = procs - .partial_procs - .get(&name) - .unwrap_or_else(|| panic!("Could not find partial_proc for {:?}", name)) - .clone(); + // If we've already seen this (Symbol, Layout) combination before, + // don't try to specialize it again. If we do, we'll loop forever! + if !answer.contains_key(&(name, layout.clone())) { + // TODO should pending_procs hold a Rc? + let partial_proc = procs + .partial_procs + .get(&name) + .unwrap_or_else(|| panic!("Could not find partial_proc for {:?}", name)) + .clone(); - match specialize(env, &mut procs, name, layout_cache, pending, partial_proc) { - Ok(proc) => { - answer.push((name, layout, proc)); - } - Err(()) => { - runtime_errors.insert(name); + match specialize(env, &mut procs, name, layout_cache, pending, partial_proc) { + Ok(proc) => { + answer.insert((name, layout), proc); + } + Err(()) => { + runtime_errors.insert(name); + } } } }