use crate::borrow_check::location::{LocationIndex, LocationTable}; use crate::dataflow::indexes::{BorrowIndex, MovePathIndex}; use polonius_engine::AllFacts as PoloniusAllFacts; use polonius_engine::Atom; use rustc::mir::Local; use rustc::ty::{RegionVid, TyCtxt}; use rustc_index::vec::Idx; use std::error::Error; use std::fmt::Debug; use std::fs::{self, File}; use std::io::Write; use std::path::Path; crate type AllFacts = PoloniusAllFacts; crate trait AllFactsExt { /// Returns `true` if there is a need to gather `AllFacts` given the /// current `-Z` flags. fn enabled(tcx: TyCtxt<'_>) -> bool; fn write_to_dir( &self, dir: impl AsRef, location_table: &LocationTable, ) -> Result<(), Box>; } impl AllFactsExt for AllFacts { /// Return fn enabled(tcx: TyCtxt<'_>) -> bool { tcx.sess.opts.debugging_opts.nll_facts || tcx.sess.opts.debugging_opts.polonius } fn write_to_dir( &self, dir: impl AsRef, location_table: &LocationTable, ) -> Result<(), Box> { let dir: &Path = dir.as_ref(); fs::create_dir_all(dir)?; let wr = FactWriter { location_table, dir }; macro_rules! write_facts_to_path { ($wr:ident . write_facts_to_path($this:ident . [ $($field:ident,)* ])) => { $( $wr.write_facts_to_path( &$this.$field, &format!("{}.facts", stringify!($field)) )?; )* } } write_facts_to_path! { wr.write_facts_to_path(self.[ borrow_region, universal_region, cfg_edge, killed, outlives, invalidates, var_used, var_defined, var_drop_used, var_uses_region, var_drops_region, child, path_belongs_to_var, initialized_at, moved_out_at, path_accessed_at, ]) } Ok(()) } } impl Atom for BorrowIndex { fn index(self) -> usize { Idx::index(self) } } impl Atom for LocationIndex { fn index(self) -> usize { Idx::index(self) } } impl Atom for MovePathIndex { fn index(self) -> usize { Idx::index(self) } } struct FactWriter<'w> { location_table: &'w LocationTable, dir: &'w Path, } impl<'w> FactWriter<'w> { fn write_facts_to_path(&self, rows: &[T], file_name: &str) -> Result<(), Box> where T: FactRow, { let file = &self.dir.join(file_name); let mut file = File::create(file)?; for row in rows { row.write(&mut file, self.location_table)?; } Ok(()) } } trait FactRow { fn write(&self, out: &mut File, location_table: &LocationTable) -> Result<(), Box>; } impl FactRow for RegionVid { fn write(&self, out: &mut File, location_table: &LocationTable) -> Result<(), Box> { write_row(out, location_table, &[self]) } } impl FactRow for (A, B) where A: FactCell, B: FactCell, { fn write(&self, out: &mut File, location_table: &LocationTable) -> Result<(), Box> { write_row(out, location_table, &[&self.0, &self.1]) } } impl FactRow for (A, B, C) where A: FactCell, B: FactCell, C: FactCell, { fn write(&self, out: &mut File, location_table: &LocationTable) -> Result<(), Box> { write_row(out, location_table, &[&self.0, &self.1, &self.2]) } } impl FactRow for (A, B, C, D) where A: FactCell, B: FactCell, C: FactCell, D: FactCell, { fn write(&self, out: &mut File, location_table: &LocationTable) -> Result<(), Box> { write_row(out, location_table, &[&self.0, &self.1, &self.2, &self.3]) } } fn write_row( out: &mut dyn Write, location_table: &LocationTable, columns: &[&dyn FactCell], ) -> Result<(), Box> { for (index, c) in columns.iter().enumerate() { let tail = if index == columns.len() - 1 { "\n" } else { "\t" }; write!(out, "{:?}{}", c.to_string(location_table), tail)?; } Ok(()) } trait FactCell { fn to_string(&self, location_table: &LocationTable) -> String; } impl FactCell for A { default fn to_string(&self, _location_table: &LocationTable) -> String { format!("{:?}", self) } } impl FactCell for LocationIndex { fn to_string(&self, location_table: &LocationTable) -> String { format!("{:?}", location_table.to_location(*self)) } }