Skip to content

Commit b0e1fec

Browse files
committed
break out the code that computes VerifyBounds
Later, we'll defer this work until a separate phase.
1 parent b2e0215 commit b0e1fec

File tree

3 files changed

+276
-218
lines changed

3 files changed

+276
-218
lines changed

src/librustc/infer/outlives/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,4 @@
1313
pub mod env;
1414
pub mod free_region_map;
1515
pub mod obligations;
16+
pub mod verify;

src/librustc/infer/outlives/obligations.rs

Lines changed: 12 additions & 218 deletions
Original file line numberDiff line numberDiff line change
@@ -69,14 +69,13 @@
6969
//! might later infer `?U` to something like `&'b u32`, which would
7070
//! imply that `'b: 'a`.
7171
72-
use hir::def_id::DefId;
7372
use infer::outlives::env::RegionBoundPairs;
73+
use infer::outlives::verify::VerifyBoundCx;
7474
use infer::{self, GenericKind, InferCtxt, RegionObligation, SubregionOrigin, VerifyBound};
7575
use rustc_data_structures::fx::FxHashMap;
7676
use syntax::ast;
77-
use traits::{self, ObligationCause};
77+
use traits::ObligationCause;
7878
use ty::outlives::Component;
79-
use ty::subst::{Subst, Substs};
8079
use ty::{self, Region, Ty, TyCtxt, TypeFoldable};
8180

8281
impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
@@ -244,9 +243,7 @@ where
244243
// of these fields.
245244
delegate: D,
246245
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>,
250247
}
251248

252249
pub trait TypeOutlivesDelegate<'tcx> {
@@ -280,9 +277,12 @@ where
280277
Self {
281278
delegate,
282279
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+
),
286286
}
287287
}
288288

@@ -357,8 +357,8 @@ where
357357
region, param_ty, origin
358358
);
359359

360-
let verify_bound = self.param_bound(param_ty);
361360
let generic = GenericKind::Param(param_ty);
361+
let verify_bound = self.verify_bound.generic_bound(generic);
362362
self.delegate
363363
.push_verify(origin, generic, region, verify_bound);
364364
}
@@ -391,7 +391,7 @@ where
391391
// Compute the bounds we can derive from the environment or trait
392392
// definition. We know that the projection outlives all the
393393
// 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);
395395

396396
debug!("projection_must_outlive: env_bounds={:?}", env_bounds);
397397

@@ -463,217 +463,11 @@ where
463463
// projection outlive; in some cases, this may add insufficient
464464
// edges into the inference graph, leading to inference failures
465465
// even though a satisfactory solution exists.
466-
let verify_bound = self.projection_bound(env_bounds, projection_ty);
467466
let generic = GenericKind::Projection(projection_ty);
467+
let verify_bound = self.verify_bound.generic_bound(generic);
468468
self.delegate
469469
.push_verify(origin, generic.clone(), region, verify_bound);
470470
}
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-
}
677471
}
678472

679473
impl<'cx, 'gcx, 'tcx> TypeOutlivesDelegate<'tcx> for &'cx InferCtxt<'cx, 'gcx, 'tcx> {

0 commit comments

Comments
 (0)