]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_borrowck/src/facts.rs
Rollup merge of #101765 - GuillaumeGomez:tyctxt-visibility-doc, r=jyn514
[rust.git] / compiler / rustc_borrowck / src / facts.rs
1 use crate::location::{LocationIndex, LocationTable};
2 use crate::BorrowIndex;
3 use polonius_engine::AllFacts as PoloniusFacts;
4 use polonius_engine::Atom;
5 use rustc_index::vec::Idx;
6 use rustc_middle::mir::Local;
7 use rustc_middle::ty::{RegionVid, TyCtxt};
8 use rustc_mir_dataflow::move_paths::MovePathIndex;
9 use std::error::Error;
10 use std::fmt::Debug;
11 use std::fs::{self, File};
12 use std::io::{BufWriter, Write};
13 use std::path::Path;
14
15 #[derive(Copy, Clone, Debug)]
16 pub struct RustcFacts;
17
18 impl polonius_engine::FactTypes for RustcFacts {
19     type Origin = RegionVid;
20     type Loan = BorrowIndex;
21     type Point = LocationIndex;
22     type Variable = Local;
23     type Path = MovePathIndex;
24 }
25
26 pub type AllFacts = PoloniusFacts<RustcFacts>;
27
28 pub(crate) trait AllFactsExt {
29     /// Returns `true` if there is a need to gather `AllFacts` given the
30     /// current `-Z` flags.
31     fn enabled(tcx: TyCtxt<'_>) -> bool;
32
33     fn write_to_dir(
34         &self,
35         dir: impl AsRef<Path>,
36         location_table: &LocationTable,
37     ) -> Result<(), Box<dyn Error>>;
38 }
39
40 impl AllFactsExt for AllFacts {
41     /// Return
42     fn enabled(tcx: TyCtxt<'_>) -> bool {
43         tcx.sess.opts.unstable_opts.nll_facts || tcx.sess.opts.unstable_opts.polonius
44     }
45
46     fn write_to_dir(
47         &self,
48         dir: impl AsRef<Path>,
49         location_table: &LocationTable,
50     ) -> Result<(), Box<dyn Error>> {
51         let dir: &Path = dir.as_ref();
52         fs::create_dir_all(dir)?;
53         let wr = FactWriter { location_table, dir };
54         macro_rules! write_facts_to_path {
55             ($wr:ident . write_facts_to_path($this:ident . [
56                 $($field:ident,)*
57             ])) => {
58                 $(
59                     $wr.write_facts_to_path(
60                         &$this.$field,
61                         &format!("{}.facts", stringify!($field))
62                     )?;
63                 )*
64             }
65         }
66         write_facts_to_path! {
67             wr.write_facts_to_path(self.[
68                 loan_issued_at,
69                 universal_region,
70                 cfg_edge,
71                 loan_killed_at,
72                 subset_base,
73                 loan_invalidated_at,
74                 var_used_at,
75                 var_defined_at,
76                 var_dropped_at,
77                 use_of_var_derefs_origin,
78                 drop_of_var_derefs_origin,
79                 child_path,
80                 path_is_var,
81                 path_assigned_at_base,
82                 path_moved_at_base,
83                 path_accessed_at_base,
84                 known_placeholder_subset,
85                 placeholder,
86             ])
87         }
88         Ok(())
89     }
90 }
91
92 impl Atom for BorrowIndex {
93     fn index(self) -> usize {
94         Idx::index(self)
95     }
96 }
97
98 impl Atom for LocationIndex {
99     fn index(self) -> usize {
100         Idx::index(self)
101     }
102 }
103
104 struct FactWriter<'w> {
105     location_table: &'w LocationTable,
106     dir: &'w Path,
107 }
108
109 impl<'w> FactWriter<'w> {
110     fn write_facts_to_path<T>(&self, rows: &[T], file_name: &str) -> Result<(), Box<dyn Error>>
111     where
112         T: FactRow,
113     {
114         let file = &self.dir.join(file_name);
115         let mut file = BufWriter::new(File::create(file)?);
116         for row in rows {
117             row.write(&mut file, self.location_table)?;
118         }
119         Ok(())
120     }
121 }
122
123 trait FactRow {
124     fn write(
125         &self,
126         out: &mut dyn Write,
127         location_table: &LocationTable,
128     ) -> Result<(), Box<dyn Error>>;
129 }
130
131 impl FactRow for RegionVid {
132     fn write(
133         &self,
134         out: &mut dyn Write,
135         location_table: &LocationTable,
136     ) -> Result<(), Box<dyn Error>> {
137         write_row(out, location_table, &[self])
138     }
139 }
140
141 impl<A, B> FactRow for (A, B)
142 where
143     A: FactCell,
144     B: FactCell,
145 {
146     fn write(
147         &self,
148         out: &mut dyn Write,
149         location_table: &LocationTable,
150     ) -> Result<(), Box<dyn Error>> {
151         write_row(out, location_table, &[&self.0, &self.1])
152     }
153 }
154
155 impl<A, B, C> FactRow for (A, B, C)
156 where
157     A: FactCell,
158     B: FactCell,
159     C: FactCell,
160 {
161     fn write(
162         &self,
163         out: &mut dyn Write,
164         location_table: &LocationTable,
165     ) -> Result<(), Box<dyn Error>> {
166         write_row(out, location_table, &[&self.0, &self.1, &self.2])
167     }
168 }
169
170 impl<A, B, C, D> FactRow for (A, B, C, D)
171 where
172     A: FactCell,
173     B: FactCell,
174     C: FactCell,
175     D: FactCell,
176 {
177     fn write(
178         &self,
179         out: &mut dyn Write,
180         location_table: &LocationTable,
181     ) -> Result<(), Box<dyn Error>> {
182         write_row(out, location_table, &[&self.0, &self.1, &self.2, &self.3])
183     }
184 }
185
186 fn write_row(
187     out: &mut dyn Write,
188     location_table: &LocationTable,
189     columns: &[&dyn FactCell],
190 ) -> Result<(), Box<dyn Error>> {
191     for (index, c) in columns.iter().enumerate() {
192         let tail = if index == columns.len() - 1 { "\n" } else { "\t" };
193         write!(out, "{:?}{}", c.to_string(location_table), tail)?;
194     }
195     Ok(())
196 }
197
198 trait FactCell {
199     fn to_string(&self, location_table: &LocationTable) -> String;
200 }
201
202 impl<A: Debug> FactCell for A {
203     default fn to_string(&self, _location_table: &LocationTable) -> String {
204         format!("{:?}", self)
205     }
206 }
207
208 impl FactCell for LocationIndex {
209     fn to_string(&self, location_table: &LocationTable) -> String {
210         format!("{:?}", location_table.to_location(*self))
211     }
212 }