|
9 | 9 | use prusti_rustc_interface::middle::mir; |
10 | 10 | use prusti_rustc_interface::hir::hir_id::HirId; |
11 | 11 | use prusti_rustc_interface::hir::def_id::{DefId, LocalDefId}; |
12 | | -use prusti_rustc_interface::middle::ty::{self, Binder, BoundConstness, ImplPolarity, TraitPredicate, TraitRef, TyCtxt}; |
| 12 | +use prusti_rustc_interface::middle::ty::{self, Binder, BoundConstness, ImplPolarity, TraitPredicate, TraitRef, TyCtxt, TypeSuperFoldable}; |
13 | 13 | use prusti_rustc_interface::middle::ty::subst::{Subst, SubstsRef}; |
14 | 14 | use prusti_rustc_interface::trait_selection::infer::{InferCtxtExt, TyCtxtInferExt}; |
15 | 15 | use prusti_rustc_interface::trait_selection::traits::{ImplSource, Obligation, ObligationCause, SelectionContext}; |
@@ -55,6 +55,11 @@ struct CachedBody<'tcx> { |
55 | 55 | monomorphised_bodies: HashMap<SubstsRef<'tcx>, Rc<mir::Body<'tcx>>>, |
56 | 56 | /// Cached borrowck information. |
57 | 57 | borrowck_facts: Rc<BorrowckFacts>, |
| 58 | + /// Copies of the MIR body with the given substs applied, called from the |
| 59 | + /// given caller. This also allows for associated types to be correctly |
| 60 | + /// normalised. |
| 61 | + /// TODO: merge more nicely with monomorphised_bodies? |
| 62 | + monomorphised_bodies_with_caller: HashMap<(SubstsRef<'tcx>, LocalDefId), Rc<mir::Body<'tcx>>>, |
58 | 63 | } |
59 | 64 |
|
60 | 65 | struct CachedExternalBody<'tcx> { |
@@ -303,12 +308,56 @@ impl<'tcx> Environment<'tcx> { |
303 | 308 | base_body: Rc::new(body), |
304 | 309 | monomorphised_bodies: HashMap::new(), |
305 | 310 | borrowck_facts: Rc::new(facts), |
| 311 | + monomorphised_bodies_with_caller: HashMap::new(), |
306 | 312 | } |
307 | 313 | }); |
308 | 314 | body |
309 | 315 | .monomorphised_bodies |
310 | 316 | .entry(substs) |
311 | | - .or_insert_with(|| ty::EarlyBinder(body.base_body.clone()).subst(self.tcx, substs)) |
| 317 | + .or_insert_with(|| { |
| 318 | + let param_env = self.tcx.param_env(def_id); |
| 319 | + let substituted = ty::EarlyBinder(body.base_body.clone()).subst(self.tcx, substs); |
| 320 | + self.resolve_assoc_types(substituted.clone(), param_env) |
| 321 | + }) |
| 322 | + .clone() |
| 323 | + } |
| 324 | + |
| 325 | + pub fn local_mir_with_caller( |
| 326 | + &self, |
| 327 | + def_id: LocalDefId, |
| 328 | + caller_def_id: LocalDefId, |
| 329 | + substs: SubstsRef<'tcx>, |
| 330 | + ) -> Rc<mir::Body<'tcx>> { |
| 331 | + // TODO: duplication ... |
| 332 | + let mut bodies = self.bodies.borrow_mut(); |
| 333 | + let body = bodies.entry(def_id) |
| 334 | + .or_insert_with(|| { |
| 335 | + // SAFETY: This is safe because we are feeding in the same `tcx` |
| 336 | + // that was used to store the data. |
| 337 | + let body_with_facts = unsafe { |
| 338 | + self::mir_storage::retrieve_mir_body(self.tcx, def_id) |
| 339 | + }; |
| 340 | + let body = body_with_facts.body; |
| 341 | + let facts = BorrowckFacts { |
| 342 | + input_facts: RefCell::new(Some(body_with_facts.input_facts)), |
| 343 | + output_facts: body_with_facts.output_facts, |
| 344 | + location_table: RefCell::new(Some(body_with_facts.location_table)), |
| 345 | + }; |
| 346 | + |
| 347 | + CachedBody { |
| 348 | + base_body: Rc::new(body), |
| 349 | + monomorphised_bodies: HashMap::new(), |
| 350 | + borrowck_facts: Rc::new(facts), |
| 351 | + monomorphised_bodies_with_caller: HashMap::new(), |
| 352 | + } |
| 353 | + }); |
| 354 | + body |
| 355 | + .monomorphised_bodies_with_caller |
| 356 | + .entry((substs, caller_def_id)) |
| 357 | + .or_insert_with(|| { |
| 358 | + let param_env = self.tcx.param_env(caller_def_id); |
| 359 | + self.tcx.subst_and_normalize_erasing_regions(substs, param_env, body.base_body.clone()) |
| 360 | + }) |
312 | 361 | .clone() |
313 | 362 | } |
314 | 363 |
|
@@ -538,10 +587,35 @@ impl<'tcx> Environment<'tcx> { |
538 | 587 | // Normalize the type to account for associated types |
539 | 588 | let ty = self.resolve_assoc_types(ty, param_env); |
540 | 589 | let ty = self.tcx.erase_late_bound_regions(ty); |
| 590 | + |
| 591 | + // Associated type was not normalised but it might still have a |
| 592 | + // `Copy` bound declared on it. |
| 593 | + // TODO: implement this more generally in `type_implements_trait` and |
| 594 | + // `type_implements_trait_with_trait_substs`. |
| 595 | + if let ty::TyKind::Projection(proj) = ty.kind() { |
| 596 | + let item_bounds = self.tcx.bound_item_bounds(proj.item_def_id); |
| 597 | + if item_bounds.0.iter().any(|predicate| { |
| 598 | + if let ty::PredicateKind::Trait(ty::TraitPredicate { |
| 599 | + trait_ref: ty::TraitRef { def_id: trait_def_id, .. }, |
| 600 | + polarity: ty::ImplPolarity::Positive, |
| 601 | + .. |
| 602 | + }) = predicate.kind().skip_binder() { |
| 603 | + trait_def_id == self.tcx.lang_items() |
| 604 | + .copy_trait() |
| 605 | + .unwrap() |
| 606 | + } else { |
| 607 | + false |
| 608 | + } |
| 609 | + }) { |
| 610 | + return true; |
| 611 | + } |
| 612 | + } |
| 613 | + |
541 | 614 | ty.is_copy_modulo_regions(self.tcx.at(prusti_rustc_interface::span::DUMMY_SP), param_env) |
542 | 615 | } |
543 | 616 |
|
544 | 617 | /// Checks whether the given type implements the trait with the given DefId. |
| 618 | + /// The trait should have no type parameters. |
545 | 619 | pub fn type_implements_trait(&self, ty: ty::Ty<'tcx>, trait_def_id: DefId, param_env: ty::ParamEnv<'tcx>) -> bool { |
546 | 620 | self.type_implements_trait_with_trait_substs(ty, trait_def_id, ty::List::empty(), param_env) |
547 | 621 | } |
@@ -583,22 +657,51 @@ impl<'tcx> Environment<'tcx> { |
583 | 657 |
|
584 | 658 | /// Normalizes associated types in foldable types, |
585 | 659 | /// i.e. this resolves projection types ([ty::TyKind::Projection]s) |
586 | | - /// **Important:** Regions while be erased during this process |
587 | | - pub fn resolve_assoc_types<T: ty::TypeFoldable<'tcx> + std::fmt::Debug + Copy>(&self, normalizable: T, param_env: ty::ParamEnv<'tcx>) -> T { |
588 | | - let norm_res = self.tcx.try_normalize_erasing_regions( |
589 | | - param_env, |
590 | | - normalizable |
591 | | - ); |
| 660 | + pub fn resolve_assoc_types<T: ty::TypeFoldable<'tcx> + std::fmt::Debug>(&self, normalizable: T, param_env: ty::ParamEnv<'tcx>) -> T { |
| 661 | + struct Normalizer<'a, 'tcx> { |
| 662 | + tcx: &'a ty::TyCtxt<'tcx>, |
| 663 | + param_env: ty::ParamEnv<'tcx>, |
| 664 | + } |
| 665 | + impl<'a, 'tcx> ty::fold::TypeFolder<'tcx> for Normalizer<'a, 'tcx> { |
| 666 | + fn tcx(&self) -> ty::TyCtxt<'tcx> { |
| 667 | + *self.tcx |
| 668 | + } |
592 | 669 |
|
593 | | - match norm_res { |
594 | | - Ok(normalized) => { |
595 | | - debug!("Normalized {:?}: {:?}", normalizable, normalized); |
596 | | - normalized |
597 | | - }, |
598 | | - Err(err) => { |
599 | | - debug!("Error while resolving associated types for {:?}: {:?}", normalizable, err); |
600 | | - normalizable |
| 670 | + fn fold_mir_const(&mut self, c: mir::ConstantKind<'tcx>) -> mir::ConstantKind<'tcx> { |
| 671 | + // rustc by default panics when we execute this TypeFolder on a mir::* type, |
| 672 | + // but we want to resolve associated types when we retrieve a local mir::Body |
| 673 | + c |
| 674 | + } |
| 675 | + |
| 676 | + fn fold_ty(&mut self, ty: ty::Ty<'tcx>) -> ty::Ty<'tcx> { |
| 677 | + match ty.kind() { |
| 678 | + ty::TyKind::Projection(_) => { |
| 679 | + let normalized = self.tcx.infer_ctxt().enter(|infcx| { |
| 680 | + use prusti_rustc_interface::trait_selection::traits::{fully_normalize, FulfillmentContext}; |
| 681 | + |
| 682 | + let normalization_result = fully_normalize( |
| 683 | + &infcx, |
| 684 | + FulfillmentContext::new(), |
| 685 | + ObligationCause::dummy(), |
| 686 | + self.param_env, |
| 687 | + ty |
| 688 | + ); |
| 689 | + |
| 690 | + match normalization_result { |
| 691 | + Ok(res) => res, |
| 692 | + Err(errors) => { |
| 693 | + debug!("Error while resolving associated types: {:?}", errors); |
| 694 | + ty |
| 695 | + } |
| 696 | + } |
| 697 | + }); |
| 698 | + normalized.super_fold_with(self) |
| 699 | + } |
| 700 | + _ => ty.super_fold_with(self) |
| 701 | + } |
601 | 702 | } |
602 | 703 | } |
| 704 | + |
| 705 | + normalizable.fold_with(&mut Normalizer {tcx: &self.tcx, param_env}) |
603 | 706 | } |
604 | 707 | } |
0 commit comments