From 59dc2013e27adc5a251e81317331890d4015cdf0 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 23 Nov 2020 10:21:54 -0500 Subject: [PATCH] optimization: use a single DepthFirstSearch instead of hashsets Extend the `DepthFirstSearch` iterator so that it can be re-used and extended with add'l start nodes. Then replace the FxHashSets of nodes we were using in the fallback analysis with a single iterator. This way we won't re-walk portions of the graph that are reached more than once, and we also do less allocation etc. --- compiler/rustc_typeck/src/check/fallback.rs | 23 ++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_typeck/src/check/fallback.rs b/compiler/rustc_typeck/src/check/fallback.rs index fff771663e96..508cea2845a6 100644 --- a/compiler/rustc_typeck/src/check/fallback.rs +++ b/compiler/rustc_typeck/src/check/fallback.rs @@ -1,6 +1,9 @@ use crate::check::FnCtxt; use rustc_data_structures::{ - fx::FxHashMap, graph::vec_graph::VecGraph, graph::WithSuccessors, stable_set::FxHashSet, + fx::FxHashMap, + graph::WithSuccessors, + graph::{iterate::DepthFirstSearch, vec_graph::VecGraph}, + stable_set::FxHashSet, }; use rustc_middle::ty::{self, Ty}; @@ -280,7 +283,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> { // type variable. These will typically default to `!`, unless // we find later that they are *also* reachable from some // other type variable outside this set. - let mut roots_reachable_from_diverging = FxHashSet::default(); + let mut roots_reachable_from_diverging = DepthFirstSearch::new(&coercion_graph); let mut diverging_vids = vec![]; let mut non_diverging_vids = vec![]; for unsolved_vid in unsolved_vids { @@ -293,16 +296,21 @@ impl<'tcx> FnCtxt<'_, 'tcx> { ); if diverging_roots.contains(&root_vid) { diverging_vids.push(unsolved_vid); + roots_reachable_from_diverging.push_start_node(root_vid); + debug!( "calculate_diverging_fallback: root_vid={:?} reaches {:?}", root_vid, coercion_graph.depth_first_search(root_vid).collect::>() ); - roots_reachable_from_diverging.extend(coercion_graph.depth_first_search(root_vid)); + + // drain the iterator to visit all nodes reachable from this node + roots_reachable_from_diverging.complete_search(); } else { non_diverging_vids.push(unsolved_vid); } } + debug!( "calculate_diverging_fallback: roots_reachable_from_diverging={:?}", roots_reachable_from_diverging, @@ -312,13 +320,14 @@ impl<'tcx> FnCtxt<'_, 'tcx> { // diverging variable, and then compute the set reachable from // N0, which we call N. These are the *non-diverging* type // variables. (Note that this set consists of "root variables".) - let mut roots_reachable_from_non_diverging = FxHashSet::default(); + let mut roots_reachable_from_non_diverging = DepthFirstSearch::new(&coercion_graph); for &non_diverging_vid in &non_diverging_vids { let root_vid = self.infcx.root_var(non_diverging_vid); - if roots_reachable_from_diverging.contains(&root_vid) { + if roots_reachable_from_diverging.visited(root_vid) { continue; } - roots_reachable_from_non_diverging.extend(coercion_graph.depth_first_search(root_vid)); + roots_reachable_from_non_diverging.push_start_node(root_vid); + roots_reachable_from_non_diverging.complete_search(); } debug!( "calculate_diverging_fallback: roots_reachable_from_non_diverging={:?}", @@ -334,7 +343,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> { let root_vid = self.infcx.root_var(diverging_vid); let can_reach_non_diverging = coercion_graph .depth_first_search(root_vid) - .any(|n| roots_reachable_from_non_diverging.contains(&n)); + .any(|n| roots_reachable_from_non_diverging.visited(n)); if can_reach_non_diverging { debug!("fallback to (): {:?}", diverging_vid); diverging_fallback.insert(diverging_ty, self.tcx.types.unit);