1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! 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 std::io::{self, Write};
use super::{OutlivesConstraint, RegionInferenceContext};

// 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, out: &mut dyn Write) -> io::Result<()> {
        writeln!(out, "| Free Region Mapping")?;

        for region in self.regions() {
            if self.definitions[region].is_universal {
                let classification = self.universal_regions.region_classification(region).unwrap();
                let outlived_by = self.universal_regions.regions_outlived_by(region);
                writeln!(
                    out,
                    "| {r:rw$} | {c:cw$} | {ob}",
                    r = format!("{:?}", region),
                    rw = REGION_WIDTH,
                    c = format!("{:?}", classification),
                    cw = 8, // "External" at most
                    ob = format!("{:?}", outlived_by)
                )?;
            }
        }

        writeln!(out, "|")?;
        writeln!(out, "| Inferred Region Values")?;
        for region in self.regions() {
            writeln!(
                out,
                "| {r:rw$} | {v}",
                r = format!("{:?}", region),
                rw = REGION_WIDTH,
                v = self.region_value_str(region),
            )?;
        }

        writeln!(out, "|")?;
        writeln!(out, "| Inference Constraints")?;
        self.for_each_constraint(&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,
        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.iter().collect();
        constraints.sort();
        for constraint in &constraints {
            let OutlivesConstraint {
                sup,
                sub,
                point,
                span,
                next: _,
            } = constraint;
            with_msg(&format!(
                "{:?}: {:?} @ {:?} due to {:?}",
                sup,
                sub,
                point,
                span
            ))?;
        }

        Ok(())
    }
}