rustc_borrowck/polonius/legacy/
facts.rs
1use std::error::Error;
2use std::fmt::Debug;
3use std::fs::{self, File};
4use std::io::Write;
5use std::path::Path;
6
7use polonius_engine::{AllFacts, Atom, Output};
8use rustc_macros::extension;
9use rustc_middle::mir::Local;
10use rustc_middle::ty::{RegionVid, TyCtxt};
11use rustc_mir_dataflow::move_paths::MovePathIndex;
12
13use super::{LocationIndex, PoloniusLocationTable};
14use crate::BorrowIndex;
15
16#[derive(Copy, Clone, Debug)]
17pub struct RustcFacts;
18
19pub type PoloniusOutput = Output<RustcFacts>;
20
21rustc_index::newtype_index! {
22 #[orderable]
24 #[debug_format = "'?{}"]
25 pub struct PoloniusRegionVid {}
26}
27
28impl polonius_engine::Atom for PoloniusRegionVid {
29 fn index(self) -> usize {
30 self.as_usize()
31 }
32}
33impl From<RegionVid> for PoloniusRegionVid {
34 fn from(value: RegionVid) -> Self {
35 Self::from_usize(value.as_usize())
36 }
37}
38impl From<PoloniusRegionVid> for RegionVid {
39 fn from(value: PoloniusRegionVid) -> Self {
40 Self::from_usize(value.as_usize())
41 }
42}
43
44impl polonius_engine::FactTypes for RustcFacts {
45 type Origin = PoloniusRegionVid;
46 type Loan = BorrowIndex;
47 type Point = LocationIndex;
48 type Variable = Local;
49 type Path = MovePathIndex;
50}
51
52pub type PoloniusFacts = AllFacts<RustcFacts>;
53
54#[extension(pub(crate) trait PoloniusFactsExt)]
55impl PoloniusFacts {
56 fn enabled(tcx: TyCtxt<'_>) -> bool {
59 tcx.sess.opts.unstable_opts.nll_facts
60 || tcx.sess.opts.unstable_opts.polonius.is_legacy_enabled()
61 }
62
63 fn write_to_dir(
64 &self,
65 dir: impl AsRef<Path>,
66 location_table: &PoloniusLocationTable,
67 ) -> Result<(), Box<dyn Error>> {
68 let dir: &Path = dir.as_ref();
69 fs::create_dir_all(dir)?;
70 let wr = FactWriter { location_table, dir };
71 macro_rules! write_facts_to_path {
72 ($wr:ident . write_facts_to_path($this:ident . [
73 $($field:ident,)*
74 ])) => {
75 $(
76 $wr.write_facts_to_path(
77 &$this.$field,
78 &format!("{}.facts", stringify!($field))
79 )?;
80 )*
81 }
82 }
83 write_facts_to_path! {
84 wr.write_facts_to_path(self.[
85 loan_issued_at,
86 universal_region,
87 cfg_edge,
88 loan_killed_at,
89 subset_base,
90 loan_invalidated_at,
91 var_used_at,
92 var_defined_at,
93 var_dropped_at,
94 use_of_var_derefs_origin,
95 drop_of_var_derefs_origin,
96 child_path,
97 path_is_var,
98 path_assigned_at_base,
99 path_moved_at_base,
100 path_accessed_at_base,
101 known_placeholder_subset,
102 placeholder,
103 ])
104 }
105 Ok(())
106 }
107}
108
109impl Atom for BorrowIndex {
110 fn index(self) -> usize {
111 self.as_usize()
112 }
113}
114
115impl Atom for LocationIndex {
116 fn index(self) -> usize {
117 self.as_usize()
118 }
119}
120
121struct FactWriter<'w> {
122 location_table: &'w PoloniusLocationTable,
123 dir: &'w Path,
124}
125
126impl<'w> FactWriter<'w> {
127 fn write_facts_to_path<T>(&self, rows: &[T], file_name: &str) -> Result<(), Box<dyn Error>>
128 where
129 T: FactRow,
130 {
131 let file = &self.dir.join(file_name);
132 let mut file = File::create_buffered(file)?;
133 for row in rows {
134 row.write(&mut file, self.location_table)?;
135 }
136 Ok(())
137 }
138}
139
140trait FactRow {
141 fn write(
142 &self,
143 out: &mut dyn Write,
144 location_table: &PoloniusLocationTable,
145 ) -> Result<(), Box<dyn Error>>;
146}
147
148impl FactRow for PoloniusRegionVid {
149 fn write(
150 &self,
151 out: &mut dyn Write,
152 location_table: &PoloniusLocationTable,
153 ) -> Result<(), Box<dyn Error>> {
154 write_row(out, location_table, &[self])
155 }
156}
157
158impl<A, B> FactRow for (A, B)
159where
160 A: FactCell,
161 B: FactCell,
162{
163 fn write(
164 &self,
165 out: &mut dyn Write,
166 location_table: &PoloniusLocationTable,
167 ) -> Result<(), Box<dyn Error>> {
168 write_row(out, location_table, &[&self.0, &self.1])
169 }
170}
171
172impl<A, B, C> FactRow for (A, B, C)
173where
174 A: FactCell,
175 B: FactCell,
176 C: FactCell,
177{
178 fn write(
179 &self,
180 out: &mut dyn Write,
181 location_table: &PoloniusLocationTable,
182 ) -> Result<(), Box<dyn Error>> {
183 write_row(out, location_table, &[&self.0, &self.1, &self.2])
184 }
185}
186
187impl<A, B, C, D> FactRow for (A, B, C, D)
188where
189 A: FactCell,
190 B: FactCell,
191 C: FactCell,
192 D: FactCell,
193{
194 fn write(
195 &self,
196 out: &mut dyn Write,
197 location_table: &PoloniusLocationTable,
198 ) -> Result<(), Box<dyn Error>> {
199 write_row(out, location_table, &[&self.0, &self.1, &self.2, &self.3])
200 }
201}
202
203fn write_row(
204 out: &mut dyn Write,
205 location_table: &PoloniusLocationTable,
206 columns: &[&dyn FactCell],
207) -> Result<(), Box<dyn Error>> {
208 for (index, c) in columns.iter().enumerate() {
209 let tail = if index == columns.len() - 1 { "\n" } else { "\t" };
210 write!(out, "{:?}{tail}", c.to_string(location_table))?;
211 }
212 Ok(())
213}
214
215trait FactCell {
216 fn to_string(&self, location_table: &PoloniusLocationTable) -> String;
217}
218
219impl FactCell for BorrowIndex {
220 fn to_string(&self, _location_table: &PoloniusLocationTable) -> String {
221 format!("{self:?}")
222 }
223}
224
225impl FactCell for Local {
226 fn to_string(&self, _location_table: &PoloniusLocationTable) -> String {
227 format!("{self:?}")
228 }
229}
230
231impl FactCell for MovePathIndex {
232 fn to_string(&self, _location_table: &PoloniusLocationTable) -> String {
233 format!("{self:?}")
234 }
235}
236
237impl FactCell for PoloniusRegionVid {
238 fn to_string(&self, _location_table: &PoloniusLocationTable) -> String {
239 format!("{self:?}")
240 }
241}
242
243impl FactCell for RegionVid {
244 fn to_string(&self, _location_table: &PoloniusLocationTable) -> String {
245 format!("{self:?}")
246 }
247}
248
249impl FactCell for LocationIndex {
250 fn to_string(&self, location_table: &PoloniusLocationTable) -> String {
251 format!("{:?}", location_table.to_rich_location(*self))
252 }
253}