Skip to content

Commit 062a416

Browse files
committed
Auto merge of #52010 - toidiu:ak-crossCrateOutlives, r=nikomatsakis
Fix: infer outlives requirements across crates Fixes #51858
2 parents 5030282 + 3f616cb commit 062a416

File tree

5 files changed

+130
-104
lines changed

5 files changed

+130
-104
lines changed

src/librustc_typeck/outlives/explicit.rs

+48-59
Original file line numberDiff line numberDiff line change
@@ -8,77 +8,66 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
use rustc::hir;
12-
use rustc::hir::def_id::{CrateNum, DefId};
13-
use rustc::hir::itemlikevisit::ItemLikeVisitor;
14-
use rustc::ty::{self, TyCtxt};
11+
use rustc::hir::def_id::DefId;
12+
use rustc::ty::{self, OutlivesPredicate, TyCtxt};
1513
use util::nodemap::FxHashMap;
1614

1715
use super::utils::*;
1816

19-
pub fn explicit_predicates<'tcx>(
20-
tcx: TyCtxt<'_, 'tcx, 'tcx>,
21-
crate_num: CrateNum,
22-
) -> FxHashMap<DefId, RequiredPredicates<'tcx>> {
23-
let mut predicates = FxHashMap::default();
24-
25-
// iterate over the entire crate
26-
tcx.hir.krate().visit_all_item_likes(&mut ExplicitVisitor {
27-
tcx: tcx,
28-
explicit_predicates: &mut predicates,
29-
crate_num: crate_num,
30-
});
31-
32-
predicates
17+
#[derive(Debug)]
18+
pub struct ExplicitPredicatesMap<'tcx> {
19+
map: FxHashMap<DefId, RequiredPredicates<'tcx>>,
3320
}
3421

35-
pub struct ExplicitVisitor<'cx, 'tcx: 'cx> {
36-
tcx: TyCtxt<'cx, 'tcx, 'tcx>,
37-
explicit_predicates: &'cx mut FxHashMap<DefId, RequiredPredicates<'tcx>>,
38-
crate_num: CrateNum,
39-
}
22+
impl<'tcx> ExplicitPredicatesMap<'tcx> {
23+
pub fn new() -> ExplicitPredicatesMap<'tcx> {
24+
ExplicitPredicatesMap {
25+
map: FxHashMap::default(),
26+
}
27+
}
4028

41-
impl<'cx, 'tcx> ItemLikeVisitor<'tcx> for ExplicitVisitor<'cx, 'tcx> {
42-
fn visit_item(&mut self, item: &'tcx hir::Item) {
43-
let def_id = DefId {
44-
krate: self.crate_num,
45-
index: item.hir_id.owner,
46-
};
29+
pub fn explicit_predicates_of(
30+
&mut self,
31+
tcx: TyCtxt<'_, 'tcx, 'tcx>,
32+
def_id: DefId,
33+
) -> &RequiredPredicates<'tcx> {
34+
self.map.entry(def_id).or_insert_with(|| {
35+
let predicates = if def_id.is_local() {
36+
tcx.explicit_predicates_of(def_id).predicates
37+
} else {
38+
tcx.predicates_of(def_id).predicates
39+
};
40+
let mut required_predicates = RequiredPredicates::default();
4741

48-
let mut required_predicates = RequiredPredicates::default();
49-
let local_explicit_predicate = self.tcx.explicit_predicates_of(def_id).predicates;
42+
// process predicates and convert to `RequiredPredicates` entry, see below
43+
for pred in predicates.into_iter() {
44+
match pred {
45+
ty::Predicate::TypeOutlives(predicate) => {
46+
let OutlivesPredicate(ref ty, ref reg) = predicate.skip_binder();
47+
insert_outlives_predicate(tcx, (*ty).into(), reg, &mut required_predicates)
48+
}
5049

51-
for pred in local_explicit_predicate.into_iter() {
52-
match pred {
53-
ty::Predicate::TypeOutlives(predicate) => {
54-
let ty::OutlivesPredicate(ref ty, ref reg) = predicate.skip_binder();
55-
insert_outlives_predicate(self.tcx, (*ty).into(), reg, &mut required_predicates)
56-
}
50+
ty::Predicate::RegionOutlives(predicate) => {
51+
let OutlivesPredicate(ref reg1, ref reg2) = predicate.skip_binder();
52+
insert_outlives_predicate(
53+
tcx,
54+
(*reg1).into(),
55+
reg2,
56+
&mut required_predicates,
57+
)
58+
}
5759

58-
ty::Predicate::RegionOutlives(predicate) => {
59-
let ty::OutlivesPredicate(ref reg1, ref reg2) = predicate.skip_binder();
60-
insert_outlives_predicate(
61-
self.tcx,
62-
(*reg1).into(),
63-
reg2,
64-
&mut required_predicates,
65-
)
60+
ty::Predicate::Trait(..)
61+
| ty::Predicate::Projection(..)
62+
| ty::Predicate::WellFormed(..)
63+
| ty::Predicate::ObjectSafe(..)
64+
| ty::Predicate::ClosureKind(..)
65+
| ty::Predicate::Subtype(..)
66+
| ty::Predicate::ConstEvaluatable(..) => (),
6667
}
67-
68-
ty::Predicate::Trait(..)
69-
| ty::Predicate::Projection(..)
70-
| ty::Predicate::WellFormed(..)
71-
| ty::Predicate::ObjectSafe(..)
72-
| ty::Predicate::ClosureKind(..)
73-
| ty::Predicate::Subtype(..)
74-
| ty::Predicate::ConstEvaluatable(..) => (),
7568
}
76-
}
7769

78-
self.explicit_predicates.insert(def_id, required_predicates);
70+
required_predicates
71+
})
7972
}
80-
81-
fn visit_trait_item(&mut self, _trait_item: &'tcx hir::TraitItem) {}
82-
83-
fn visit_impl_item(&mut self, _impl_item: &'tcx hir::ImplItem) {}
8473
}

src/librustc_typeck/outlives/implicit_infer.rs

+45-43
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ use rustc::ty::subst::{Kind, Subst, UnpackedKind};
1515
use rustc::ty::{self, Ty, TyCtxt};
1616
use rustc::util::nodemap::FxHashMap;
1717

18+
use super::explicit::ExplicitPredicatesMap;
1819
use super::utils::*;
1920

2021
/// Infer predicates for the items in the crate.
@@ -24,7 +25,7 @@ use super::utils::*;
2425
/// now be filled with inferred predicates.
2526
pub fn infer_predicates<'tcx>(
2627
tcx: TyCtxt<'_, 'tcx, 'tcx>,
27-
explicit_map: &FxHashMap<DefId, RequiredPredicates<'tcx>>,
28+
explicit_map: &mut ExplicitPredicatesMap<'tcx>,
2829
) -> FxHashMap<DefId, RequiredPredicates<'tcx>> {
2930
debug!("infer_predicates");
3031

@@ -55,7 +56,7 @@ pub struct InferVisitor<'cx, 'tcx: 'cx> {
5556
tcx: TyCtxt<'cx, 'tcx, 'tcx>,
5657
global_inferred_outlives: &'cx mut FxHashMap<DefId, RequiredPredicates<'tcx>>,
5758
predicates_added: &'cx mut bool,
58-
explicit_map: &'cx FxHashMap<DefId, RequiredPredicates<'tcx>>,
59+
explicit_map: &'cx mut ExplicitPredicatesMap<'tcx>,
5960
}
6061

6162
impl<'cx, 'tcx> ItemLikeVisitor<'tcx> for InferVisitor<'cx, 'tcx> {
@@ -93,7 +94,7 @@ impl<'cx, 'tcx> ItemLikeVisitor<'tcx> for InferVisitor<'cx, 'tcx> {
9394
field_ty,
9495
self.global_inferred_outlives,
9596
&mut item_required_predicates,
96-
self.explicit_map,
97+
&mut self.explicit_map,
9798
);
9899
}
99100
}
@@ -129,7 +130,7 @@ fn insert_required_predicates_to_be_wf<'tcx>(
129130
field_ty: Ty<'tcx>,
130131
global_inferred_outlives: &FxHashMap<DefId, RequiredPredicates<'tcx>>,
131132
required_predicates: &mut RequiredPredicates<'tcx>,
132-
explicit_map: &FxHashMap<DefId, RequiredPredicates<'tcx>>,
133+
explicit_map: &mut ExplicitPredicatesMap<'tcx>,
133134
) {
134135
for ty in field_ty.walk() {
135136
match ty.sty {
@@ -257,53 +258,54 @@ pub fn check_explicit_predicates<'tcx>(
257258
def_id: &DefId,
258259
substs: &[Kind<'tcx>],
259260
required_predicates: &mut RequiredPredicates<'tcx>,
260-
explicit_map: &FxHashMap<DefId, RequiredPredicates<'tcx>>,
261+
explicit_map: &mut ExplicitPredicatesMap<'tcx>,
261262
ignore_self_ty: bool,
262263
) {
263264
debug!("def_id = {:?}", &def_id);
264265
debug!("substs = {:?}", &substs);
265266
debug!("explicit_map = {:?}", explicit_map);
266267
debug!("required_predicates = {:?}", required_predicates);
267-
if let Some(explicit_predicates) = explicit_map.get(def_id) {
268-
for outlives_predicate in explicit_predicates.iter() {
269-
debug!("outlives_predicate = {:?}", &outlives_predicate);
268+
let explicit_predicates = explicit_map.explicit_predicates_of(tcx, *def_id);
270269

271-
// Careful: If we are inferring the effects of a `dyn Trait<..>`
272-
// type, then when we look up the predicates for `Trait`,
273-
// we may find some that reference `Self`. e.g., perhaps the
274-
// definition of `Trait` was:
275-
//
276-
// ```
277-
// trait Trait<'a, T> where Self: 'a { .. }
278-
// ```
279-
//
280-
// we want to ignore such predicates here, because
281-
// there is no type parameter for them to affect. Consider
282-
// a struct containing `dyn Trait`:
283-
//
284-
// ```
285-
// struct MyStruct<'x, X> { field: Box<dyn Trait<'x, X>> }
286-
// ```
287-
//
288-
// The `where Self: 'a` predicate refers to the *existential, hidden type*
289-
// that is represented by the `dyn Trait`, not to the `X` type parameter
290-
// (or any other generic parameter) declared on `MyStruct`.
291-
//
292-
// Note that we do this check for self **before** applying `substs`. In the
293-
// case that `substs` come from a `dyn Trait` type, our caller will have
294-
// included `Self = dyn Trait<'x, X>` as the value for `Self`. If we were
295-
// to apply the substs, and not filter this predicate, we might then falsely
296-
// conclude that e.g. `X: 'x` was a reasonable inferred requirement.
297-
if let UnpackedKind::Type(ty) = outlives_predicate.0.unpack() {
298-
if ty.is_self() && ignore_self_ty {
299-
debug!("skipping self ty = {:?}", &ty);
300-
continue;
301-
}
302-
}
270+
for outlives_predicate in explicit_predicates.iter() {
271+
debug!("outlives_predicate = {:?}", &outlives_predicate);
303272

304-
let predicate = outlives_predicate.subst(tcx, substs);
305-
debug!("predicate = {:?}", &predicate);
306-
insert_outlives_predicate(tcx, predicate.0.into(), predicate.1, required_predicates);
273+
// Careful: If we are inferring the effects of a `dyn Trait<..>`
274+
// type, then when we look up the predicates for `Trait`,
275+
// we may find some that reference `Self`. e.g., perhaps the
276+
// definition of `Trait` was:
277+
//
278+
// ```
279+
// trait Trait<'a, T> where Self: 'a { .. }
280+
// ```
281+
//
282+
// we want to ignore such predicates here, because
283+
// there is no type parameter for them to affect. Consider
284+
// a struct containing `dyn Trait`:
285+
//
286+
// ```
287+
// struct MyStruct<'x, X> { field: Box<dyn Trait<'x, X>> }
288+
// ```
289+
//
290+
// The `where Self: 'a` predicate refers to the *existential, hidden type*
291+
// that is represented by the `dyn Trait`, not to the `X` type parameter
292+
// (or any other generic parameter) declared on `MyStruct`.
293+
//
294+
// Note that we do this check for self **before** applying `substs`. In the
295+
// case that `substs` come from a `dyn Trait` type, our caller will have
296+
// included `Self = dyn Trait<'x, X>` as the value for `Self`. If we were
297+
// to apply the substs, and not filter this predicate, we might then falsely
298+
// conclude that e.g. `X: 'x` was a reasonable inferred requirement.
299+
if let UnpackedKind::Type(ty) = outlives_predicate.0.unpack() {
300+
if ty.is_self() && ignore_self_ty {
301+
debug!("skipping self ty = {:?}", &ty);
302+
continue;
303+
}
307304
}
305+
306+
let predicate = outlives_predicate.subst(tcx, substs);
307+
debug!("predicate = {:?}", &predicate);
308+
insert_outlives_predicate(tcx, predicate.0.into(), predicate.1, required_predicates);
308309
}
310+
// }
309311
}

src/librustc_typeck/outlives/mod.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,8 @@ fn inferred_outlives_crate<'tcx>(
8484
tcx: TyCtxt<'_, 'tcx, 'tcx>,
8585
crate_num: CrateNum,
8686
) -> Lrc<CratePredicatesMap<'tcx>> {
87+
assert_eq!(crate_num, LOCAL_CRATE);
88+
8789
// Compute a map from each struct/enum/union S to the **explicit**
8890
// outlives predicates (`T: 'a`, `'a: 'b`) that the user wrote.
8991
// Typically there won't be many of these, except in older code where
@@ -92,8 +94,9 @@ fn inferred_outlives_crate<'tcx>(
9294
// for the type.
9395

9496
// Compute the inferred predicates
95-
let exp = explicit::explicit_predicates(tcx, crate_num);
96-
let global_inferred_outlives = implicit_infer::infer_predicates(tcx, &exp);
97+
let mut exp_map = explicit::ExplicitPredicatesMap::new();
98+
99+
let global_inferred_outlives = implicit_infer::infer_predicates(tcx, &mut exp_map);
97100

98101
// Convert the inferred predicates into the "collected" form the
99102
// global data structure expects.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![feature(rustc_attrs)]
12+
#![feature(infer_outlives_requirements)]
13+
14+
#[rustc_outlives]
15+
struct Foo<'a, T> { //~ ERROR 15:1: 17:2: rustc_outlives
16+
bar: std::slice::IterMut<'a, T>
17+
}
18+
19+
fn main() {}
20+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
error: rustc_outlives
2+
--> $DIR/cross-crate.rs:15:1
3+
|
4+
LL | / struct Foo<'a, T> { //~ ERROR 15:1: 17:2: rustc_outlives
5+
LL | | bar: std::slice::IterMut<'a, T>
6+
LL | | }
7+
| |_^
8+
|
9+
= note: T : 'a
10+
11+
error: aborting due to previous error
12+

0 commit comments

Comments
 (0)