]>
Commit | Line | Data |
---|---|---|
3dfed10e XL |
1 | //! Provides wrappers over `RustIrDatabase` which record used definitions and write |
2 | //! `.chalk` files containing those definitions. | |
3 | use std::{ | |
4 | borrow::Borrow, | |
5 | cmp::{Ord, Ordering}, | |
6 | collections::BTreeSet, | |
7 | fmt::{self, Debug, Display}, | |
8 | io::Write, | |
9 | marker::PhantomData, | |
10 | sync::Arc, | |
11 | sync::Mutex, | |
12 | }; | |
13 | ||
14 | use crate::rust_ir::*; | |
15 | use crate::{ | |
16 | display::{self, WriterState}, | |
17 | RustIrDatabase, | |
18 | }; | |
19 | use chalk_ir::{interner::Interner, *}; | |
20 | ||
21 | mod id_collector; | |
22 | ||
23 | /// Wraps another `RustIrDatabase` (`DB`) and records which definitions are | |
24 | /// used. | |
25 | /// | |
26 | /// A full .chalk file containing all used definitions can be recovered through | |
27 | /// `LoggingRustIrDatabase`'s `Display` implementation. | |
28 | /// | |
29 | /// Uses a separate type, `P`, for the database stored inside to account for | |
30 | /// `Arc` or wrapping other storage mediums. | |
31 | #[derive(Debug)] | |
32 | pub struct LoggingRustIrDatabase<I, DB, P = DB> | |
33 | where | |
34 | DB: RustIrDatabase<I>, | |
35 | P: Borrow<DB>, | |
36 | I: Interner, | |
37 | { | |
38 | ws: WriterState<I, DB, P>, | |
39 | def_ids: Mutex<BTreeSet<RecordedItemId<I>>>, | |
40 | _phantom: PhantomData<DB>, | |
41 | } | |
42 | ||
43 | impl<I, DB, P> LoggingRustIrDatabase<I, DB, P> | |
44 | where | |
45 | DB: RustIrDatabase<I>, | |
46 | P: Borrow<DB>, | |
47 | I: Interner, | |
48 | { | |
49 | pub fn new(db: P) -> Self { | |
50 | LoggingRustIrDatabase { | |
51 | ws: WriterState::new(db), | |
52 | def_ids: Default::default(), | |
53 | _phantom: PhantomData, | |
54 | } | |
55 | } | |
56 | } | |
57 | ||
58 | impl<I, DB, P> Display for LoggingRustIrDatabase<I, DB, P> | |
59 | where | |
60 | DB: RustIrDatabase<I>, | |
61 | P: Borrow<DB>, | |
62 | I: Interner, | |
63 | { | |
64 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | |
65 | let def_ids = self.def_ids.lock().unwrap(); | |
66 | let stub_ids = id_collector::collect_unrecorded_ids(self.ws.db(), &def_ids); | |
67 | display::write_stub_items(f, &self.ws, stub_ids)?; | |
68 | display::write_items(f, &self.ws, def_ids.iter().copied()) | |
69 | } | |
70 | } | |
71 | ||
72 | impl<I, DB, P> LoggingRustIrDatabase<I, DB, P> | |
73 | where | |
74 | DB: RustIrDatabase<I>, | |
75 | P: Borrow<DB>, | |
76 | I: Interner, | |
77 | { | |
78 | fn record(&self, id: impl Into<RecordedItemId<I>>) { | |
79 | self.def_ids.lock().unwrap().insert(id.into()); | |
80 | } | |
81 | ||
82 | fn record_all<T, U>(&self, ids: T) | |
83 | where | |
84 | T: IntoIterator<Item = U>, | |
85 | U: Into<RecordedItemId<I>>, | |
86 | { | |
87 | self.def_ids | |
88 | .lock() | |
89 | .unwrap() | |
90 | .extend(ids.into_iter().map(Into::into)); | |
91 | } | |
92 | } | |
93 | ||
94 | impl<I, DB, P> RustIrDatabase<I> for LoggingRustIrDatabase<I, DB, P> | |
95 | where | |
96 | DB: RustIrDatabase<I>, | |
97 | P: Borrow<DB> + Debug, | |
98 | I: Interner, | |
99 | { | |
100 | fn custom_clauses(&self) -> Vec<chalk_ir::ProgramClause<I>> { | |
101 | self.ws.db().custom_clauses() | |
102 | } | |
103 | ||
104 | fn associated_ty_data( | |
105 | &self, | |
106 | ty: chalk_ir::AssocTypeId<I>, | |
107 | ) -> Arc<crate::rust_ir::AssociatedTyDatum<I>> { | |
108 | let ty_datum = self.ws.db().associated_ty_data(ty); | |
109 | self.record(ty_datum.trait_id); | |
110 | ty_datum | |
111 | } | |
112 | ||
113 | fn trait_datum(&self, trait_id: TraitId<I>) -> Arc<TraitDatum<I>> { | |
114 | self.record(trait_id); | |
115 | self.ws.db().trait_datum(trait_id) | |
116 | } | |
117 | ||
118 | fn adt_datum(&self, adt_id: AdtId<I>) -> Arc<AdtDatum<I>> { | |
119 | self.record(adt_id); | |
120 | self.ws.db().adt_datum(adt_id) | |
121 | } | |
122 | ||
123 | fn adt_repr(&self, id: AdtId<I>) -> AdtRepr { | |
124 | self.record(id); | |
125 | self.ws.db().adt_repr(id) | |
126 | } | |
127 | ||
128 | fn impl_datum(&self, impl_id: ImplId<I>) -> Arc<ImplDatum<I>> { | |
129 | self.record(impl_id); | |
130 | self.ws.db().impl_datum(impl_id) | |
131 | } | |
132 | ||
133 | fn hidden_opaque_type(&self, id: OpaqueTyId<I>) -> Ty<I> { | |
134 | self.record(id); | |
135 | self.ws.db().hidden_opaque_type(id) | |
136 | } | |
137 | ||
138 | fn associated_ty_value( | |
139 | &self, | |
140 | id: crate::rust_ir::AssociatedTyValueId<I>, | |
141 | ) -> Arc<crate::rust_ir::AssociatedTyValue<I>> { | |
142 | let value = self.ws.db().associated_ty_value(id); | |
143 | self.record(value.impl_id); | |
144 | value | |
145 | } | |
146 | ||
147 | fn opaque_ty_data(&self, id: OpaqueTyId<I>) -> Arc<OpaqueTyDatum<I>> { | |
148 | self.record(id); | |
149 | self.ws.db().opaque_ty_data(id) | |
150 | } | |
151 | ||
152 | fn impls_for_trait( | |
153 | &self, | |
154 | trait_id: TraitId<I>, | |
155 | parameters: &[chalk_ir::GenericArg<I>], | |
156 | binders: &CanonicalVarKinds<I>, | |
157 | ) -> Vec<ImplId<I>> { | |
158 | self.record(trait_id); | |
159 | let impl_ids = self.ws.db().impls_for_trait(trait_id, parameters, binders); | |
160 | self.record_all(impl_ids.iter().copied()); | |
161 | impl_ids | |
162 | } | |
163 | ||
164 | fn local_impls_to_coherence_check(&self, trait_id: TraitId<I>) -> Vec<ImplId<I>> { | |
165 | self.record(trait_id); | |
166 | self.ws.db().local_impls_to_coherence_check(trait_id) | |
167 | } | |
168 | ||
169 | fn impl_provided_for(&self, auto_trait_id: TraitId<I>, adt_id: AdtId<I>) -> bool { | |
170 | self.record(auto_trait_id); | |
171 | self.record(adt_id); | |
172 | self.ws.db().impl_provided_for(auto_trait_id, adt_id) | |
173 | } | |
174 | ||
175 | fn well_known_trait_id( | |
176 | &self, | |
177 | well_known_trait: crate::rust_ir::WellKnownTrait, | |
178 | ) -> Option<TraitId<I>> { | |
179 | let trait_id = self.ws.db().well_known_trait_id(well_known_trait); | |
180 | trait_id.map(|id| self.record(id)); | |
181 | trait_id | |
182 | } | |
183 | ||
184 | fn program_clauses_for_env( | |
185 | &self, | |
186 | environment: &chalk_ir::Environment<I>, | |
187 | ) -> chalk_ir::ProgramClauses<I> { | |
188 | self.ws.db().program_clauses_for_env(environment) | |
189 | } | |
190 | ||
191 | fn interner(&self) -> &I { | |
192 | self.ws.db().interner() | |
193 | } | |
194 | ||
195 | fn trait_name(&self, trait_id: TraitId<I>) -> String { | |
196 | self.ws.db().trait_name(trait_id) | |
197 | } | |
198 | ||
199 | fn adt_name(&self, adt_id: AdtId<I>) -> String { | |
200 | self.ws.db().adt_name(adt_id) | |
201 | } | |
202 | ||
203 | fn assoc_type_name(&self, assoc_ty_id: AssocTypeId<I>) -> String { | |
204 | self.ws.db().assoc_type_name(assoc_ty_id) | |
205 | } | |
206 | ||
207 | fn opaque_type_name(&self, opaque_ty_id: OpaqueTyId<I>) -> String { | |
208 | self.ws.db().opaque_type_name(opaque_ty_id) | |
209 | } | |
210 | ||
211 | fn is_object_safe(&self, trait_id: TraitId<I>) -> bool { | |
212 | self.record(trait_id); | |
213 | self.ws.db().is_object_safe(trait_id) | |
214 | } | |
215 | ||
216 | fn fn_def_datum(&self, fn_def_id: chalk_ir::FnDefId<I>) -> Arc<FnDefDatum<I>> { | |
217 | self.record(fn_def_id); | |
218 | self.ws.db().fn_def_datum(fn_def_id) | |
219 | } | |
220 | ||
221 | fn fn_def_name(&self, fn_def_id: FnDefId<I>) -> String { | |
222 | self.ws.db().fn_def_name(fn_def_id) | |
223 | } | |
224 | ||
225 | fn closure_kind(&self, closure_id: ClosureId<I>, substs: &Substitution<I>) -> ClosureKind { | |
226 | // TODO: record closure IDs | |
227 | self.ws.db().closure_kind(closure_id, substs) | |
228 | } | |
229 | ||
230 | fn closure_inputs_and_output( | |
231 | &self, | |
232 | closure_id: ClosureId<I>, | |
233 | substs: &Substitution<I>, | |
234 | ) -> Binders<FnDefInputsAndOutputDatum<I>> { | |
235 | // TODO: record closure IDs | |
236 | self.ws.db().closure_inputs_and_output(closure_id, substs) | |
237 | } | |
238 | ||
239 | fn closure_upvars(&self, closure_id: ClosureId<I>, substs: &Substitution<I>) -> Binders<Ty<I>> { | |
240 | // TODO: record closure IDs | |
241 | self.ws.db().closure_upvars(closure_id, substs) | |
242 | } | |
243 | ||
244 | fn closure_fn_substitution( | |
245 | &self, | |
246 | closure_id: ClosureId<I>, | |
247 | substs: &Substitution<I>, | |
248 | ) -> Substitution<I> { | |
249 | // TODO: record closure IDs | |
250 | self.ws.db().closure_fn_substitution(closure_id, substs) | |
251 | } | |
252 | } | |
253 | ||
254 | /// Wraps a [`RustIrDatabase`], and, when dropped, writes out all used | |
255 | /// definition to the given file. | |
256 | /// | |
257 | /// Uses [`LoggingRustIrDatabase`] internally. | |
258 | /// | |
259 | /// Uses a separate type, `P`, for the database stored inside to account for | |
260 | /// `Arc` or wrapping other storage mediums. | |
261 | pub struct WriteOnDropRustIrDatabase<I, W, DB, P = DB> | |
262 | where | |
263 | I: Interner, | |
264 | W: Write, | |
265 | DB: RustIrDatabase<I>, | |
266 | P: Borrow<DB>, | |
267 | { | |
268 | db: LoggingRustIrDatabase<I, DB, P>, | |
269 | write: W, | |
270 | } | |
271 | ||
272 | impl<I, W, DB, P> fmt::Debug for WriteOnDropRustIrDatabase<I, W, DB, P> | |
273 | where | |
274 | I: Interner, | |
275 | W: Write, | |
276 | DB: RustIrDatabase<I>, | |
277 | P: Borrow<DB> + fmt::Debug, | |
278 | { | |
279 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | |
280 | f.debug_struct("WriteOnDropRustIrDatabase") | |
281 | .field("db", &self.db) | |
282 | .field("write", &"<opaque>") | |
283 | .finish() | |
284 | } | |
285 | } | |
286 | ||
287 | impl<I, W, DB, P> WriteOnDropRustIrDatabase<I, W, DB, P> | |
288 | where | |
289 | I: Interner, | |
290 | W: Write, | |
291 | DB: RustIrDatabase<I>, | |
292 | P: Borrow<DB>, | |
293 | { | |
294 | pub fn new(db: P, write: W) -> Self { | |
295 | WriteOnDropRustIrDatabase { | |
296 | db: LoggingRustIrDatabase::new(db), | |
297 | write, | |
298 | } | |
299 | } | |
300 | ||
301 | pub fn from_logging_db(db: LoggingRustIrDatabase<I, DB, P>, write: W) -> Self { | |
302 | WriteOnDropRustIrDatabase { db, write } | |
303 | } | |
304 | } | |
305 | ||
306 | impl<I, W, DB, P> Drop for WriteOnDropRustIrDatabase<I, W, DB, P> | |
307 | where | |
308 | I: Interner, | |
309 | W: Write, | |
310 | DB: RustIrDatabase<I>, | |
311 | P: Borrow<DB>, | |
312 | { | |
313 | fn drop(&mut self) { | |
314 | write!(self.write, "{}", self.db) | |
315 | .and_then(|_| self.write.flush()) | |
316 | .expect("expected to be able to write rust ir database"); | |
317 | } | |
318 | } | |
319 | ||
320 | impl<I, W, DB, P> RustIrDatabase<I> for WriteOnDropRustIrDatabase<I, W, DB, P> | |
321 | where | |
322 | I: Interner, | |
323 | W: Write, | |
324 | DB: RustIrDatabase<I>, | |
325 | P: Borrow<DB> + Debug, | |
326 | { | |
327 | fn custom_clauses(&self) -> Vec<chalk_ir::ProgramClause<I>> { | |
328 | self.db.custom_clauses() | |
329 | } | |
330 | ||
331 | fn associated_ty_data( | |
332 | &self, | |
333 | ty: chalk_ir::AssocTypeId<I>, | |
334 | ) -> Arc<crate::rust_ir::AssociatedTyDatum<I>> { | |
335 | self.db.associated_ty_data(ty) | |
336 | } | |
337 | ||
338 | fn trait_datum(&self, trait_id: TraitId<I>) -> Arc<TraitDatum<I>> { | |
339 | self.db.trait_datum(trait_id) | |
340 | } | |
341 | ||
342 | fn adt_datum(&self, adt_id: AdtId<I>) -> Arc<AdtDatum<I>> { | |
343 | self.db.adt_datum(adt_id) | |
344 | } | |
345 | ||
346 | fn adt_repr(&self, id: AdtId<I>) -> AdtRepr { | |
347 | self.db.adt_repr(id) | |
348 | } | |
349 | ||
350 | fn impl_datum(&self, impl_id: ImplId<I>) -> Arc<ImplDatum<I>> { | |
351 | self.db.impl_datum(impl_id) | |
352 | } | |
353 | ||
354 | fn associated_ty_value( | |
355 | &self, | |
356 | id: crate::rust_ir::AssociatedTyValueId<I>, | |
357 | ) -> Arc<crate::rust_ir::AssociatedTyValue<I>> { | |
358 | self.db.associated_ty_value(id) | |
359 | } | |
360 | ||
361 | fn opaque_ty_data(&self, id: OpaqueTyId<I>) -> Arc<OpaqueTyDatum<I>> { | |
362 | self.db.opaque_ty_data(id) | |
363 | } | |
364 | ||
365 | fn hidden_opaque_type(&self, id: OpaqueTyId<I>) -> Ty<I> { | |
366 | self.db.hidden_opaque_type(id) | |
367 | } | |
368 | ||
369 | fn impls_for_trait( | |
370 | &self, | |
371 | trait_id: TraitId<I>, | |
372 | parameters: &[chalk_ir::GenericArg<I>], | |
373 | binders: &CanonicalVarKinds<I>, | |
374 | ) -> Vec<ImplId<I>> { | |
375 | self.db.impls_for_trait(trait_id, parameters, binders) | |
376 | } | |
377 | ||
378 | fn local_impls_to_coherence_check(&self, trait_id: TraitId<I>) -> Vec<ImplId<I>> { | |
379 | self.db.local_impls_to_coherence_check(trait_id) | |
380 | } | |
381 | ||
382 | fn impl_provided_for(&self, auto_trait_id: TraitId<I>, adt_id: AdtId<I>) -> bool { | |
383 | self.db.impl_provided_for(auto_trait_id, adt_id) | |
384 | } | |
385 | ||
386 | fn well_known_trait_id( | |
387 | &self, | |
388 | well_known_trait: crate::rust_ir::WellKnownTrait, | |
389 | ) -> Option<TraitId<I>> { | |
390 | self.db.well_known_trait_id(well_known_trait) | |
391 | } | |
392 | ||
393 | fn program_clauses_for_env( | |
394 | &self, | |
395 | environment: &chalk_ir::Environment<I>, | |
396 | ) -> chalk_ir::ProgramClauses<I> { | |
397 | self.db.program_clauses_for_env(environment) | |
398 | } | |
399 | ||
400 | fn interner(&self) -> &I { | |
401 | self.db.interner() | |
402 | } | |
403 | ||
404 | fn is_object_safe(&self, trait_id: TraitId<I>) -> bool { | |
405 | self.db.is_object_safe(trait_id) | |
406 | } | |
407 | ||
408 | fn trait_name(&self, trait_id: TraitId<I>) -> String { | |
409 | self.db.trait_name(trait_id) | |
410 | } | |
411 | ||
412 | fn adt_name(&self, adt_id: AdtId<I>) -> String { | |
413 | self.db.adt_name(adt_id) | |
414 | } | |
415 | ||
416 | fn assoc_type_name(&self, assoc_ty_id: AssocTypeId<I>) -> String { | |
417 | self.db.assoc_type_name(assoc_ty_id) | |
418 | } | |
419 | ||
420 | fn opaque_type_name(&self, opaque_ty_id: OpaqueTyId<I>) -> String { | |
421 | self.db.opaque_type_name(opaque_ty_id) | |
422 | } | |
423 | ||
424 | fn fn_def_datum(&self, fn_def_id: chalk_ir::FnDefId<I>) -> Arc<FnDefDatum<I>> { | |
425 | self.db.fn_def_datum(fn_def_id) | |
426 | } | |
427 | ||
428 | fn fn_def_name(&self, fn_def_id: FnDefId<I>) -> String { | |
429 | self.db.fn_def_name(fn_def_id) | |
430 | } | |
431 | ||
432 | fn closure_kind(&self, closure_id: ClosureId<I>, substs: &Substitution<I>) -> ClosureKind { | |
433 | // TODO: record closure IDs | |
434 | self.db.closure_kind(closure_id, substs) | |
435 | } | |
436 | ||
437 | fn closure_inputs_and_output( | |
438 | &self, | |
439 | closure_id: ClosureId<I>, | |
440 | substs: &Substitution<I>, | |
441 | ) -> Binders<FnDefInputsAndOutputDatum<I>> { | |
442 | self.db.closure_inputs_and_output(closure_id, substs) | |
443 | } | |
444 | ||
445 | fn closure_upvars(&self, closure_id: ClosureId<I>, substs: &Substitution<I>) -> Binders<Ty<I>> { | |
446 | self.db.closure_upvars(closure_id, substs) | |
447 | } | |
448 | ||
449 | fn closure_fn_substitution( | |
450 | &self, | |
451 | closure_id: ClosureId<I>, | |
452 | substs: &Substitution<I>, | |
453 | ) -> Substitution<I> { | |
454 | self.db.closure_fn_substitution(closure_id, substs) | |
455 | } | |
456 | } | |
457 | ||
458 | #[derive(Copy, Clone, PartialEq, Eq, Debug)] | |
459 | pub enum RecordedItemId<I: Interner> { | |
460 | Adt(AdtId<I>), | |
461 | Trait(TraitId<I>), | |
462 | Impl(ImplId<I>), | |
463 | OpaqueTy(OpaqueTyId<I>), | |
464 | FnDef(FnDefId<I>), | |
465 | } | |
466 | ||
467 | impl<I: Interner> From<AdtId<I>> for RecordedItemId<I> { | |
468 | fn from(v: AdtId<I>) -> Self { | |
469 | RecordedItemId::Adt(v) | |
470 | } | |
471 | } | |
472 | ||
473 | impl<I: Interner> From<TraitId<I>> for RecordedItemId<I> { | |
474 | fn from(v: TraitId<I>) -> Self { | |
475 | RecordedItemId::Trait(v) | |
476 | } | |
477 | } | |
478 | ||
479 | impl<I: Interner> From<ImplId<I>> for RecordedItemId<I> { | |
480 | fn from(v: ImplId<I>) -> Self { | |
481 | RecordedItemId::Impl(v) | |
482 | } | |
483 | } | |
484 | ||
485 | impl<I: Interner> From<OpaqueTyId<I>> for RecordedItemId<I> { | |
486 | fn from(v: OpaqueTyId<I>) -> Self { | |
487 | RecordedItemId::OpaqueTy(v) | |
488 | } | |
489 | } | |
490 | ||
491 | impl<I: Interner> From<FnDefId<I>> for RecordedItemId<I> { | |
492 | fn from(v: FnDefId<I>) -> Self { | |
493 | RecordedItemId::FnDef(v) | |
494 | } | |
495 | } | |
496 | ||
497 | /// Utility for implementing Ord for RecordedItemId. | |
498 | #[derive(PartialEq, Eq, PartialOrd, Ord)] | |
499 | enum OrderedItemId<'a, DefId, AdtId> { | |
500 | DefId(&'a DefId), | |
501 | AdtId(&'a AdtId), | |
502 | } | |
503 | ||
504 | impl<I: Interner> RecordedItemId<I> { | |
505 | /// Extract internal identifier. Allows for absolute ordering matching the | |
506 | /// order in which chalk saw things (and thus reproducing that order in | |
507 | /// printed programs) | |
508 | fn ordered_item_id(&self) -> OrderedItemId<'_, I::DefId, I::InternedAdtId> { | |
509 | match self { | |
510 | RecordedItemId::Trait(TraitId(x)) | |
511 | | RecordedItemId::Impl(ImplId(x)) | |
512 | | RecordedItemId::OpaqueTy(OpaqueTyId(x)) | |
513 | | RecordedItemId::FnDef(FnDefId(x)) => OrderedItemId::DefId(x), | |
514 | RecordedItemId::Adt(AdtId(x)) => OrderedItemId::AdtId(x), | |
515 | } | |
516 | } | |
517 | } | |
518 | ||
519 | impl<I: Interner> PartialOrd for RecordedItemId<I> { | |
520 | fn partial_cmp(&self, other: &Self) -> Option<Ordering> { | |
521 | Some(self.cmp(other)) | |
522 | } | |
523 | } | |
524 | ||
525 | impl<I: Interner> Ord for RecordedItemId<I> { | |
526 | fn cmp(&self, other: &Self) -> Ordering { | |
527 | self.ordered_item_id().cmp(&other.ordered_item_id()) | |
528 | } | |
529 | } |