From b85cba87e45b75010f138006f0f17c5883a452bc Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 23 Nov 2023 16:26:55 +1100 Subject: [PATCH 1/9] Use typedefs to clarify some impls. And insert some whitespace. --- compiler/rustc_mir_dataflow/src/framework/cursor.rs | 2 +- compiler/rustc_mir_dataflow/src/framework/engine.rs | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_mir_dataflow/src/framework/cursor.rs b/compiler/rustc_mir_dataflow/src/framework/cursor.rs index c9bce80853db9..5a77b2eff72ef 100644 --- a/compiler/rustc_mir_dataflow/src/framework/cursor.rs +++ b/compiler/rustc_mir_dataflow/src/framework/cursor.rs @@ -104,7 +104,7 @@ where } } -impl<'res, 'mir, 'tcx, A> ResultsCursor<'mir, 'tcx, A, ResultsCloned<'res, 'tcx, A>> +impl<'res, 'mir, 'tcx, A> ResultsClonedCursor<'res, 'mir, 'tcx, A> where A: Analysis<'tcx> + CloneAnalysis, { diff --git a/compiler/rustc_mir_dataflow/src/framework/engine.rs b/compiler/rustc_mir_dataflow/src/framework/engine.rs index ed82b1e8cdcf4..00a74b0d770dc 100644 --- a/compiler/rustc_mir_dataflow/src/framework/engine.rs +++ b/compiler/rustc_mir_dataflow/src/framework/engine.rs @@ -80,6 +80,7 @@ where visit_results(body, blocks.map(|(bb, _)| bb), self, vis) } } + impl<'tcx, A> Results<'tcx, A> where A: Analysis<'tcx>, @@ -92,6 +93,7 @@ where ResultsCursor::new(body, self) } } + impl<'tcx, A> Results<'tcx, A> where A: Analysis<'tcx> + CloneAnalysis, @@ -113,7 +115,8 @@ where self.clone_analysis().into_results_cursor(body) } } -impl<'res, 'tcx, A> Results<'tcx, A, &'res EntrySets<'tcx, A>> + +impl<'res, 'tcx, A> ResultsCloned<'res, 'tcx, A> where A: Analysis<'tcx> + CloneAnalysis, { From 389e2cc69a917ea7ddc40bef0c1bda0466b423db Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 23 Nov 2023 16:59:13 +1100 Subject: [PATCH 2/9] Remove some unused code relating to `ResultsCloned`. --- .../rustc_mir_dataflow/src/framework/cursor.rs | 13 +------------ .../rustc_mir_dataflow/src/framework/engine.rs | 14 -------------- .../src/impls/storage_liveness.rs | 12 ------------ compiler/rustc_mir_dataflow/src/lib.rs | 2 +- 4 files changed, 2 insertions(+), 39 deletions(-) diff --git a/compiler/rustc_mir_dataflow/src/framework/cursor.rs b/compiler/rustc_mir_dataflow/src/framework/cursor.rs index 5a77b2eff72ef..e27666d590bc3 100644 --- a/compiler/rustc_mir_dataflow/src/framework/cursor.rs +++ b/compiler/rustc_mir_dataflow/src/framework/cursor.rs @@ -1,6 +1,6 @@ //! Random access inspection of the results of a dataflow analysis. -use crate::{framework::BitSetExt, CloneAnalysis}; +use crate::framework::BitSetExt; use std::borrow::{Borrow, BorrowMut}; use std::cmp::Ordering; @@ -104,17 +104,6 @@ where } } -impl<'res, 'mir, 'tcx, A> ResultsClonedCursor<'res, 'mir, 'tcx, A> -where - A: Analysis<'tcx> + CloneAnalysis, -{ - /// Creates a new cursor over the same `Results`. Note that the cursor's position is *not* - /// copied. - pub fn new_cursor(&self) -> Self { - Self::new(self.body, self.results.reclone_analysis()) - } -} - impl<'mir, 'tcx, A, R> ResultsCursor<'mir, 'tcx, A, R> where A: Analysis<'tcx>, diff --git a/compiler/rustc_mir_dataflow/src/framework/engine.rs b/compiler/rustc_mir_dataflow/src/framework/engine.rs index 00a74b0d770dc..78b5700823303 100644 --- a/compiler/rustc_mir_dataflow/src/framework/engine.rs +++ b/compiler/rustc_mir_dataflow/src/framework/engine.rs @@ -116,20 +116,6 @@ where } } -impl<'res, 'tcx, A> ResultsCloned<'res, 'tcx, A> -where - A: Analysis<'tcx> + CloneAnalysis, -{ - /// Creates a new `Results` type with a cloned `Analysis` and borrowed entry sets. - pub fn reclone_analysis(&self) -> Self { - Results { - analysis: self.analysis.clone_analysis(), - entry_sets: self.entry_sets, - _marker: PhantomData, - } - } -} - /// A solver for dataflow problems. pub struct Engine<'mir, 'tcx, A> where diff --git a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs index 5a58e3af8be1a..7f6668fe27cad 100644 --- a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs +++ b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs @@ -18,12 +18,6 @@ impl<'a> MaybeStorageLive<'a> { } } -impl crate::CloneAnalysis for MaybeStorageLive<'_> { - fn clone_analysis(&self) -> Self { - self.clone() - } -} - impl<'tcx, 'a> crate::AnalysisDomain<'tcx> for MaybeStorageLive<'a> { type Domain = BitSet; @@ -173,12 +167,6 @@ impl<'res, 'mir, 'tcx> MaybeRequiresStorage<'res, 'mir, 'tcx> { } } -impl crate::CloneAnalysis for MaybeRequiresStorage<'_, '_, '_> { - fn clone_analysis(&self) -> Self { - Self { borrowed_locals: self.borrowed_locals.new_cursor() } - } -} - impl<'tcx> crate::AnalysisDomain<'tcx> for MaybeRequiresStorage<'_, '_, 'tcx> { type Domain = BitSet; diff --git a/compiler/rustc_mir_dataflow/src/lib.rs b/compiler/rustc_mir_dataflow/src/lib.rs index d218f033d62d0..abe9dd45ea1eb 100644 --- a/compiler/rustc_mir_dataflow/src/lib.rs +++ b/compiler/rustc_mir_dataflow/src/lib.rs @@ -23,7 +23,7 @@ pub use self::framework::{ fmt, lattice, visit_results, Analysis, AnalysisDomain, Direction, GenKill, GenKillAnalysis, JoinSemiLattice, MaybeReachable, Results, ResultsCursor, ResultsVisitable, ResultsVisitor, }; -use self::framework::{Backward, CloneAnalysis, ResultsClonedCursor, SwitchIntEdgeEffects}; +use self::framework::{Backward, ResultsClonedCursor, SwitchIntEdgeEffects}; use self::move_paths::MoveData; pub mod debuginfo; From d957c4718377b8cb0dacc58cdbaa5a3fe82c53cc Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 23 Nov 2023 17:17:52 +1100 Subject: [PATCH 3/9] Remove `CloneAnalysis`. It's only implemented for analyses that implement `Copy`, which means it's basically a complicated synonym for `Copy`. So this commit removes it and uses `Copy` directly. (That direct use will be removed in a later commit.) --- .../src/framework/engine.rs | 19 +++++-------------- .../rustc_mir_dataflow/src/framework/mod.rs | 15 --------------- 2 files changed, 5 insertions(+), 29 deletions(-) diff --git a/compiler/rustc_mir_dataflow/src/framework/engine.rs b/compiler/rustc_mir_dataflow/src/framework/engine.rs index 78b5700823303..442b1facfc67e 100644 --- a/compiler/rustc_mir_dataflow/src/framework/engine.rs +++ b/compiler/rustc_mir_dataflow/src/framework/engine.rs @@ -24,9 +24,8 @@ use rustc_span::symbol::{sym, Symbol}; use super::fmt::DebugWithContext; use super::graphviz; use super::{ - visit_results, Analysis, AnalysisDomain, CloneAnalysis, Direction, GenKill, GenKillAnalysis, - GenKillSet, JoinSemiLattice, ResultsClonedCursor, ResultsCursor, ResultsRefCursor, - ResultsVisitor, + visit_results, Analysis, AnalysisDomain, Direction, GenKill, GenKillAnalysis, GenKillSet, + JoinSemiLattice, ResultsClonedCursor, ResultsCursor, ResultsRefCursor, ResultsVisitor, }; pub type EntrySets<'tcx, A> = IndexVec>::Domain>; @@ -96,23 +95,15 @@ where impl<'tcx, A> Results<'tcx, A> where - A: Analysis<'tcx> + CloneAnalysis, + A: Analysis<'tcx> + Copy, { - /// Creates a new `Results` type with a cloned `Analysis` and borrowed entry sets. - pub fn clone_analysis(&self) -> ResultsCloned<'_, 'tcx, A> { - Results { - analysis: self.analysis.clone_analysis(), - entry_sets: &self.entry_sets, - _marker: PhantomData, - } - } - /// Creates a `ResultsCursor` that can inspect these `Results`. pub fn cloned_results_cursor<'mir>( &self, body: &'mir mir::Body<'tcx>, ) -> ResultsClonedCursor<'_, 'mir, 'tcx, A> { - self.clone_analysis().into_results_cursor(body) + Results { analysis: self.analysis, entry_sets: &self.entry_sets, _marker: PhantomData } + .into_results_cursor(body) } } diff --git a/compiler/rustc_mir_dataflow/src/framework/mod.rs b/compiler/rustc_mir_dataflow/src/framework/mod.rs index a5ae1edf221cb..36c02e329e307 100644 --- a/compiler/rustc_mir_dataflow/src/framework/mod.rs +++ b/compiler/rustc_mir_dataflow/src/framework/mod.rs @@ -246,21 +246,6 @@ pub trait Analysis<'tcx>: AnalysisDomain<'tcx> { } } -/// Defines an `Analysis` which can be cloned for use in multiple `ResultsCursor`s or -/// `ResultsVisitor`s. Note this need not be a full clone, only enough of one to be used with a new -/// `ResultsCursor` or `ResultsVisitor` -pub trait CloneAnalysis { - fn clone_analysis(&self) -> Self; -} -impl<'tcx, A> CloneAnalysis for A -where - A: Analysis<'tcx> + Copy, -{ - fn clone_analysis(&self) -> Self { - *self - } -} - /// A gen/kill dataflow problem. /// /// Each method in this trait has a corresponding one in `Analysis`. However, these methods only From 3dea72aa1bf0ed5e5ccd36e8ee6c1c97976e5d25 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 23 Nov 2023 17:59:54 +1100 Subject: [PATCH 4/9] Remove one use of `as_results_cursor`. It's currently used because `requires_storage_results` is used in two locations: once with a cursor, and once later on without a cursor. The non-consuming `as_results_cursor` is used for the first location. But we can instead use the consuming `into_results_cursor` and then use `into_results` to extract the `Results` from the finished-with cursor for use at the second location. --- compiler/rustc_mir_transform/src/coroutine.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs index 1cb1a9886a09d..8d9555c63cf7f 100644 --- a/compiler/rustc_mir_transform/src/coroutine.rs +++ b/compiler/rustc_mir_transform/src/coroutine.rs @@ -684,11 +684,11 @@ fn locals_live_across_suspend_points<'tcx>( // Calculate the MIR locals that we actually need to keep storage around // for. - let mut requires_storage_results = + let mut requires_storage_cursor = MaybeRequiresStorage::new(borrowed_locals_results.cloned_results_cursor(body)) .into_engine(tcx, body) - .iterate_to_fixpoint(); - let mut requires_storage_cursor = requires_storage_results.as_results_cursor(body); + .iterate_to_fixpoint() + .into_results_cursor(body); // Calculate the liveness of MIR locals ignoring borrows. let mut liveness = MaybeLiveLocals @@ -764,7 +764,7 @@ fn locals_live_across_suspend_points<'tcx>( body, &saved_locals, always_live_locals.clone(), - requires_storage_results, + requires_storage_cursor.into_results(), ); LivenessInfo { From cf82b410f91082bce79bb70d5d94633f946a3b77 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 23 Nov 2023 18:19:43 +1100 Subject: [PATCH 5/9] Remove another use of `as_results_cursor`. The new code is a little clunky, but I couldn't see how to make it better. --- .../src/framework/engine.rs | 56 +++++++++++-------- .../src/framework/graphviz.rs | 45 +++++++++------ compiler/rustc_mir_dataflow/src/lib.rs | 1 + 3 files changed, 62 insertions(+), 40 deletions(-) diff --git a/compiler/rustc_mir_dataflow/src/framework/engine.rs b/compiler/rustc_mir_dataflow/src/framework/engine.rs index 442b1facfc67e..90fc91d012391 100644 --- a/compiler/rustc_mir_dataflow/src/framework/engine.rs +++ b/compiler/rustc_mir_dataflow/src/framework/engine.rs @@ -271,29 +271,31 @@ where ); } - let mut results = Results { analysis, entry_sets, _marker: PhantomData }; + let results = Results { analysis, entry_sets, _marker: PhantomData }; if tcx.sess.opts.unstable_opts.dump_mir_dataflow { - let res = write_graphviz_results(tcx, body, &mut results, pass_name); + let (res, results) = write_graphviz_results(tcx, body, results, pass_name); if let Err(e) = res { error!("Failed to write graphviz dataflow results: {}", e); } + results + } else { + results } - - results } } // Graphviz /// Writes a DOT file containing the results of a dataflow analysis if the user requested it via -/// `rustc_mir` attributes and `-Z dump-mir-dataflow`. +/// `rustc_mir` attributes and `-Z dump-mir-dataflow`. The `Result` in and the `Results` out are +/// the same. fn write_graphviz_results<'tcx, A>( tcx: TyCtxt<'tcx>, body: &mir::Body<'tcx>, - results: &mut Results<'tcx, A>, + results: Results<'tcx, A>, pass_name: Option<&'static str>, -) -> std::io::Result<()> +) -> (std::io::Result<()>, Results<'tcx, A>) where A: Analysis<'tcx>, A::Domain: DebugWithContext, @@ -304,23 +306,30 @@ where let def_id = body.source.def_id(); let Ok(attrs) = RustcMirAttrs::parse(tcx, def_id) else { // Invalid `rustc_mir` attrs are reported in `RustcMirAttrs::parse` - return Ok(()); + return (Ok(()), results); }; - let mut file = match attrs.output_path(A::NAME) { - Some(path) => { - debug!("printing dataflow results for {:?} to {}", def_id, path.display()); - if let Some(parent) = path.parent() { - fs::create_dir_all(parent)?; + let file = try { + match attrs.output_path(A::NAME) { + Some(path) => { + debug!("printing dataflow results for {:?} to {}", def_id, path.display()); + if let Some(parent) = path.parent() { + fs::create_dir_all(parent)?; + } + let f = fs::File::create(&path)?; + io::BufWriter::new(f) } - io::BufWriter::new(fs::File::create(&path)?) - } - None if dump_enabled(tcx, A::NAME, def_id) => { - create_dump_file(tcx, ".dot", false, A::NAME, &pass_name.unwrap_or("-----"), body)? - } + None if dump_enabled(tcx, A::NAME, def_id) => { + create_dump_file(tcx, ".dot", false, A::NAME, &pass_name.unwrap_or("-----"), body)? + } - _ => return Ok(()), + _ => return (Ok(()), results), + } + }; + let mut file = match file { + Ok(f) => f, + Err(e) => return (Err(e), results), }; let style = match attrs.formatter { @@ -336,11 +345,14 @@ where if tcx.sess.opts.unstable_opts.graphviz_dark_mode { render_opts.push(dot::RenderOption::DarkTheme); } - with_no_trimmed_paths!(dot::render_opts(&graphviz, &mut buf, &render_opts)?); + let r = with_no_trimmed_paths!(dot::render_opts(&graphviz, &mut buf, &render_opts)); - file.write_all(&buf)?; + let lhs = try { + r?; + file.write_all(&buf)?; + }; - Ok(()) + (lhs, graphviz.into_results()) } #[derive(Default)] diff --git a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs index 832d1cba9a73b..fa16cac31686b 100644 --- a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs +++ b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs @@ -12,7 +12,7 @@ use rustc_middle::mir::graphviz_safe_def_name; use rustc_middle::mir::{self, BasicBlock, Body, Location}; use super::fmt::{DebugDiffWithAdapter, DebugWithAdapter, DebugWithContext}; -use super::{Analysis, CallReturnPlaces, Direction, Results, ResultsRefCursor, ResultsVisitor}; +use super::{Analysis, CallReturnPlaces, Direction, Results, ResultsCursor, ResultsVisitor}; #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub(crate) enum OutputStyle { @@ -29,27 +29,31 @@ impl OutputStyle { } } -pub(crate) struct Formatter<'res, 'mir, 'tcx, A> +pub(crate) struct Formatter<'mir, 'tcx, A> where A: Analysis<'tcx>, { body: &'mir Body<'tcx>, - results: RefCell<&'res mut Results<'tcx, A>>, + results: RefCell>>, style: OutputStyle, reachable: BitSet, } -impl<'res, 'mir, 'tcx, A> Formatter<'res, 'mir, 'tcx, A> +impl<'mir, 'tcx, A> Formatter<'mir, 'tcx, A> where A: Analysis<'tcx>, { pub(crate) fn new( body: &'mir Body<'tcx>, - results: &'res mut Results<'tcx, A>, + results: Results<'tcx, A>, style: OutputStyle, ) -> Self { let reachable = mir::traversal::reachable_as_bitset(body); - Formatter { body, results: results.into(), style, reachable } + Formatter { body, results: Some(results).into(), style, reachable } + } + + pub(crate) fn into_results(self) -> Results<'tcx, A> { + self.results.into_inner().unwrap() } } @@ -69,7 +73,7 @@ fn dataflow_successors(body: &Body<'_>, bb: BasicBlock) -> Vec { .collect() } -impl<'tcx, A> dot::Labeller<'_> for Formatter<'_, '_, 'tcx, A> +impl<'tcx, A> dot::Labeller<'_> for Formatter<'_, 'tcx, A> where A: Analysis<'tcx>, A::Domain: DebugWithContext, @@ -88,14 +92,19 @@ where fn node_label(&self, block: &Self::Node) -> dot::LabelText<'_> { let mut label = Vec::new(); - let mut results = self.results.borrow_mut(); - let mut fmt = BlockFormatter { - results: results.as_results_cursor(self.body), - style: self.style, - bg: Background::Light, - }; + self.results.replace_with(|results| { + // `Formatter::result` is a `RefCell>` so we can replace + // the value with `None`, move it into the results cursor, move it + // back out, and return it to the refcell wrapped in `Some`. + let mut fmt = BlockFormatter { + results: results.take().unwrap().into_results_cursor(self.body), + style: self.style, + bg: Background::Light, + }; - fmt.write_node_label(&mut label, *block).unwrap(); + fmt.write_node_label(&mut label, *block).unwrap(); + Some(fmt.results.into_results()) + }); dot::LabelText::html(String::from_utf8(label).unwrap()) } @@ -109,7 +118,7 @@ where } } -impl<'mir, 'tcx, A> dot::GraphWalk<'mir> for Formatter<'_, 'mir, 'tcx, A> +impl<'mir, 'tcx, A> dot::GraphWalk<'mir> for Formatter<'mir, 'tcx, A> where A: Analysis<'tcx>, { @@ -143,16 +152,16 @@ where } } -struct BlockFormatter<'res, 'mir, 'tcx, A> +struct BlockFormatter<'mir, 'tcx, A> where A: Analysis<'tcx>, { - results: ResultsRefCursor<'res, 'mir, 'tcx, A>, + results: ResultsCursor<'mir, 'tcx, A>, bg: Background, style: OutputStyle, } -impl<'res, 'mir, 'tcx, A> BlockFormatter<'res, 'mir, 'tcx, A> +impl<'mir, 'tcx, A> BlockFormatter<'mir, 'tcx, A> where A: Analysis<'tcx>, A::Domain: DebugWithContext, diff --git a/compiler/rustc_mir_dataflow/src/lib.rs b/compiler/rustc_mir_dataflow/src/lib.rs index abe9dd45ea1eb..accc13bf94def 100644 --- a/compiler/rustc_mir_dataflow/src/lib.rs +++ b/compiler/rustc_mir_dataflow/src/lib.rs @@ -4,6 +4,7 @@ #![feature(let_chains)] #![feature(min_specialization)] #![feature(stmt_expr_attributes)] +#![feature(try_blocks)] #![recursion_limit = "256"] #![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::diagnostic_outside_of_impl)] From 5f5263bfc82a199dfc1121022d855bb7545046ac Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 23 Nov 2023 18:50:25 +1100 Subject: [PATCH 6/9] Remove `ResultsRefCursor`. It's no longer used. --- .../rustc_mir_dataflow/src/framework/cursor.rs | 14 -------------- .../rustc_mir_dataflow/src/framework/engine.rs | 15 +-------------- compiler/rustc_mir_dataflow/src/framework/mod.rs | 2 +- 3 files changed, 2 insertions(+), 29 deletions(-) diff --git a/compiler/rustc_mir_dataflow/src/framework/cursor.rs b/compiler/rustc_mir_dataflow/src/framework/cursor.rs index e27666d590bc3..6033f33196699 100644 --- a/compiler/rustc_mir_dataflow/src/framework/cursor.rs +++ b/compiler/rustc_mir_dataflow/src/framework/cursor.rs @@ -39,17 +39,6 @@ where { type EntrySets = E; } -impl<'a, 'tcx, A, E> AnalysisResults<'tcx, A> for &'a mut Results<'tcx, A, E> -where - A: Analysis<'tcx>, - E: Borrow>, -{ - type EntrySets = E; -} - -/// A `ResultsCursor` that borrows the underlying `Results`. -pub type ResultsRefCursor<'res, 'mir, 'tcx, A> = - ResultsCursor<'mir, 'tcx, A, &'res mut Results<'tcx, A>>; /// A `ResultsCursor` which uses a cloned `Analysis` while borrowing the underlying `Results`. This /// allows multiple cursors over the same `Results`. @@ -62,9 +51,6 @@ pub type ResultsClonedCursor<'res, 'mir, 'tcx, A> = /// the same order as the `DIRECTION` of the analysis. In the worst case—when statements are /// visited in *reverse* order—performance will be quadratic in the number of statements in the /// block. The order in which basic blocks are inspected has no impact on performance. -/// -/// A `ResultsCursor` can either own (the default) or borrow the dataflow results it inspects. The -/// type of ownership is determined by `R` (see `ResultsRefCursor` above). pub struct ResultsCursor<'mir, 'tcx, A, R = Results<'tcx, A>> where A: Analysis<'tcx>, diff --git a/compiler/rustc_mir_dataflow/src/framework/engine.rs b/compiler/rustc_mir_dataflow/src/framework/engine.rs index 90fc91d012391..cb8bbf0bff4b4 100644 --- a/compiler/rustc_mir_dataflow/src/framework/engine.rs +++ b/compiler/rustc_mir_dataflow/src/framework/engine.rs @@ -25,7 +25,7 @@ use super::fmt::DebugWithContext; use super::graphviz; use super::{ visit_results, Analysis, AnalysisDomain, Direction, GenKill, GenKillAnalysis, GenKillSet, - JoinSemiLattice, ResultsClonedCursor, ResultsCursor, ResultsRefCursor, ResultsVisitor, + JoinSemiLattice, ResultsClonedCursor, ResultsCursor, ResultsVisitor, }; pub type EntrySets<'tcx, A> = IndexVec>::Domain>; @@ -80,19 +80,6 @@ where } } -impl<'tcx, A> Results<'tcx, A> -where - A: Analysis<'tcx>, -{ - /// Creates a `ResultsCursor` that can inspect these `Results`. - pub fn as_results_cursor<'a, 'mir>( - &'a mut self, - body: &'mir mir::Body<'tcx>, - ) -> ResultsRefCursor<'a, 'mir, 'tcx, A> { - ResultsCursor::new(body, self) - } -} - impl<'tcx, A> Results<'tcx, A> where A: Analysis<'tcx> + Copy, diff --git a/compiler/rustc_mir_dataflow/src/framework/mod.rs b/compiler/rustc_mir_dataflow/src/framework/mod.rs index 36c02e329e307..d732ea5d4ea48 100644 --- a/compiler/rustc_mir_dataflow/src/framework/mod.rs +++ b/compiler/rustc_mir_dataflow/src/framework/mod.rs @@ -45,7 +45,7 @@ pub mod graphviz; pub mod lattice; mod visitor; -pub use self::cursor::{ResultsClonedCursor, ResultsCursor, ResultsRefCursor}; +pub use self::cursor::{ResultsClonedCursor, ResultsCursor}; pub use self::direction::{Backward, Direction, Forward}; pub use self::engine::{Engine, EntrySets, Results, ResultsCloned}; pub use self::lattice::{JoinSemiLattice, MaybeReachable}; From 500e55ba8c07d0e2a4dce4e51ad79dac21c94d6f Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 24 Nov 2023 11:14:00 +1100 Subject: [PATCH 7/9] Remove uses of `ResultsClonedCursor`. By just cloning the entire `Results` in the one place where `ResultsClonedCursor` was used. This is extra allocations but the performance effect is negligible. --- .../src/framework/engine.rs | 1 + .../src/impls/storage_liveness.rs | 25 +++++++++---------- compiler/rustc_mir_dataflow/src/lib.rs | 2 +- compiler/rustc_mir_transform/src/coroutine.rs | 6 ++--- 4 files changed, 17 insertions(+), 17 deletions(-) diff --git a/compiler/rustc_mir_dataflow/src/framework/engine.rs b/compiler/rustc_mir_dataflow/src/framework/engine.rs index cb8bbf0bff4b4..6be0cb06fc52b 100644 --- a/compiler/rustc_mir_dataflow/src/framework/engine.rs +++ b/compiler/rustc_mir_dataflow/src/framework/engine.rs @@ -31,6 +31,7 @@ use super::{ pub type EntrySets<'tcx, A> = IndexVec>::Domain>; /// A dataflow analysis that has converged to fixpoint. +#[derive(Clone)] pub struct Results<'tcx, A, E = EntrySets<'tcx, A>> where A: Analysis<'tcx>, diff --git a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs index 7f6668fe27cad..26fc903973f80 100644 --- a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs +++ b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs @@ -5,7 +5,7 @@ use rustc_middle::mir::*; use std::borrow::Cow; use super::MaybeBorrowedLocals; -use crate::{GenKill, ResultsClonedCursor}; +use crate::{GenKill, ResultsCursor}; #[derive(Clone)] pub struct MaybeStorageLive<'a> { @@ -152,22 +152,21 @@ impl<'tcx> crate::GenKillAnalysis<'tcx> for MaybeStorageDead { } } -type BorrowedLocalsResults<'res, 'mir, 'tcx> = - ResultsClonedCursor<'res, 'mir, 'tcx, MaybeBorrowedLocals>; +type BorrowedLocalsResults<'mir, 'tcx> = ResultsCursor<'mir, 'tcx, MaybeBorrowedLocals>; /// Dataflow analysis that determines whether each local requires storage at a /// given location; i.e. whether its storage can go away without being observed. -pub struct MaybeRequiresStorage<'res, 'mir, 'tcx> { - borrowed_locals: BorrowedLocalsResults<'res, 'mir, 'tcx>, +pub struct MaybeRequiresStorage<'mir, 'tcx> { + borrowed_locals: BorrowedLocalsResults<'mir, 'tcx>, } -impl<'res, 'mir, 'tcx> MaybeRequiresStorage<'res, 'mir, 'tcx> { - pub fn new(borrowed_locals: BorrowedLocalsResults<'res, 'mir, 'tcx>) -> Self { +impl<'mir, 'tcx> MaybeRequiresStorage<'mir, 'tcx> { + pub fn new(borrowed_locals: BorrowedLocalsResults<'mir, 'tcx>) -> Self { MaybeRequiresStorage { borrowed_locals } } } -impl<'tcx> crate::AnalysisDomain<'tcx> for MaybeRequiresStorage<'_, '_, 'tcx> { +impl<'tcx> crate::AnalysisDomain<'tcx> for MaybeRequiresStorage<'_, 'tcx> { type Domain = BitSet; const NAME: &'static str = "requires_storage"; @@ -186,7 +185,7 @@ impl<'tcx> crate::AnalysisDomain<'tcx> for MaybeRequiresStorage<'_, '_, 'tcx> { } } -impl<'tcx> crate::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'_, '_, 'tcx> { +impl<'tcx> crate::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'_, 'tcx> { type Idx = Local; fn domain_size(&self, body: &Body<'tcx>) -> usize { @@ -343,7 +342,7 @@ impl<'tcx> crate::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'_, '_, 'tcx> { } } -impl<'tcx> MaybeRequiresStorage<'_, '_, 'tcx> { +impl<'tcx> MaybeRequiresStorage<'_, 'tcx> { /// Kill locals that are fully moved and have not been borrowed. fn check_for_move(&mut self, trans: &mut impl GenKill, loc: Location) { let body = self.borrowed_locals.body(); @@ -352,12 +351,12 @@ impl<'tcx> MaybeRequiresStorage<'_, '_, 'tcx> { } } -struct MoveVisitor<'a, 'res, 'mir, 'tcx, T> { - borrowed_locals: &'a mut BorrowedLocalsResults<'res, 'mir, 'tcx>, +struct MoveVisitor<'a, 'mir, 'tcx, T> { + borrowed_locals: &'a mut BorrowedLocalsResults<'mir, 'tcx>, trans: &'a mut T, } -impl<'tcx, T> Visitor<'tcx> for MoveVisitor<'_, '_, '_, 'tcx, T> +impl<'tcx, T> Visitor<'tcx> for MoveVisitor<'_, '_, 'tcx, T> where T: GenKill, { diff --git a/compiler/rustc_mir_dataflow/src/lib.rs b/compiler/rustc_mir_dataflow/src/lib.rs index accc13bf94def..f0b21fd418472 100644 --- a/compiler/rustc_mir_dataflow/src/lib.rs +++ b/compiler/rustc_mir_dataflow/src/lib.rs @@ -24,7 +24,7 @@ pub use self::framework::{ fmt, lattice, visit_results, Analysis, AnalysisDomain, Direction, GenKill, GenKillAnalysis, JoinSemiLattice, MaybeReachable, Results, ResultsCursor, ResultsVisitable, ResultsVisitor, }; -use self::framework::{Backward, ResultsClonedCursor, SwitchIntEdgeEffects}; +use self::framework::{Backward, SwitchIntEdgeEffects}; use self::move_paths::MoveData; pub mod debuginfo; diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs index 8d9555c63cf7f..57becf097aec9 100644 --- a/compiler/rustc_mir_transform/src/coroutine.rs +++ b/compiler/rustc_mir_transform/src/coroutine.rs @@ -680,12 +680,12 @@ fn locals_live_across_suspend_points<'tcx>( let borrowed_locals_results = MaybeBorrowedLocals.into_engine(tcx, body).pass_name("coroutine").iterate_to_fixpoint(); - let mut borrowed_locals_cursor = borrowed_locals_results.cloned_results_cursor(body); + let mut borrowed_locals_cursor = borrowed_locals_results.clone().into_results_cursor(body); // Calculate the MIR locals that we actually need to keep storage around // for. let mut requires_storage_cursor = - MaybeRequiresStorage::new(borrowed_locals_results.cloned_results_cursor(body)) + MaybeRequiresStorage::new(borrowed_locals_results.into_results_cursor(body)) .into_engine(tcx, body) .iterate_to_fixpoint() .into_results_cursor(body); @@ -829,7 +829,7 @@ fn compute_storage_conflicts<'mir, 'tcx>( body: &'mir Body<'tcx>, saved_locals: &CoroutineSavedLocals, always_live_locals: BitSet, - mut requires_storage: rustc_mir_dataflow::Results<'tcx, MaybeRequiresStorage<'_, 'mir, 'tcx>>, + mut requires_storage: rustc_mir_dataflow::Results<'tcx, MaybeRequiresStorage<'mir, 'tcx>>, ) -> BitMatrix { assert_eq!(body.local_decls.len(), saved_locals.domain_size()); From 34aa36b266f4e94c73392353e5651797997f5845 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 24 Nov 2023 11:18:12 +1100 Subject: [PATCH 8/9] Remove `ResultsCloned` and `ResultsClonedCursor`. They're now unused. --- .../src/framework/cursor.rs | 7 +------ .../src/framework/engine.rs | 19 +------------------ .../rustc_mir_dataflow/src/framework/mod.rs | 4 ++-- 3 files changed, 4 insertions(+), 26 deletions(-) diff --git a/compiler/rustc_mir_dataflow/src/framework/cursor.rs b/compiler/rustc_mir_dataflow/src/framework/cursor.rs index 6033f33196699..8cc22717f70d8 100644 --- a/compiler/rustc_mir_dataflow/src/framework/cursor.rs +++ b/compiler/rustc_mir_dataflow/src/framework/cursor.rs @@ -9,7 +9,7 @@ use std::cmp::Ordering; use rustc_index::bit_set::BitSet; use rustc_middle::mir::{self, BasicBlock, Location}; -use super::{Analysis, Direction, Effect, EffectIndex, EntrySets, Results, ResultsCloned}; +use super::{Analysis, Direction, Effect, EffectIndex, EntrySets, Results}; // `AnalysisResults` is needed as an impl such as the following has an unconstrained type // parameter: @@ -40,11 +40,6 @@ where type EntrySets = E; } -/// A `ResultsCursor` which uses a cloned `Analysis` while borrowing the underlying `Results`. This -/// allows multiple cursors over the same `Results`. -pub type ResultsClonedCursor<'res, 'mir, 'tcx, A> = - ResultsCursor<'mir, 'tcx, A, ResultsCloned<'res, 'tcx, A>>; - /// Allows random access inspection of the results of a dataflow analysis. /// /// This cursor only has linear performance within a basic block when its statements are visited in diff --git a/compiler/rustc_mir_dataflow/src/framework/engine.rs b/compiler/rustc_mir_dataflow/src/framework/engine.rs index 6be0cb06fc52b..96a61c0d85508 100644 --- a/compiler/rustc_mir_dataflow/src/framework/engine.rs +++ b/compiler/rustc_mir_dataflow/src/framework/engine.rs @@ -25,7 +25,7 @@ use super::fmt::DebugWithContext; use super::graphviz; use super::{ visit_results, Analysis, AnalysisDomain, Direction, GenKill, GenKillAnalysis, GenKillSet, - JoinSemiLattice, ResultsClonedCursor, ResultsCursor, ResultsVisitor, + JoinSemiLattice, ResultsCursor, ResultsVisitor, }; pub type EntrySets<'tcx, A> = IndexVec>::Domain>; @@ -41,9 +41,6 @@ where pub(super) _marker: PhantomData<&'tcx ()>, } -/// `Results` type with a cloned `Analysis` and borrowed entry sets. -pub type ResultsCloned<'res, 'tcx, A> = Results<'tcx, A, &'res EntrySets<'tcx, A>>; - impl<'tcx, A, E> Results<'tcx, A, E> where A: Analysis<'tcx>, @@ -81,20 +78,6 @@ where } } -impl<'tcx, A> Results<'tcx, A> -where - A: Analysis<'tcx> + Copy, -{ - /// Creates a `ResultsCursor` that can inspect these `Results`. - pub fn cloned_results_cursor<'mir>( - &self, - body: &'mir mir::Body<'tcx>, - ) -> ResultsClonedCursor<'_, 'mir, 'tcx, A> { - Results { analysis: self.analysis, entry_sets: &self.entry_sets, _marker: PhantomData } - .into_results_cursor(body) - } -} - /// A solver for dataflow problems. pub struct Engine<'mir, 'tcx, A> where diff --git a/compiler/rustc_mir_dataflow/src/framework/mod.rs b/compiler/rustc_mir_dataflow/src/framework/mod.rs index d732ea5d4ea48..71dff5181cc5c 100644 --- a/compiler/rustc_mir_dataflow/src/framework/mod.rs +++ b/compiler/rustc_mir_dataflow/src/framework/mod.rs @@ -45,9 +45,9 @@ pub mod graphviz; pub mod lattice; mod visitor; -pub use self::cursor::{ResultsClonedCursor, ResultsCursor}; +pub use self::cursor::ResultsCursor; pub use self::direction::{Backward, Direction, Forward}; -pub use self::engine::{Engine, EntrySets, Results, ResultsCloned}; +pub use self::engine::{Engine, EntrySets, Results}; pub use self::lattice::{JoinSemiLattice, MaybeReachable}; pub use self::visitor::{visit_results, ResultsVisitable, ResultsVisitor}; From e966c894179969e22d51982ac85da58e8b8862bb Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 24 Nov 2023 11:28:21 +1100 Subject: [PATCH 9/9] Deparameterize `Results` and `ResultsCursor`. They both now only ever contain a `Results<'tcx, A>`. This means `AnalysisResults` can be removed, as can many `borrow`/`borrow_mut` calls. Also `Results` no longer needs a `PhantomData` because `'tcx` is now named by `entry_sets`. --- .../src/framework/cursor.rs | 71 +++++-------------- .../src/framework/engine.rs | 16 ++--- .../rustc_mir_dataflow/src/framework/mod.rs | 2 +- .../rustc_mir_dataflow/src/framework/tests.rs | 3 +- .../src/framework/visitor.rs | 7 +- 5 files changed, 27 insertions(+), 72 deletions(-) diff --git a/compiler/rustc_mir_dataflow/src/framework/cursor.rs b/compiler/rustc_mir_dataflow/src/framework/cursor.rs index 8cc22717f70d8..815f204594257 100644 --- a/compiler/rustc_mir_dataflow/src/framework/cursor.rs +++ b/compiler/rustc_mir_dataflow/src/framework/cursor.rs @@ -2,43 +2,13 @@ use crate::framework::BitSetExt; -use std::borrow::{Borrow, BorrowMut}; use std::cmp::Ordering; #[cfg(debug_assertions)] use rustc_index::bit_set::BitSet; use rustc_middle::mir::{self, BasicBlock, Location}; -use super::{Analysis, Direction, Effect, EffectIndex, EntrySets, Results}; - -// `AnalysisResults` is needed as an impl such as the following has an unconstrained type -// parameter: -// ``` -// impl<'tcx, A, E, R> ResultsCursor<'_, 'tcx, A, R> -// where -// A: Analysis<'tcx>, -// E: Borrow>, -// R: Results<'tcx, A, E>, -// {} -// ``` - -/// A type representing the analysis results consumed by a `ResultsCursor`. -pub trait AnalysisResults<'tcx, A>: BorrowMut> -where - A: Analysis<'tcx>, -{ - /// The type containing the entry sets for this `Results` type. - /// - /// Should be either `EntrySets<'tcx, A>` or `&EntrySets<'tcx, A>`. - type EntrySets: Borrow>; -} -impl<'tcx, A, E> AnalysisResults<'tcx, A> for Results<'tcx, A, E> -where - A: Analysis<'tcx>, - E: Borrow>, -{ - type EntrySets = E; -} +use super::{Analysis, Direction, Effect, EffectIndex, Results}; /// Allows random access inspection of the results of a dataflow analysis. /// @@ -46,12 +16,12 @@ where /// the same order as the `DIRECTION` of the analysis. In the worst case—when statements are /// visited in *reverse* order—performance will be quadratic in the number of statements in the /// block. The order in which basic blocks are inspected has no impact on performance. -pub struct ResultsCursor<'mir, 'tcx, A, R = Results<'tcx, A>> +pub struct ResultsCursor<'mir, 'tcx, A> where A: Analysis<'tcx>, { body: &'mir mir::Body<'tcx>, - results: R, + results: Results<'tcx, A>, state: A::Domain, pos: CursorPosition, @@ -65,7 +35,7 @@ where reachable_blocks: BitSet, } -impl<'mir, 'tcx, A, R> ResultsCursor<'mir, 'tcx, A, R> +impl<'mir, 'tcx, A> ResultsCursor<'mir, 'tcx, A> where A: Analysis<'tcx>, { @@ -80,19 +50,13 @@ where } /// Unwraps this cursor, returning the underlying `Results`. - pub fn into_results(self) -> R { + pub fn into_results(self) -> Results<'tcx, A> { self.results } -} -impl<'mir, 'tcx, A, R> ResultsCursor<'mir, 'tcx, A, R> -where - A: Analysis<'tcx>, - R: AnalysisResults<'tcx, A>, -{ /// Returns a new cursor that can inspect `results`. - pub fn new(body: &'mir mir::Body<'tcx>, results: R) -> Self { - let bottom_value = results.borrow().analysis.bottom_value(body); + pub fn new(body: &'mir mir::Body<'tcx>, results: Results<'tcx, A>) -> Self { + let bottom_value = results.analysis.bottom_value(body); ResultsCursor { body, results, @@ -117,23 +81,23 @@ where } /// Returns the underlying `Results`. - pub fn results(&self) -> &Results<'tcx, A, R::EntrySets> { - self.results.borrow() + pub fn results(&self) -> &Results<'tcx, A> { + &self.results } /// Returns the underlying `Results`. - pub fn mut_results(&mut self) -> &mut Results<'tcx, A, R::EntrySets> { - self.results.borrow_mut() + pub fn mut_results(&mut self) -> &mut Results<'tcx, A> { + &mut self.results } /// Returns the `Analysis` used to generate the underlying `Results`. pub fn analysis(&self) -> &A { - &self.results.borrow().analysis + &self.results.analysis } /// Returns the `Analysis` used to generate the underlying `Results`. pub fn mut_analysis(&mut self) -> &mut A { - &mut self.results.borrow_mut().analysis + &mut self.results.analysis } /// Resets the cursor to hold the entry set for the given basic block. @@ -145,7 +109,7 @@ where #[cfg(debug_assertions)] assert!(self.reachable_blocks.contains(block)); - self.state.clone_from(self.results.borrow().entry_set_for_block(block)); + self.state.clone_from(self.results.entry_set_for_block(block)); self.pos = CursorPosition::block_entry(block); self.state_needs_reset = false; } @@ -234,11 +198,10 @@ where ) }; - let analysis = &mut self.results.borrow_mut().analysis; let target_effect_index = effect.at_index(target.statement_index); A::Direction::apply_effects_in_range( - analysis, + &mut self.results.analysis, &mut self.state, target.block, block_data, @@ -254,12 +217,12 @@ where /// This can be used, e.g., to apply the call return effect directly to the cursor without /// creating an extra copy of the dataflow state. pub fn apply_custom_effect(&mut self, f: impl FnOnce(&mut A, &mut A::Domain)) { - f(&mut self.results.borrow_mut().analysis, &mut self.state); + f(&mut self.results.analysis, &mut self.state); self.state_needs_reset = true; } } -impl<'mir, 'tcx, A, R> ResultsCursor<'mir, 'tcx, A, R> +impl<'mir, 'tcx, A> ResultsCursor<'mir, 'tcx, A> where A: crate::GenKillAnalysis<'tcx>, A::Domain: BitSetExt, diff --git a/compiler/rustc_mir_dataflow/src/framework/engine.rs b/compiler/rustc_mir_dataflow/src/framework/engine.rs index 96a61c0d85508..784872c7ed7d8 100644 --- a/compiler/rustc_mir_dataflow/src/framework/engine.rs +++ b/compiler/rustc_mir_dataflow/src/framework/engine.rs @@ -5,9 +5,7 @@ use crate::errors::{ }; use crate::framework::BitSetExt; -use std::borrow::Borrow; use std::ffi::OsString; -use std::marker::PhantomData; use std::path::PathBuf; use rustc_ast as ast; @@ -32,31 +30,29 @@ pub type EntrySets<'tcx, A> = IndexVec>:: /// A dataflow analysis that has converged to fixpoint. #[derive(Clone)] -pub struct Results<'tcx, A, E = EntrySets<'tcx, A>> +pub struct Results<'tcx, A> where A: Analysis<'tcx>, { pub analysis: A, - pub(super) entry_sets: E, - pub(super) _marker: PhantomData<&'tcx ()>, + pub(super) entry_sets: EntrySets<'tcx, A>, } -impl<'tcx, A, E> Results<'tcx, A, E> +impl<'tcx, A> Results<'tcx, A> where A: Analysis<'tcx>, - E: Borrow>, { /// Creates a `ResultsCursor` that can inspect these `Results`. pub fn into_results_cursor<'mir>( self, body: &'mir mir::Body<'tcx>, - ) -> ResultsCursor<'mir, 'tcx, A, Self> { + ) -> ResultsCursor<'mir, 'tcx, A> { ResultsCursor::new(body, self) } /// Gets the dataflow state for the given block. pub fn entry_set_for_block(&self, block: BasicBlock) -> &A::Domain { - &self.entry_sets.borrow()[block] + &self.entry_sets[block] } pub fn visit_with<'mir>( @@ -242,7 +238,7 @@ where ); } - let results = Results { analysis, entry_sets, _marker: PhantomData }; + let results = Results { analysis, entry_sets }; if tcx.sess.opts.unstable_opts.dump_mir_dataflow { let (res, results) = write_graphviz_results(tcx, body, results, pass_name); diff --git a/compiler/rustc_mir_dataflow/src/framework/mod.rs b/compiler/rustc_mir_dataflow/src/framework/mod.rs index 71dff5181cc5c..b7dfbe0710da7 100644 --- a/compiler/rustc_mir_dataflow/src/framework/mod.rs +++ b/compiler/rustc_mir_dataflow/src/framework/mod.rs @@ -47,7 +47,7 @@ mod visitor; pub use self::cursor::ResultsCursor; pub use self::direction::{Backward, Direction, Forward}; -pub use self::engine::{Engine, EntrySets, Results}; +pub use self::engine::{Engine, Results}; pub use self::lattice::{JoinSemiLattice, MaybeReachable}; pub use self::visitor::{visit_results, ResultsVisitable, ResultsVisitor}; diff --git a/compiler/rustc_mir_dataflow/src/framework/tests.rs b/compiler/rustc_mir_dataflow/src/framework/tests.rs index 9cce5b26cd305..1da5057ff40f7 100644 --- a/compiler/rustc_mir_dataflow/src/framework/tests.rs +++ b/compiler/rustc_mir_dataflow/src/framework/tests.rs @@ -267,8 +267,7 @@ fn test_cursor(analysis: MockAnalysis<'_, D>) { let body = analysis.body; let mut cursor = - Results { entry_sets: analysis.mock_entry_sets(), analysis, _marker: PhantomData } - .into_results_cursor(body); + Results { entry_sets: analysis.mock_entry_sets(), analysis }.into_results_cursor(body); cursor.allow_unreachable(); diff --git a/compiler/rustc_mir_dataflow/src/framework/visitor.rs b/compiler/rustc_mir_dataflow/src/framework/visitor.rs index 3cfa7cc1c02fd..e3648bb40768f 100644 --- a/compiler/rustc_mir_dataflow/src/framework/visitor.rs +++ b/compiler/rustc_mir_dataflow/src/framework/visitor.rs @@ -1,8 +1,6 @@ -use std::borrow::Borrow; - use rustc_middle::mir::{self, BasicBlock, Location}; -use super::{Analysis, Direction, EntrySets, Results}; +use super::{Analysis, Direction, Results}; /// Calls the corresponding method in `ResultsVisitor` for every location in a `mir::Body` with the /// dataflow state at that location. @@ -143,10 +141,9 @@ pub trait ResultsVisitable<'tcx> { ); } -impl<'tcx, A, E> ResultsVisitable<'tcx> for Results<'tcx, A, E> +impl<'tcx, A> ResultsVisitable<'tcx> for Results<'tcx, A> where A: Analysis<'tcx>, - E: Borrow>, { type FlowState = A::Domain;