Skip to content

Commit 2939e48

Browse files
committed
Extend the implicator so it produces general obligations and also so
that it produces "outlives" relations for associated types. Add several tests relating to #22246.
1 parent 5511add commit 2939e48

12 files changed

+527
-132
lines changed

src/librustc/middle/infer/unify.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,7 @@ impl<K:UnifyKey> UnificationTable<K> {
212212
}
213213
}
214214

215-
impl<K> sv::SnapshotVecDelegate for Delegate<K> {
215+
impl<K:UnifyKey> sv::SnapshotVecDelegate for Delegate<K> {
216216
type Value = VarValue<K>;
217217
type Undo = ();
218218

src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs

-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ use borrowck::gather_loans::move_error::{MoveError, MoveErrorCollector};
1616
use borrowck::move_data::*;
1717
use rustc::middle::expr_use_visitor as euv;
1818
use rustc::middle::mem_categorization as mc;
19-
use rustc::middle::mem_categorization::Typer;
2019
use rustc::middle::mem_categorization::InteriorOffsetKind as Kind;
2120
use rustc::middle::ty;
2221
use rustc::util::ppaux::Repr;

src/librustc_borrowck/borrowck/gather_loans/move_error.rs

-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010

1111
use borrowck::BorrowckCtxt;
1212
use rustc::middle::mem_categorization as mc;
13-
use rustc::middle::mem_categorization::Typer;
1413
use rustc::middle::mem_categorization::InteriorOffsetKind as Kind;
1514
use rustc::middle::ty;
1615
use rustc::util::ppaux::UserString;

src/librustc_typeck/check/implicator.rs

+160-98
Original file line numberDiff line numberDiff line change
@@ -11,49 +11,73 @@
1111
// #![warn(deprecated_mode)]
1212

1313
use astconv::object_region_bounds;
14-
use middle::infer::GenericKind;
15-
use middle::subst::{ParamSpace, Subst, Substs};
16-
use middle::ty::{self, Ty};
17-
use middle::ty_fold::{TypeFolder};
14+
use middle::infer::{InferCtxt, GenericKind};
15+
use middle::subst::{Substs};
16+
use middle::traits;
17+
use middle::ty::{self, ToPolyTraitRef, Ty};
18+
use middle::ty_fold::{TypeFoldable, TypeFolder};
1819

20+
use std::rc::Rc;
1921
use syntax::ast;
22+
use syntax::codemap::Span;
2023

24+
use util::common::ErrorReported;
2125
use util::ppaux::Repr;
2226

2327
// Helper functions related to manipulating region types.
2428

2529
pub enum Implication<'tcx> {
2630
RegionSubRegion(Option<Ty<'tcx>>, ty::Region, ty::Region),
2731
RegionSubGeneric(Option<Ty<'tcx>>, ty::Region, GenericKind<'tcx>),
32+
Predicate(ast::DefId, ty::Predicate<'tcx>),
2833
}
2934

3035
struct Implicator<'a, 'tcx: 'a> {
31-
tcx: &'a ty::ctxt<'tcx>,
36+
infcx: &'a InferCtxt<'a,'tcx>,
37+
closure_typer: &'a (ty::ClosureTyper<'tcx>+'a),
38+
body_id: ast::NodeId,
3239
stack: Vec<(ty::Region, Option<Ty<'tcx>>)>,
40+
span: Span,
3341
out: Vec<Implication<'tcx>>,
3442
}
3543

3644
/// This routine computes the well-formedness constraints that must hold for the type `ty` to
3745
/// appear in a context with lifetime `outer_region`
38-
pub fn implications<'tcx>(
39-
tcx: &ty::ctxt<'tcx>,
46+
pub fn implications<'a,'tcx>(
47+
infcx: &'a InferCtxt<'a,'tcx>,
48+
closure_typer: &ty::ClosureTyper<'tcx>,
49+
body_id: ast::NodeId,
4050
ty: Ty<'tcx>,
41-
outer_region: ty::Region)
51+
outer_region: ty::Region,
52+
span: Span)
4253
-> Vec<Implication<'tcx>>
4354
{
55+
debug!("implications(body_id={}, ty={}, outer_region={})",
56+
body_id,
57+
ty.repr(closure_typer.tcx()),
58+
outer_region.repr(closure_typer.tcx()));
59+
4460
let mut stack = Vec::new();
4561
stack.push((outer_region, None));
46-
let mut wf = Implicator { tcx: tcx,
47-
stack: stack,
48-
out: Vec::new() };
62+
let mut wf = Implicator { closure_typer: closure_typer,
63+
infcx: infcx,
64+
body_id: body_id,
65+
span: span,
66+
stack: stack,
67+
out: Vec::new() };
4968
wf.accumulate_from_ty(ty);
69+
debug!("implications: out={}", wf.out.repr(closure_typer.tcx()));
5070
wf.out
5171
}
5272

5373
impl<'a, 'tcx> Implicator<'a, 'tcx> {
74+
fn tcx(&self) -> &'a ty::ctxt<'tcx> {
75+
self.infcx.tcx
76+
}
77+
5478
fn accumulate_from_ty(&mut self, ty: Ty<'tcx>) {
5579
debug!("accumulate_from_ty(ty={})",
56-
ty.repr(self.tcx));
80+
ty.repr(self.tcx()));
5781

5882
match ty.sty {
5983
ty::ty_bool |
@@ -94,13 +118,13 @@ impl<'a, 'tcx> Implicator<'a, 'tcx> {
94118

95119
ty::ty_trait(ref t) => {
96120
let required_region_bounds =
97-
object_region_bounds(self.tcx, &t.principal, t.bounds.builtin_bounds);
121+
object_region_bounds(self.tcx(), &t.principal, t.bounds.builtin_bounds);
98122
self.accumulate_from_object_ty(ty, t.bounds.region_bound, required_region_bounds)
99123
}
100124

101125
ty::ty_enum(def_id, substs) |
102126
ty::ty_struct(def_id, substs) => {
103-
let item_scheme = ty::lookup_item_type(self.tcx, def_id);
127+
let item_scheme = ty::lookup_item_type(self.tcx(), def_id);
104128
self.accumulate_from_adt(ty, def_id, &item_scheme.generics, substs)
105129
}
106130

@@ -139,9 +163,9 @@ impl<'a, 'tcx> Implicator<'a, 'tcx> {
139163
}
140164

141165
ty::ty_open(_) => {
142-
self.tcx.sess.bug(
166+
self.tcx().sess.bug(
143167
&format!("Unexpected type encountered while doing wf check: {}",
144-
ty.repr(self.tcx))[]);
168+
ty.repr(self.tcx()))[]);
145169
}
146170
}
147171
}
@@ -225,103 +249,113 @@ impl<'a, 'tcx> Implicator<'a, 'tcx> {
225249
fn accumulate_from_adt(&mut self,
226250
ty: Ty<'tcx>,
227251
def_id: ast::DefId,
228-
generics: &ty::Generics<'tcx>,
252+
_generics: &ty::Generics<'tcx>,
229253
substs: &Substs<'tcx>)
230254
{
231-
// The generic declarations from the type, appropriately
232-
// substituted for the actual substitutions.
233-
let generics = generics.subst(self.tcx, substs);
234-
235-
// Variance of each type/region parameter.
236-
let variances = ty::item_variances(self.tcx, def_id);
237-
238-
for &space in &ParamSpace::all() {
239-
let region_params = substs.regions().get_slice(space);
240-
let region_variances = variances.regions.get_slice(space);
241-
let region_param_defs = generics.regions.get_slice(space);
242-
assert_eq!(region_params.len(), region_variances.len());
243-
for (&region_param, (&region_variance, region_param_def)) in
244-
region_params.iter().zip(
245-
region_variances.iter().zip(
246-
region_param_defs.iter()))
247-
{
248-
match region_variance {
249-
ty::Covariant | ty::Bivariant => {
250-
// Ignore covariant or bivariant region
251-
// parameters. To understand why, consider a
252-
// struct `Foo<'a>`. If `Foo` contains any
253-
// references with lifetime `'a`, then `'a` must
254-
// be at least contravariant (and possibly
255-
// invariant). The only way to have a covariant
256-
// result is if `Foo` contains only a field with a
257-
// type like `fn() -> &'a T`; i.e., a bare
258-
// function that can produce a reference of
259-
// lifetime `'a`. In this case, there is no
260-
// *actual data* with lifetime `'a` that is
261-
// reachable. (Presumably this bare function is
262-
// really returning static data.)
263-
}
264-
265-
ty::Contravariant | ty::Invariant => {
266-
// If the parameter is contravariant or
267-
// invariant, there may indeed be reachable
268-
// data with this lifetime. See other case for
269-
// more details.
270-
self.push_region_constraint_from_top(region_param);
255+
let predicates =
256+
ty::lookup_predicates(self.tcx(), def_id).instantiate(self.tcx(), substs);
257+
let predicates = match self.fully_normalize(&predicates) {
258+
Ok(predicates) => predicates,
259+
Err(ErrorReported) => { return; }
260+
};
261+
262+
for predicate in predicates.predicates.as_slice() {
263+
match *predicate {
264+
ty::Predicate::Trait(ref data) => {
265+
self.accumulate_from_assoc_types_transitive(data);
266+
}
267+
ty::Predicate::Equate(..) => { }
268+
ty::Predicate::Projection(..) => { }
269+
ty::Predicate::RegionOutlives(ref data) => {
270+
match ty::no_late_bound_regions(self.tcx(), data) {
271+
None => { }
272+
Some(ty::OutlivesPredicate(r_a, r_b)) => {
273+
self.push_sub_region_constraint(Some(ty), r_b, r_a);
274+
}
271275
}
272276
}
273-
274-
for &region_bound in &region_param_def.bounds {
275-
// The type declared a constraint like
276-
//
277-
// 'b : 'a
278-
//
279-
// which means that `'a <= 'b` (after
280-
// substitution). So take the region we
281-
// substituted for `'a` (`region_bound`) and make
282-
// it a subregion of the region we substituted
283-
// `'b` (`region_param`).
284-
self.push_sub_region_constraint(
285-
Some(ty), region_bound, region_param);
277+
ty::Predicate::TypeOutlives(ref data) => {
278+
match ty::no_late_bound_regions(self.tcx(), data) {
279+
None => { }
280+
Some(ty::OutlivesPredicate(ty_a, r_b)) => {
281+
self.stack.push((r_b, Some(ty)));
282+
self.accumulate_from_ty(ty_a);
283+
self.stack.pop().unwrap();
284+
}
285+
}
286286
}
287287
}
288+
}
288289

289-
let types = substs.types.get_slice(space);
290-
let type_variances = variances.types.get_slice(space);
291-
let type_param_defs = generics.types.get_slice(space);
292-
assert_eq!(types.len(), type_variances.len());
293-
for (&type_param_ty, (&variance, type_param_def)) in
294-
types.iter().zip(
295-
type_variances.iter().zip(
296-
type_param_defs.iter()))
297-
{
298-
debug!("type_param_ty={} variance={}",
299-
type_param_ty.repr(self.tcx),
300-
variance.repr(self.tcx));
301-
302-
match variance {
303-
ty::Contravariant | ty::Bivariant => {
304-
// As above, except that in this it is a
305-
// *contravariant* reference that indices that no
306-
// actual data of type T is reachable.
307-
}
290+
let obligations = predicates.predicates
291+
.into_iter()
292+
.map(|pred| Implication::Predicate(def_id, pred));
293+
self.out.extend(obligations);
308294

309-
ty::Covariant | ty::Invariant => {
310-
self.accumulate_from_ty(type_param_ty);
311-
}
295+
let variances = ty::item_variances(self.tcx(), def_id);
296+
297+
for (&region, &variance) in substs.regions().iter().zip(variances.regions.iter()) {
298+
match variance {
299+
ty::Contravariant | ty::Invariant => {
300+
// If any data with this lifetime is reachable
301+
// within, it must be at least contravariant.
302+
self.push_region_constraint_from_top(region)
312303
}
304+
ty::Covariant | ty::Bivariant => { }
305+
}
306+
}
313307

314-
// Inspect bounds on this type parameter for any
315-
// region bounds.
316-
for &r in &type_param_def.bounds.region_bounds {
317-
self.stack.push((r, Some(ty)));
318-
self.accumulate_from_ty(type_param_ty);
319-
self.stack.pop().unwrap();
308+
for (&ty, &variance) in substs.types.iter().zip(variances.types.iter()) {
309+
match variance {
310+
ty::Covariant | ty::Invariant => {
311+
// If any data of this type is reachable within,
312+
// it must be at least covariant.
313+
self.accumulate_from_ty(ty);
320314
}
315+
ty::Contravariant | ty::Bivariant => { }
321316
}
322317
}
323318
}
324319

320+
/// Given that there is a requirement that `Foo<X> : 'a`, where
321+
/// `Foo` is declared like `struct Foo<T> where T : SomeTrait`,
322+
/// this code finds all the associated types defined in
323+
/// `SomeTrait` (and supertraits) and adds a requirement that `<X
324+
/// as SomeTrait>::N : 'a` (where `N` is some associated type
325+
/// defined in `SomeTrait`). This rule only applies to
326+
/// trait-bounds that are not higher-ranked, because we cannot
327+
/// project out of a HRTB. This rule helps code using associated
328+
/// types to compile, see Issue #22246 for an example.
329+
fn accumulate_from_assoc_types_transitive(&mut self,
330+
data: &ty::PolyTraitPredicate<'tcx>)
331+
{
332+
for poly_trait_ref in traits::supertraits(self.tcx(), data.to_poly_trait_ref()) {
333+
match ty::no_late_bound_regions(self.tcx(), &poly_trait_ref) {
334+
Some(trait_ref) => { self.accumulate_from_assoc_types(trait_ref); }
335+
None => { }
336+
}
337+
}
338+
}
339+
340+
fn accumulate_from_assoc_types(&mut self,
341+
trait_ref: Rc<ty::TraitRef<'tcx>>)
342+
{
343+
let trait_def_id = trait_ref.def_id;
344+
let trait_def = ty::lookup_trait_def(self.tcx(), trait_def_id);
345+
let assoc_type_projections: Vec<_> =
346+
trait_def.associated_type_names
347+
.iter()
348+
.map(|&name| ty::mk_projection(self.tcx(), trait_ref.clone(), name))
349+
.collect();
350+
let tys = match self.fully_normalize(&assoc_type_projections) {
351+
Ok(tys) => { tys }
352+
Err(ErrorReported) => { return; }
353+
};
354+
for ty in tys {
355+
self.accumulate_from_ty(ty);
356+
}
357+
}
358+
325359
fn accumulate_from_object_ty(&mut self,
326360
ty: Ty<'tcx>,
327361
region_bound: ty::Region,
@@ -373,6 +407,28 @@ impl<'a, 'tcx> Implicator<'a, 'tcx> {
373407
self.out.push(Implication::RegionSubRegion(Some(ty), r_d, r_c));
374408
}
375409
}
410+
411+
fn fully_normalize<T>(&self, value: &T) -> Result<T,ErrorReported>
412+
where T : TypeFoldable<'tcx> + ty::HasProjectionTypes + Clone + Repr<'tcx>
413+
{
414+
let value =
415+
traits::fully_normalize(self.infcx,
416+
self.closure_typer,
417+
traits::ObligationCause::misc(self.span, self.body_id),
418+
value);
419+
match value {
420+
Ok(value) => Ok(value),
421+
Err(errors) => {
422+
// I don't like reporting these errors here, but I
423+
// don't know where else to report them just now. And
424+
// I don't really expect errors to arise here
425+
// frequently. I guess the best option would be to
426+
// propagate them out.
427+
traits::report_fulfillment_errors(self.infcx, &errors);
428+
Err(ErrorReported)
429+
}
430+
}
431+
}
376432
}
377433

378434
impl<'tcx> Repr<'tcx> for Implication<'tcx> {
@@ -389,6 +445,12 @@ impl<'tcx> Repr<'tcx> for Implication<'tcx> {
389445
r.repr(tcx),
390446
p.repr(tcx))
391447
}
448+
449+
Implication::Predicate(ref def_id, ref p) => {
450+
format!("Predicate({}, {})",
451+
def_id.repr(tcx),
452+
p.repr(tcx))
453+
}
392454
}
393455
}
394456
}

0 commit comments

Comments
 (0)