|
69 | 69 | //! might later infer `?U` to something like `&'b u32`, which would
|
70 | 70 | //! imply that `'b: 'a`.
|
71 | 71 |
|
72 |
| -use hir::def_id::DefId; |
73 | 72 | use infer::outlives::env::RegionBoundPairs;
|
| 73 | +use infer::outlives::verify::VerifyBoundCx; |
74 | 74 | use infer::{self, GenericKind, InferCtxt, RegionObligation, SubregionOrigin, VerifyBound};
|
75 | 75 | use rustc_data_structures::fx::FxHashMap;
|
76 | 76 | use syntax::ast;
|
77 |
| -use traits::{self, ObligationCause}; |
| 77 | +use traits::ObligationCause; |
78 | 78 | use ty::outlives::Component;
|
79 |
| -use ty::subst::{Subst, Substs}; |
80 | 79 | use ty::{self, Region, Ty, TyCtxt, TypeFoldable};
|
81 | 80 |
|
82 | 81 | impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
|
@@ -244,9 +243,7 @@ where
|
244 | 243 | // of these fields.
|
245 | 244 | delegate: D,
|
246 | 245 | tcx: TyCtxt<'cx, 'gcx, 'tcx>,
|
247 |
| - region_bound_pairs: &'cx RegionBoundPairs<'tcx>, |
248 |
| - implicit_region_bound: Option<ty::Region<'tcx>>, |
249 |
| - param_env: ty::ParamEnv<'tcx>, |
| 246 | + verify_bound: VerifyBoundCx<'cx, 'gcx, 'tcx>, |
250 | 247 | }
|
251 | 248 |
|
252 | 249 | pub trait TypeOutlivesDelegate<'tcx> {
|
@@ -280,9 +277,12 @@ where
|
280 | 277 | Self {
|
281 | 278 | delegate,
|
282 | 279 | tcx,
|
283 |
| - region_bound_pairs, |
284 |
| - implicit_region_bound, |
285 |
| - param_env, |
| 280 | + verify_bound: VerifyBoundCx::new( |
| 281 | + tcx, |
| 282 | + region_bound_pairs, |
| 283 | + implicit_region_bound, |
| 284 | + param_env, |
| 285 | + ), |
286 | 286 | }
|
287 | 287 | }
|
288 | 288 |
|
@@ -357,8 +357,8 @@ where
|
357 | 357 | region, param_ty, origin
|
358 | 358 | );
|
359 | 359 |
|
360 |
| - let verify_bound = self.param_bound(param_ty); |
361 | 360 | let generic = GenericKind::Param(param_ty);
|
| 361 | + let verify_bound = self.verify_bound.generic_bound(generic); |
362 | 362 | self.delegate
|
363 | 363 | .push_verify(origin, generic, region, verify_bound);
|
364 | 364 | }
|
@@ -391,7 +391,7 @@ where
|
391 | 391 | // Compute the bounds we can derive from the environment or trait
|
392 | 392 | // definition. We know that the projection outlives all the
|
393 | 393 | // regions in this list.
|
394 |
| - let env_bounds = self.projection_declared_bounds(projection_ty); |
| 394 | + let env_bounds = self.verify_bound.projection_declared_bounds(projection_ty); |
395 | 395 |
|
396 | 396 | debug!("projection_must_outlive: env_bounds={:?}", env_bounds);
|
397 | 397 |
|
@@ -463,217 +463,11 @@ where
|
463 | 463 | // projection outlive; in some cases, this may add insufficient
|
464 | 464 | // edges into the inference graph, leading to inference failures
|
465 | 465 | // even though a satisfactory solution exists.
|
466 |
| - let verify_bound = self.projection_bound(env_bounds, projection_ty); |
467 | 466 | let generic = GenericKind::Projection(projection_ty);
|
| 467 | + let verify_bound = self.verify_bound.generic_bound(generic); |
468 | 468 | self.delegate
|
469 | 469 | .push_verify(origin, generic.clone(), region, verify_bound);
|
470 | 470 | }
|
471 |
| - |
472 |
| - fn type_bound(&self, ty: Ty<'tcx>) -> VerifyBound<'tcx> { |
473 |
| - match ty.sty { |
474 |
| - ty::Param(p) => self.param_bound(p), |
475 |
| - ty::Projection(data) => { |
476 |
| - let declared_bounds = self.projection_declared_bounds(data); |
477 |
| - self.projection_bound(declared_bounds, data) |
478 |
| - } |
479 |
| - _ => self.recursive_type_bound(ty), |
480 |
| - } |
481 |
| - } |
482 |
| - |
483 |
| - fn param_bound(&self, param_ty: ty::ParamTy) -> VerifyBound<'tcx> { |
484 |
| - debug!("param_bound(param_ty={:?})", param_ty); |
485 |
| - |
486 |
| - let mut param_bounds = self.declared_generic_bounds_from_env(GenericKind::Param(param_ty)); |
487 |
| - |
488 |
| - // Add in the default bound of fn body that applies to all in |
489 |
| - // scope type parameters: |
490 |
| - param_bounds.extend(self.implicit_region_bound); |
491 |
| - |
492 |
| - VerifyBound::AnyRegion(param_bounds) |
493 |
| - } |
494 |
| - |
495 |
| - fn projection_declared_bounds( |
496 |
| - &self, |
497 |
| - projection_ty: ty::ProjectionTy<'tcx>, |
498 |
| - ) -> Vec<ty::Region<'tcx>> { |
499 |
| - // First assemble bounds from where clauses and traits. |
500 |
| - |
501 |
| - let mut declared_bounds = |
502 |
| - self.declared_generic_bounds_from_env(GenericKind::Projection(projection_ty)); |
503 |
| - |
504 |
| - declared_bounds |
505 |
| - .extend_from_slice(&self.declared_projection_bounds_from_trait(projection_ty)); |
506 |
| - |
507 |
| - declared_bounds |
508 |
| - } |
509 |
| - |
510 |
| - fn projection_bound( |
511 |
| - &self, |
512 |
| - declared_bounds: Vec<ty::Region<'tcx>>, |
513 |
| - projection_ty: ty::ProjectionTy<'tcx>, |
514 |
| - ) -> VerifyBound<'tcx> { |
515 |
| - debug!( |
516 |
| - "projection_bound(declared_bounds={:?}, projection_ty={:?})", |
517 |
| - declared_bounds, projection_ty |
518 |
| - ); |
519 |
| - |
520 |
| - // see the extensive comment in projection_must_outlive |
521 |
| - let ty = self.tcx |
522 |
| - .mk_projection(projection_ty.item_def_id, projection_ty.substs); |
523 |
| - let recursive_bound = self.recursive_type_bound(ty); |
524 |
| - |
525 |
| - VerifyBound::AnyRegion(declared_bounds).or(recursive_bound) |
526 |
| - } |
527 |
| - |
528 |
| - fn recursive_type_bound(&self, ty: Ty<'tcx>) -> VerifyBound<'tcx> { |
529 |
| - let mut bounds = ty.walk_shallow() |
530 |
| - .map(|subty| self.type_bound(subty)) |
531 |
| - .collect::<Vec<_>>(); |
532 |
| - |
533 |
| - let mut regions = ty.regions(); |
534 |
| - regions.retain(|r| !r.is_late_bound()); // ignore late-bound regions |
535 |
| - bounds.push(VerifyBound::AllRegions(regions)); |
536 |
| - |
537 |
| - // remove bounds that must hold, since they are not interesting |
538 |
| - bounds.retain(|b| !b.must_hold()); |
539 |
| - |
540 |
| - if bounds.len() == 1 { |
541 |
| - bounds.pop().unwrap() |
542 |
| - } else { |
543 |
| - VerifyBound::AllBounds(bounds) |
544 |
| - } |
545 |
| - } |
546 |
| - |
547 |
| - fn declared_generic_bounds_from_env( |
548 |
| - &self, |
549 |
| - generic: GenericKind<'tcx>, |
550 |
| - ) -> Vec<ty::Region<'tcx>> { |
551 |
| - let tcx = self.tcx; |
552 |
| - |
553 |
| - // To start, collect bounds from user environment. Note that |
554 |
| - // parameter environments are already elaborated, so we don't |
555 |
| - // have to worry about that. Comparing using `==` is a bit |
556 |
| - // dubious for projections, but it will work for simple cases |
557 |
| - // like `T` and `T::Item`. It may not work as well for things |
558 |
| - // like `<T as Foo<'a>>::Item`. |
559 |
| - let generic_ty = generic.to_ty(tcx); |
560 |
| - let c_b = self.param_env.caller_bounds; |
561 |
| - let mut param_bounds = self.collect_outlives_from_predicate_list(generic_ty, c_b); |
562 |
| - |
563 |
| - // Next, collect regions we scraped from the well-formedness |
564 |
| - // constraints in the fn signature. To do that, we walk the list |
565 |
| - // of known relations from the fn ctxt. |
566 |
| - // |
567 |
| - // This is crucial because otherwise code like this fails: |
568 |
| - // |
569 |
| - // fn foo<'a, A>(x: &'a A) { x.bar() } |
570 |
| - // |
571 |
| - // The problem is that the type of `x` is `&'a A`. To be |
572 |
| - // well-formed, then, A must be lower-generic by `'a`, but we |
573 |
| - // don't know that this holds from first principles. |
574 |
| - for &(r, p) in self.region_bound_pairs { |
575 |
| - debug!("generic={:?} p={:?}", generic, p); |
576 |
| - if generic == p { |
577 |
| - param_bounds.push(r); |
578 |
| - } |
579 |
| - } |
580 |
| - |
581 |
| - param_bounds |
582 |
| - } |
583 |
| - |
584 |
| - /// Given a projection like `<T as Foo<'x>>::Bar`, returns any bounds |
585 |
| - /// declared in the trait definition. For example, if the trait were |
586 |
| - /// |
587 |
| - /// ```rust |
588 |
| - /// trait Foo<'a> { |
589 |
| - /// type Bar: 'a; |
590 |
| - /// } |
591 |
| - /// ``` |
592 |
| - /// |
593 |
| - /// then this function would return `'x`. This is subject to the |
594 |
| - /// limitations around higher-ranked bounds described in |
595 |
| - /// `region_bounds_declared_on_associated_item`. |
596 |
| - fn declared_projection_bounds_from_trait( |
597 |
| - &self, |
598 |
| - projection_ty: ty::ProjectionTy<'tcx>, |
599 |
| - ) -> Vec<ty::Region<'tcx>> { |
600 |
| - debug!("projection_bounds(projection_ty={:?})", projection_ty); |
601 |
| - let mut bounds = self.region_bounds_declared_on_associated_item(projection_ty.item_def_id); |
602 |
| - for r in &mut bounds { |
603 |
| - *r = r.subst(self.tcx, projection_ty.substs); |
604 |
| - } |
605 |
| - bounds |
606 |
| - } |
607 |
| - |
608 |
| - /// Given the def-id of an associated item, returns any region |
609 |
| - /// bounds attached to that associated item from the trait definition. |
610 |
| - /// |
611 |
| - /// For example: |
612 |
| - /// |
613 |
| - /// ```rust |
614 |
| - /// trait Foo<'a> { |
615 |
| - /// type Bar: 'a; |
616 |
| - /// } |
617 |
| - /// ``` |
618 |
| - /// |
619 |
| - /// If we were given the def-id of `Foo::Bar`, we would return |
620 |
| - /// `'a`. You could then apply the substitutions from the |
621 |
| - /// projection to convert this into your namespace. This also |
622 |
| - /// works if the user writes `where <Self as Foo<'a>>::Bar: 'a` on |
623 |
| - /// the trait. In fact, it works by searching for just such a |
624 |
| - /// where-clause. |
625 |
| - /// |
626 |
| - /// It will not, however, work for higher-ranked bounds like: |
627 |
| - /// |
628 |
| - /// ```rust |
629 |
| - /// trait Foo<'a, 'b> |
630 |
| - /// where for<'x> <Self as Foo<'x, 'b>>::Bar: 'x |
631 |
| - /// { |
632 |
| - /// type Bar; |
633 |
| - /// } |
634 |
| - /// ``` |
635 |
| - /// |
636 |
| - /// This is for simplicity, and because we are not really smart |
637 |
| - /// enough to cope with such bounds anywhere. |
638 |
| - fn region_bounds_declared_on_associated_item( |
639 |
| - &self, |
640 |
| - assoc_item_def_id: DefId, |
641 |
| - ) -> Vec<ty::Region<'tcx>> { |
642 |
| - let tcx = self.tcx; |
643 |
| - let assoc_item = tcx.associated_item(assoc_item_def_id); |
644 |
| - let trait_def_id = assoc_item.container.assert_trait(); |
645 |
| - let trait_predicates = tcx.predicates_of(trait_def_id); |
646 |
| - let identity_substs = Substs::identity_for_item(tcx, assoc_item_def_id); |
647 |
| - let identity_proj = tcx.mk_projection(assoc_item_def_id, identity_substs); |
648 |
| - self.collect_outlives_from_predicate_list( |
649 |
| - identity_proj, |
650 |
| - traits::elaborate_predicates(tcx, trait_predicates.predicates), |
651 |
| - ) |
652 |
| - } |
653 |
| - |
654 |
| - /// Searches through a predicate list for a predicate `T: 'a`. |
655 |
| - /// |
656 |
| - /// Careful: does not elaborate predicates, and just uses `==` |
657 |
| - /// when comparing `ty` for equality, so `ty` must be something |
658 |
| - /// that does not involve inference variables and where you |
659 |
| - /// otherwise want a precise match. |
660 |
| - fn collect_outlives_from_predicate_list<I, P>( |
661 |
| - &self, |
662 |
| - ty: Ty<'tcx>, |
663 |
| - predicates: I, |
664 |
| - ) -> Vec<ty::Region<'tcx>> |
665 |
| - where |
666 |
| - I: IntoIterator<Item = P>, |
667 |
| - P: AsRef<ty::Predicate<'tcx>>, |
668 |
| - { |
669 |
| - predicates |
670 |
| - .into_iter() |
671 |
| - .filter_map(|p| p.as_ref().to_opt_type_outlives()) |
672 |
| - .filter_map(|p| p.no_late_bound_regions()) |
673 |
| - .filter(|p| p.0 == ty) |
674 |
| - .map(|p| p.1) |
675 |
| - .collect() |
676 |
| - } |
677 | 471 | }
|
678 | 472 |
|
679 | 473 | impl<'cx, 'gcx, 'tcx> TypeOutlivesDelegate<'tcx> for &'cx InferCtxt<'cx, 'gcx, 'tcx> {
|
|
0 commit comments