]>
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 | ||
1b1a35ee | 169 | fn impl_provided_for(&self, auto_trait_id: TraitId<I>, app_ty: &ApplicationTy<I>) -> bool { |
3dfed10e | 170 | self.record(auto_trait_id); |
1b1a35ee XL |
171 | if let TypeName::Adt(adt_id) = app_ty.name { |
172 | self.record(adt_id); | |
173 | } | |
174 | self.ws.db().impl_provided_for(auto_trait_id, app_ty) | |
3dfed10e XL |
175 | } |
176 | ||
177 | fn well_known_trait_id( | |
178 | &self, | |
179 | well_known_trait: crate::rust_ir::WellKnownTrait, | |
180 | ) -> Option<TraitId<I>> { | |
181 | let trait_id = self.ws.db().well_known_trait_id(well_known_trait); | |
182 | trait_id.map(|id| self.record(id)); | |
183 | trait_id | |
184 | } | |
185 | ||
186 | fn program_clauses_for_env( | |
187 | &self, | |
188 | environment: &chalk_ir::Environment<I>, | |
189 | ) -> chalk_ir::ProgramClauses<I> { | |
190 | self.ws.db().program_clauses_for_env(environment) | |
191 | } | |
192 | ||
193 | fn interner(&self) -> &I { | |
194 | self.ws.db().interner() | |
195 | } | |
196 | ||
197 | fn trait_name(&self, trait_id: TraitId<I>) -> String { | |
198 | self.ws.db().trait_name(trait_id) | |
199 | } | |
200 | ||
201 | fn adt_name(&self, adt_id: AdtId<I>) -> String { | |
202 | self.ws.db().adt_name(adt_id) | |
203 | } | |
204 | ||
205 | fn assoc_type_name(&self, assoc_ty_id: AssocTypeId<I>) -> String { | |
206 | self.ws.db().assoc_type_name(assoc_ty_id) | |
207 | } | |
208 | ||
209 | fn opaque_type_name(&self, opaque_ty_id: OpaqueTyId<I>) -> String { | |
210 | self.ws.db().opaque_type_name(opaque_ty_id) | |
211 | } | |
212 | ||
213 | fn is_object_safe(&self, trait_id: TraitId<I>) -> bool { | |
214 | self.record(trait_id); | |
215 | self.ws.db().is_object_safe(trait_id) | |
216 | } | |
217 | ||
218 | fn fn_def_datum(&self, fn_def_id: chalk_ir::FnDefId<I>) -> Arc<FnDefDatum<I>> { | |
219 | self.record(fn_def_id); | |
220 | self.ws.db().fn_def_datum(fn_def_id) | |
221 | } | |
222 | ||
223 | fn fn_def_name(&self, fn_def_id: FnDefId<I>) -> String { | |
224 | self.ws.db().fn_def_name(fn_def_id) | |
225 | } | |
226 | ||
227 | fn closure_kind(&self, closure_id: ClosureId<I>, substs: &Substitution<I>) -> ClosureKind { | |
228 | // TODO: record closure IDs | |
229 | self.ws.db().closure_kind(closure_id, substs) | |
230 | } | |
231 | ||
232 | fn closure_inputs_and_output( | |
233 | &self, | |
234 | closure_id: ClosureId<I>, | |
235 | substs: &Substitution<I>, | |
236 | ) -> Binders<FnDefInputsAndOutputDatum<I>> { | |
237 | // TODO: record closure IDs | |
238 | self.ws.db().closure_inputs_and_output(closure_id, substs) | |
239 | } | |
240 | ||
241 | fn closure_upvars(&self, closure_id: ClosureId<I>, substs: &Substitution<I>) -> Binders<Ty<I>> { | |
242 | // TODO: record closure IDs | |
243 | self.ws.db().closure_upvars(closure_id, substs) | |
244 | } | |
245 | ||
246 | fn closure_fn_substitution( | |
247 | &self, | |
248 | closure_id: ClosureId<I>, | |
249 | substs: &Substitution<I>, | |
250 | ) -> Substitution<I> { | |
251 | // TODO: record closure IDs | |
252 | self.ws.db().closure_fn_substitution(closure_id, substs) | |
253 | } | |
254 | } | |
255 | ||
256 | /// Wraps a [`RustIrDatabase`], and, when dropped, writes out all used | |
257 | /// definition to the given file. | |
258 | /// | |
259 | /// Uses [`LoggingRustIrDatabase`] internally. | |
260 | /// | |
261 | /// Uses a separate type, `P`, for the database stored inside to account for | |
262 | /// `Arc` or wrapping other storage mediums. | |
263 | pub struct WriteOnDropRustIrDatabase<I, W, DB, P = DB> | |
264 | where | |
265 | I: Interner, | |
266 | W: Write, | |
267 | DB: RustIrDatabase<I>, | |
268 | P: Borrow<DB>, | |
269 | { | |
270 | db: LoggingRustIrDatabase<I, DB, P>, | |
271 | write: W, | |
272 | } | |
273 | ||
274 | impl<I, W, DB, P> fmt::Debug for WriteOnDropRustIrDatabase<I, W, DB, P> | |
275 | where | |
276 | I: Interner, | |
277 | W: Write, | |
278 | DB: RustIrDatabase<I>, | |
279 | P: Borrow<DB> + fmt::Debug, | |
280 | { | |
281 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | |
282 | f.debug_struct("WriteOnDropRustIrDatabase") | |
283 | .field("db", &self.db) | |
284 | .field("write", &"<opaque>") | |
285 | .finish() | |
286 | } | |
287 | } | |
288 | ||
289 | impl<I, W, DB, P> WriteOnDropRustIrDatabase<I, W, DB, P> | |
290 | where | |
291 | I: Interner, | |
292 | W: Write, | |
293 | DB: RustIrDatabase<I>, | |
294 | P: Borrow<DB>, | |
295 | { | |
296 | pub fn new(db: P, write: W) -> Self { | |
297 | WriteOnDropRustIrDatabase { | |
298 | db: LoggingRustIrDatabase::new(db), | |
299 | write, | |
300 | } | |
301 | } | |
302 | ||
303 | pub fn from_logging_db(db: LoggingRustIrDatabase<I, DB, P>, write: W) -> Self { | |
304 | WriteOnDropRustIrDatabase { db, write } | |
305 | } | |
306 | } | |
307 | ||
308 | impl<I, W, DB, P> Drop for WriteOnDropRustIrDatabase<I, W, DB, P> | |
309 | where | |
310 | I: Interner, | |
311 | W: Write, | |
312 | DB: RustIrDatabase<I>, | |
313 | P: Borrow<DB>, | |
314 | { | |
315 | fn drop(&mut self) { | |
316 | write!(self.write, "{}", self.db) | |
317 | .and_then(|_| self.write.flush()) | |
318 | .expect("expected to be able to write rust ir database"); | |
319 | } | |
320 | } | |
321 | ||
322 | impl<I, W, DB, P> RustIrDatabase<I> for WriteOnDropRustIrDatabase<I, W, DB, P> | |
323 | where | |
324 | I: Interner, | |
325 | W: Write, | |
326 | DB: RustIrDatabase<I>, | |
327 | P: Borrow<DB> + Debug, | |
328 | { | |
329 | fn custom_clauses(&self) -> Vec<chalk_ir::ProgramClause<I>> { | |
330 | self.db.custom_clauses() | |
331 | } | |
332 | ||
333 | fn associated_ty_data( | |
334 | &self, | |
335 | ty: chalk_ir::AssocTypeId<I>, | |
336 | ) -> Arc<crate::rust_ir::AssociatedTyDatum<I>> { | |
337 | self.db.associated_ty_data(ty) | |
338 | } | |
339 | ||
340 | fn trait_datum(&self, trait_id: TraitId<I>) -> Arc<TraitDatum<I>> { | |
341 | self.db.trait_datum(trait_id) | |
342 | } | |
343 | ||
344 | fn adt_datum(&self, adt_id: AdtId<I>) -> Arc<AdtDatum<I>> { | |
345 | self.db.adt_datum(adt_id) | |
346 | } | |
347 | ||
348 | fn adt_repr(&self, id: AdtId<I>) -> AdtRepr { | |
349 | self.db.adt_repr(id) | |
350 | } | |
351 | ||
352 | fn impl_datum(&self, impl_id: ImplId<I>) -> Arc<ImplDatum<I>> { | |
353 | self.db.impl_datum(impl_id) | |
354 | } | |
355 | ||
356 | fn associated_ty_value( | |
357 | &self, | |
358 | id: crate::rust_ir::AssociatedTyValueId<I>, | |
359 | ) -> Arc<crate::rust_ir::AssociatedTyValue<I>> { | |
360 | self.db.associated_ty_value(id) | |
361 | } | |
362 | ||
363 | fn opaque_ty_data(&self, id: OpaqueTyId<I>) -> Arc<OpaqueTyDatum<I>> { | |
364 | self.db.opaque_ty_data(id) | |
365 | } | |
366 | ||
367 | fn hidden_opaque_type(&self, id: OpaqueTyId<I>) -> Ty<I> { | |
368 | self.db.hidden_opaque_type(id) | |
369 | } | |
370 | ||
371 | fn impls_for_trait( | |
372 | &self, | |
373 | trait_id: TraitId<I>, | |
374 | parameters: &[chalk_ir::GenericArg<I>], | |
375 | binders: &CanonicalVarKinds<I>, | |
376 | ) -> Vec<ImplId<I>> { | |
377 | self.db.impls_for_trait(trait_id, parameters, binders) | |
378 | } | |
379 | ||
380 | fn local_impls_to_coherence_check(&self, trait_id: TraitId<I>) -> Vec<ImplId<I>> { | |
381 | self.db.local_impls_to_coherence_check(trait_id) | |
382 | } | |
383 | ||
1b1a35ee XL |
384 | fn impl_provided_for(&self, auto_trait_id: TraitId<I>, app_ty: &ApplicationTy<I>) -> bool { |
385 | self.db.impl_provided_for(auto_trait_id, app_ty) | |
3dfed10e XL |
386 | } |
387 | ||
388 | fn well_known_trait_id( | |
389 | &self, | |
390 | well_known_trait: crate::rust_ir::WellKnownTrait, | |
391 | ) -> Option<TraitId<I>> { | |
392 | self.db.well_known_trait_id(well_known_trait) | |
393 | } | |
394 | ||
395 | fn program_clauses_for_env( | |
396 | &self, | |
397 | environment: &chalk_ir::Environment<I>, | |
398 | ) -> chalk_ir::ProgramClauses<I> { | |
399 | self.db.program_clauses_for_env(environment) | |
400 | } | |
401 | ||
402 | fn interner(&self) -> &I { | |
403 | self.db.interner() | |
404 | } | |
405 | ||
406 | fn is_object_safe(&self, trait_id: TraitId<I>) -> bool { | |
407 | self.db.is_object_safe(trait_id) | |
408 | } | |
409 | ||
410 | fn trait_name(&self, trait_id: TraitId<I>) -> String { | |
411 | self.db.trait_name(trait_id) | |
412 | } | |
413 | ||
414 | fn adt_name(&self, adt_id: AdtId<I>) -> String { | |
415 | self.db.adt_name(adt_id) | |
416 | } | |
417 | ||
418 | fn assoc_type_name(&self, assoc_ty_id: AssocTypeId<I>) -> String { | |
419 | self.db.assoc_type_name(assoc_ty_id) | |
420 | } | |
421 | ||
422 | fn opaque_type_name(&self, opaque_ty_id: OpaqueTyId<I>) -> String { | |
423 | self.db.opaque_type_name(opaque_ty_id) | |
424 | } | |
425 | ||
426 | fn fn_def_datum(&self, fn_def_id: chalk_ir::FnDefId<I>) -> Arc<FnDefDatum<I>> { | |
427 | self.db.fn_def_datum(fn_def_id) | |
428 | } | |
429 | ||
430 | fn fn_def_name(&self, fn_def_id: FnDefId<I>) -> String { | |
431 | self.db.fn_def_name(fn_def_id) | |
432 | } | |
433 | ||
434 | fn closure_kind(&self, closure_id: ClosureId<I>, substs: &Substitution<I>) -> ClosureKind { | |
435 | // TODO: record closure IDs | |
436 | self.db.closure_kind(closure_id, substs) | |
437 | } | |
438 | ||
439 | fn closure_inputs_and_output( | |
440 | &self, | |
441 | closure_id: ClosureId<I>, | |
442 | substs: &Substitution<I>, | |
443 | ) -> Binders<FnDefInputsAndOutputDatum<I>> { | |
444 | self.db.closure_inputs_and_output(closure_id, substs) | |
445 | } | |
446 | ||
447 | fn closure_upvars(&self, closure_id: ClosureId<I>, substs: &Substitution<I>) -> Binders<Ty<I>> { | |
448 | self.db.closure_upvars(closure_id, substs) | |
449 | } | |
450 | ||
451 | fn closure_fn_substitution( | |
452 | &self, | |
453 | closure_id: ClosureId<I>, | |
454 | substs: &Substitution<I>, | |
455 | ) -> Substitution<I> { | |
456 | self.db.closure_fn_substitution(closure_id, substs) | |
457 | } | |
458 | } | |
459 | ||
460 | #[derive(Copy, Clone, PartialEq, Eq, Debug)] | |
461 | pub enum RecordedItemId<I: Interner> { | |
462 | Adt(AdtId<I>), | |
463 | Trait(TraitId<I>), | |
464 | Impl(ImplId<I>), | |
465 | OpaqueTy(OpaqueTyId<I>), | |
466 | FnDef(FnDefId<I>), | |
467 | } | |
468 | ||
469 | impl<I: Interner> From<AdtId<I>> for RecordedItemId<I> { | |
470 | fn from(v: AdtId<I>) -> Self { | |
471 | RecordedItemId::Adt(v) | |
472 | } | |
473 | } | |
474 | ||
475 | impl<I: Interner> From<TraitId<I>> for RecordedItemId<I> { | |
476 | fn from(v: TraitId<I>) -> Self { | |
477 | RecordedItemId::Trait(v) | |
478 | } | |
479 | } | |
480 | ||
481 | impl<I: Interner> From<ImplId<I>> for RecordedItemId<I> { | |
482 | fn from(v: ImplId<I>) -> Self { | |
483 | RecordedItemId::Impl(v) | |
484 | } | |
485 | } | |
486 | ||
487 | impl<I: Interner> From<OpaqueTyId<I>> for RecordedItemId<I> { | |
488 | fn from(v: OpaqueTyId<I>) -> Self { | |
489 | RecordedItemId::OpaqueTy(v) | |
490 | } | |
491 | } | |
492 | ||
493 | impl<I: Interner> From<FnDefId<I>> for RecordedItemId<I> { | |
494 | fn from(v: FnDefId<I>) -> Self { | |
495 | RecordedItemId::FnDef(v) | |
496 | } | |
497 | } | |
498 | ||
499 | /// Utility for implementing Ord for RecordedItemId. | |
500 | #[derive(PartialEq, Eq, PartialOrd, Ord)] | |
501 | enum OrderedItemId<'a, DefId, AdtId> { | |
502 | DefId(&'a DefId), | |
503 | AdtId(&'a AdtId), | |
504 | } | |
505 | ||
506 | impl<I: Interner> RecordedItemId<I> { | |
507 | /// Extract internal identifier. Allows for absolute ordering matching the | |
508 | /// order in which chalk saw things (and thus reproducing that order in | |
509 | /// printed programs) | |
510 | fn ordered_item_id(&self) -> OrderedItemId<'_, I::DefId, I::InternedAdtId> { | |
511 | match self { | |
512 | RecordedItemId::Trait(TraitId(x)) | |
513 | | RecordedItemId::Impl(ImplId(x)) | |
514 | | RecordedItemId::OpaqueTy(OpaqueTyId(x)) | |
515 | | RecordedItemId::FnDef(FnDefId(x)) => OrderedItemId::DefId(x), | |
516 | RecordedItemId::Adt(AdtId(x)) => OrderedItemId::AdtId(x), | |
517 | } | |
518 | } | |
519 | } | |
520 | ||
521 | impl<I: Interner> PartialOrd for RecordedItemId<I> { | |
522 | fn partial_cmp(&self, other: &Self) -> Option<Ordering> { | |
523 | Some(self.cmp(other)) | |
524 | } | |
525 | } | |
526 | ||
527 | impl<I: Interner> Ord for RecordedItemId<I> { | |
528 | fn cmp(&self, other: &Self) -> Ordering { | |
529 | self.ordered_item_id().cmp(&other.ordered_item_id()) | |
530 | } | |
531 | } |