diff options
Diffstat (limited to 'compiler/rustc_borrowck/src/region_infer/dump_mir.rs')
-rw-r--r-- | compiler/rustc_borrowck/src/region_infer/dump_mir.rs | 93 |
1 files changed, 93 insertions, 0 deletions
diff --git a/compiler/rustc_borrowck/src/region_infer/dump_mir.rs b/compiler/rustc_borrowck/src/region_infer/dump_mir.rs new file mode 100644 index 000000000..fe5193102 --- /dev/null +++ b/compiler/rustc_borrowck/src/region_infer/dump_mir.rs @@ -0,0 +1,93 @@ +//! As part of generating the regions, if you enable `-Zdump-mir=nll`, +//! we will generate an annotated copy of the MIR that includes the +//! state of region inference. This code handles emitting the region +//! context internal state. + +use super::{OutlivesConstraint, RegionInferenceContext}; +use crate::type_check::Locations; +use rustc_infer::infer::NllRegionVariableOrigin; +use rustc_middle::ty::TyCtxt; +use std::io::{self, Write}; + +// Room for "'_#NNNNr" before things get misaligned. +// Easy enough to fix if this ever doesn't seem like +// enough. +const REGION_WIDTH: usize = 8; + +impl<'tcx> RegionInferenceContext<'tcx> { + /// Write out our state into the `.mir` files. + pub(crate) fn dump_mir(&self, tcx: TyCtxt<'tcx>, out: &mut dyn Write) -> io::Result<()> { + writeln!(out, "| Free Region Mapping")?; + + for region in self.regions() { + if let NllRegionVariableOrigin::FreeRegion = self.definitions[region].origin { + let classification = self.universal_regions.region_classification(region).unwrap(); + let outlived_by = self.universal_region_relations.regions_outlived_by(region); + writeln!( + out, + "| {r:rw$?} | {c:cw$?} | {ob:?}", + r = region, + rw = REGION_WIDTH, + c = classification, + cw = 8, // "External" at most + ob = outlived_by + )?; + } + } + + writeln!(out, "|")?; + writeln!(out, "| Inferred Region Values")?; + for region in self.regions() { + writeln!( + out, + "| {r:rw$?} | {ui:4?} | {v}", + r = region, + rw = REGION_WIDTH, + ui = self.region_universe(region), + v = self.region_value_str(region), + )?; + } + + writeln!(out, "|")?; + writeln!(out, "| Inference Constraints")?; + self.for_each_constraint(tcx, &mut |msg| writeln!(out, "| {}", msg))?; + + Ok(()) + } + + /// Debugging aid: Invokes the `with_msg` callback repeatedly with + /// our internal region constraints. These are dumped into the + /// -Zdump-mir file so that we can figure out why the region + /// inference resulted in the values that it did when debugging. + fn for_each_constraint( + &self, + tcx: TyCtxt<'tcx>, + with_msg: &mut dyn FnMut(&str) -> io::Result<()>, + ) -> io::Result<()> { + for region in self.definitions.indices() { + let value = self.liveness_constraints.region_value_str(region); + if value != "{}" { + with_msg(&format!("{:?} live at {}", region, value))?; + } + } + + let mut constraints: Vec<_> = self.constraints.outlives().iter().collect(); + constraints.sort_by_key(|c| (c.sup, c.sub)); + for constraint in &constraints { + let OutlivesConstraint { sup, sub, locations, category, span, variance_info: _ } = + constraint; + let (name, arg) = match locations { + Locations::All(span) => { + ("All", tcx.sess.source_map().span_to_embeddable_string(*span)) + } + Locations::Single(loc) => ("Single", format!("{:?}", loc)), + }; + with_msg(&format!( + "{:?}: {:?} due to {:?} at {}({}) ({:?}", + sup, sub, category, name, arg, span + ))?; + } + + Ok(()) + } +} |