Skip to content

Commit 9f80045

Browse files
author
Alexander Regueiro
committed
Ban multi-trait objects via trait aliases.
1 parent 16ef295 commit 9f80045

File tree

13 files changed

+215
-133
lines changed

13 files changed

+215
-133
lines changed

src/liballoc/slice.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -123,12 +123,12 @@ pub use core::slice::{RChunks, RChunksMut, RChunksExact, RChunksExactMut};
123123
////////////////////////////////////////////////////////////////////////////////
124124

125125
// HACK(japaric) needed for the implementation of `vec!` macro during testing
126-
// NB see the hack module in this file for more details
126+
// N.B., see the `hack` module in this file for more details.
127127
#[cfg(test)]
128128
pub use hack::into_vec;
129129

130130
// HACK(japaric) needed for the implementation of `Vec::clone` during testing
131-
// NB see the hack module in this file for more details
131+
// N.B., see the `hack` module in this file for more details.
132132
#[cfg(test)]
133133
pub use hack::to_vec;
134134

@@ -376,7 +376,7 @@ impl<T> [T] {
376376
pub fn to_vec(&self) -> Vec<T>
377377
where T: Clone
378378
{
379-
// NB see hack module in this file
379+
// N.B., see the `hack` module in this file for more details.
380380
hack::to_vec(self)
381381
}
382382

@@ -397,7 +397,7 @@ impl<T> [T] {
397397
#[stable(feature = "rust1", since = "1.0.0")]
398398
#[inline]
399399
pub fn into_vec(self: Box<Self>) -> Vec<T> {
400-
// NB see hack module in this file
400+
// N.B., see the `hack` module in this file for more details.
401401
hack::into_vec(self)
402402
}
403403

src/librustc/hir/map/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -957,7 +957,7 @@ impl<'hir> Map<'hir> {
957957
}
958958
}
959959

960-
/// Returns the name associated with the given NodeId's AST.
960+
/// Returns the name associated with the given `NodeId`'s AST.
961961
pub fn name(&self, id: NodeId) -> Name {
962962
let hir_id = self.node_to_hir_id(id);
963963
self.name_by_hir_id(hir_id)

src/librustc/hir/mod.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2143,11 +2143,11 @@ pub enum UseKind {
21432143
ListStem,
21442144
}
21452145

2146-
/// TraitRef's appear in impls.
2146+
/// `TraitRef` are references to traits in impls.
21472147
///
2148-
/// resolve maps each TraitRef's ref_id to its defining trait; that's all
2149-
/// that the ref_id is for. Note that ref_id's value is not the NodeId of the
2150-
/// trait being referred to but just a unique NodeId that serves as a key
2148+
/// `resolve` maps each `TraitRef`'s `ref_id` to its defining trait; that's all
2149+
/// that the `ref_id` is for. Note that `ref_id`'s value is not the `NodeId` of the
2150+
/// trait being referred to but just a unique `NodeId` that serves as a key
21512151
/// within the resolution map.
21522152
#[derive(Clone, RustcEncodable, RustcDecodable, Debug, HashStable)]
21532153
pub struct TraitRef {

src/librustc/infer/outlives/verify.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -141,9 +141,9 @@ impl<'cx, 'gcx, 'tcx> VerifyBoundCx<'cx, 'gcx, 'tcx> {
141141
}
142142

143143
fn recursive_type_bound(&self, ty: Ty<'tcx>) -> VerifyBound<'tcx> {
144-
let mut bounds = ty.walk_shallow()
144+
let mut bounds: Vec<_> = ty.walk_shallow()
145145
.map(|subty| self.type_bound(subty))
146-
.collect::<Vec<_>>();
146+
.collect();
147147

148148
let mut regions = smallvec![];
149149
ty.push_regions(&mut regions);

src/librustc/traits/mod.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ pub use self::engine::{TraitEngine, TraitEngineExt};
6262
pub use self::util::{elaborate_predicates, elaborate_trait_ref, elaborate_trait_refs};
6363
pub use self::util::{supertraits, supertrait_def_ids, transitive_bounds,
6464
Supertraits, SupertraitDefIds};
65+
pub use self::util::{expand_trait_refs, TraitRefExpander};
6566

6667
pub use self::chalk_fulfill::{
6768
CanonicalGoal as ChalkCanonicalGoal,
@@ -1043,7 +1044,7 @@ fn vtable_methods<'a, 'tcx>(
10431044
)
10441045
}
10451046

1046-
impl<'tcx,O> Obligation<'tcx,O> {
1047+
impl<'tcx, O> Obligation<'tcx,O> {
10471048
pub fn new(cause: ObligationCause<'tcx>,
10481049
param_env: ty::ParamEnv<'tcx>,
10491050
predicate: O)

src/librustc/traits/select.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1772,7 +1772,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
17721772
bounds
17731773
);
17741774

1775-
let matching_bound = util::elaborate_predicates(self.tcx(), bounds.predicates)
1775+
let elaborated_predicates = util::elaborate_predicates(self.tcx(), bounds.predicates);
1776+
let matching_bound = elaborated_predicates
17761777
.filter_to_traits()
17771778
.find(|bound| {
17781779
self.infcx.probe(|_| {

src/librustc/traits/util.rs

Lines changed: 155 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use syntax_pos::Span;
2+
13
use crate::hir;
24
use crate::hir::def_id::DefId;
35
use crate::traits::specialize::specialization_graph::NodeItem;
@@ -41,7 +43,6 @@ fn anonymize_predicate<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
4143
}
4244
}
4345

44-
4546
struct PredicateSet<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
4647
tcx: TyCtxt<'a, 'gcx, 'tcx>,
4748
set: FxHashSet<ty::Predicate<'tcx>>,
@@ -73,12 +74,11 @@ impl<'a, 'gcx, 'tcx> PredicateSet<'a, 'gcx, 'tcx> {
7374

7475
/// "Elaboration" is the process of identifying all the predicates that
7576
/// are implied by a source predicate. Currently this basically means
76-
/// walking the "supertraits" and other similar assumptions. For
77-
/// example, if we know that `T : Ord`, the elaborator would deduce
78-
/// that `T : PartialOrd` holds as well. Similarly, if we have `trait
79-
/// Foo : 'static`, and we know that `T : Foo`, then we know that `T :
80-
/// 'static`.
81-
pub struct Elaborator<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
77+
/// walking the "supertraits" and other similar assumptions. For example,
78+
/// if we know that `T: Ord`, the elaborator would deduce that `T: PartialOrd`
79+
/// holds as well. Similarly, if we have `trait Foo: 'static`, and we know that
80+
/// `T: Foo`, then we know that `T: 'static`.
81+
pub struct Elaborator<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
8282
stack: Vec<ty::Predicate<'tcx>>,
8383
visited: PredicateSet<'a, 'gcx, 'tcx>,
8484
}
@@ -96,8 +96,7 @@ pub fn elaborate_trait_refs<'cx, 'gcx, 'tcx>(
9696
trait_refs: impl Iterator<Item = ty::PolyTraitRef<'tcx>>)
9797
-> Elaborator<'cx, 'gcx, 'tcx>
9898
{
99-
let predicates = trait_refs.map(|trait_ref| trait_ref.to_predicate())
100-
.collect();
99+
let predicates = trait_refs.map(|trait_ref| trait_ref.to_predicate()).collect();
101100
elaborate_predicates(tcx, predicates)
102101
}
103102

@@ -120,7 +119,7 @@ impl<'cx, 'gcx, 'tcx> Elaborator<'cx, 'gcx, 'tcx> {
120119
let tcx = self.visited.tcx;
121120
match *predicate {
122121
ty::Predicate::Trait(ref data) => {
123-
// Predicates declared on the trait.
122+
// Get predicates declared on the trait.
124123
let predicates = tcx.super_predicates_of(data.def_id());
125124

126125
let mut predicates: Vec<_> = predicates.predicates
@@ -130,12 +129,11 @@ impl<'cx, 'gcx, 'tcx> Elaborator<'cx, 'gcx, 'tcx> {
130129
debug!("super_predicates: data={:?} predicates={:?}",
131130
data, predicates);
132131

133-
// Only keep those bounds that we haven't already
134-
// seen. This is necessary to prevent infinite
135-
// recursion in some cases. One common case is when
136-
// people define `trait Sized: Sized { }` rather than `trait
137-
// Sized { }`.
138-
predicates.retain(|r| self.visited.insert(r));
132+
// Only keep those bounds that we haven't already seen.
133+
// This is necessary to prevent infinite recursion in some
134+
// cases. One common case is when people define
135+
// `trait Sized: Sized { }` rather than `trait Sized { }`.
136+
predicates.retain(|p| self.visited.insert(p));
139137

140138
self.stack.extend(predicates);
141139
}
@@ -161,11 +159,9 @@ impl<'cx, 'gcx, 'tcx> Elaborator<'cx, 'gcx, 'tcx> {
161159
// Currently, we do not elaborate const-evaluatable
162160
// predicates.
163161
}
164-
165162
ty::Predicate::RegionOutlives(..) => {
166163
// Nothing to elaborate from `'a: 'b`.
167164
}
168-
169165
ty::Predicate::TypeOutlives(ref data) => {
170166
// We know that `T: 'a` for some type `T`. We can
171167
// often elaborate this. For example, if we know that
@@ -192,34 +188,35 @@ impl<'cx, 'gcx, 'tcx> Elaborator<'cx, 'gcx, 'tcx> {
192188
tcx.push_outlives_components(ty_max, &mut components);
193189
self.stack.extend(
194190
components
195-
.into_iter()
196-
.filter_map(|component| match component {
197-
Component::Region(r) => if r.is_late_bound() {
198-
None
199-
} else {
200-
Some(ty::Predicate::RegionOutlives(
201-
ty::Binder::dummy(ty::OutlivesPredicate(r, r_min))))
202-
},
203-
204-
Component::Param(p) => {
205-
let ty = tcx.mk_ty_param(p.index, p.name);
206-
Some(ty::Predicate::TypeOutlives(
207-
ty::Binder::dummy(ty::OutlivesPredicate(ty, r_min))))
208-
},
209-
210-
Component::UnresolvedInferenceVariable(_) => {
211-
None
212-
},
213-
214-
Component::Projection(_) |
215-
Component::EscapingProjection(_) => {
216-
// We can probably do more here. This
217-
// corresponds to a case like `<T as
218-
// Foo<'a>>::U: 'b`.
219-
None
220-
},
221-
})
222-
.filter(|p| visited.insert(p)));
191+
.into_iter()
192+
.filter_map(|component| match component {
193+
Component::Region(r) => if r.is_late_bound() {
194+
None
195+
} else {
196+
Some(ty::Predicate::RegionOutlives(
197+
ty::Binder::dummy(ty::OutlivesPredicate(r, r_min))))
198+
}
199+
200+
Component::Param(p) => {
201+
let ty = tcx.mk_ty_param(p.index, p.name);
202+
Some(ty::Predicate::TypeOutlives(
203+
ty::Binder::dummy(ty::OutlivesPredicate(ty, r_min))))
204+
}
205+
206+
Component::UnresolvedInferenceVariable(_) => {
207+
None
208+
}
209+
210+
Component::Projection(_) |
211+
Component::EscapingProjection(_) => {
212+
// We can probably do more here. This
213+
// corresponds to a case like `<T as
214+
// Foo<'a>>::U: 'b`.
215+
None
216+
}
217+
})
218+
.filter(|p| visited.insert(p))
219+
);
223220
}
224221
}
225222
}
@@ -233,16 +230,10 @@ impl<'cx, 'gcx, 'tcx> Iterator for Elaborator<'cx, 'gcx, 'tcx> {
233230
}
234231

235232
fn next(&mut self) -> Option<ty::Predicate<'tcx>> {
236-
// Extract next item from top-most stack frame, if any.
237-
let next_predicate = match self.stack.pop() {
238-
Some(predicate) => predicate,
239-
None => {
240-
// No more stack frames. Done.
241-
return None;
242-
}
243-
};
244-
self.push(&next_predicate);
245-
return Some(next_predicate);
233+
self.stack.pop().map(|item| {
234+
self.push(&item);
235+
item
236+
})
246237
}
247238
}
248239

@@ -254,20 +245,124 @@ pub type Supertraits<'cx, 'gcx, 'tcx> = FilterToTraits<Elaborator<'cx, 'gcx, 'tc
254245

255246
pub fn supertraits<'cx, 'gcx, 'tcx>(tcx: TyCtxt<'cx, 'gcx, 'tcx>,
256247
trait_ref: ty::PolyTraitRef<'tcx>)
257-
-> Supertraits<'cx, 'gcx, 'tcx>
258-
{
248+
-> Supertraits<'cx, 'gcx, 'tcx> {
259249
elaborate_trait_ref(tcx, trait_ref).filter_to_traits()
260250
}
261251

262252
pub fn transitive_bounds<'cx, 'gcx, 'tcx>(tcx: TyCtxt<'cx, 'gcx, 'tcx>,
263253
bounds: impl Iterator<Item = ty::PolyTraitRef<'tcx>>)
264-
-> Supertraits<'cx, 'gcx, 'tcx>
265-
{
254+
-> Supertraits<'cx, 'gcx, 'tcx> {
266255
elaborate_trait_refs(tcx, bounds).filter_to_traits()
267256
}
268257

258+
///////////////////////////////////////////////////////////////////////////
259+
// `TraitRefExpander` iterator
260+
///////////////////////////////////////////////////////////////////////////
261+
262+
/// "Trait reference expansion" is the process of expanding a sequence of trait
263+
/// references into another sequence by transitively following all trait
264+
/// aliases. e.g. If you have bounds like `Foo + Send`, a trait alias
265+
/// `trait Foo = Bar + Sync;`, and another trait alias
266+
/// `trait Bar = Read + Write`, then the bounds would expand to
267+
/// `Read + Write + Sync + Send`.
268+
pub struct TraitRefExpander<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
269+
stack: Vec<TraitRefExpansionInfo<'tcx>>,
270+
visited: PredicateSet<'a, 'gcx, 'tcx>,
271+
}
272+
273+
#[derive(Debug, Clone)]
274+
pub struct TraitRefExpansionInfo<'tcx> {
275+
pub top_level_trait_ref: ty::PolyTraitRef<'tcx>,
276+
pub top_level_span: Span,
277+
pub trait_ref: ty::PolyTraitRef<'tcx>,
278+
pub span: Span,
279+
}
280+
281+
pub fn expand_trait_refs<'cx, 'gcx, 'tcx>(
282+
tcx: TyCtxt<'cx, 'gcx, 'tcx>,
283+
trait_refs: impl IntoIterator<Item = (ty::PolyTraitRef<'tcx>, Span)>
284+
) -> TraitRefExpander<'cx, 'gcx, 'tcx> {
285+
let mut visited = PredicateSet::new(tcx);
286+
let mut items: Vec<_> =
287+
trait_refs
288+
.into_iter()
289+
.map(|(tr, sp)| TraitRefExpansionInfo {
290+
top_level_trait_ref: tr.clone(),
291+
top_level_span: sp,
292+
trait_ref: tr,
293+
span: sp,
294+
})
295+
.collect();
296+
items.retain(|item| visited.insert(&item.trait_ref.to_predicate()));
297+
TraitRefExpander { stack: items, visited: visited, }
298+
}
299+
300+
impl<'cx, 'gcx, 'tcx> TraitRefExpander<'cx, 'gcx, 'tcx> {
301+
// Returns `true` if `item` refers to a trait.
302+
fn push(&mut self, item: &TraitRefExpansionInfo<'tcx>) -> bool {
303+
let tcx = self.visited.tcx;
304+
305+
if !tcx.is_trait_alias(item.trait_ref.def_id()) {
306+
return true;
307+
}
308+
309+
// Get predicates declared on the trait.
310+
let predicates = tcx.super_predicates_of(item.trait_ref.def_id());
311+
312+
let mut items: Vec<_> = predicates.predicates
313+
.iter()
314+
.rev()
315+
.filter_map(|(pred, sp)| {
316+
pred.subst_supertrait(tcx, &item.trait_ref)
317+
.to_opt_poly_trait_ref()
318+
.map(|trait_ref|
319+
TraitRefExpansionInfo {
320+
trait_ref,
321+
span: *sp,
322+
..*item
323+
}
324+
)
325+
})
326+
.collect();
327+
328+
debug!("expand_trait_refs: trait_ref={:?} items={:?}",
329+
item.trait_ref, items);
330+
331+
// Only keep those items that we haven't already seen.
332+
items.retain(|i| self.visited.insert(&i.trait_ref.to_predicate()));
333+
334+
self.stack.extend(items);
335+
false
336+
}
337+
}
338+
339+
impl<'cx, 'gcx, 'tcx> Iterator for TraitRefExpander<'cx, 'gcx, 'tcx> {
340+
type Item = TraitRefExpansionInfo<'tcx>;
341+
342+
fn size_hint(&self) -> (usize, Option<usize>) {
343+
(self.stack.len(), None)
344+
}
345+
346+
fn next(&mut self) -> Option<TraitRefExpansionInfo<'tcx>> {
347+
loop {
348+
let item = self.stack.pop();
349+
match item {
350+
Some(item) => {
351+
if self.push(&item) {
352+
return Some(item);
353+
}
354+
}
355+
None => {
356+
return None;
357+
}
358+
}
359+
}
360+
}
361+
}
362+
269363
///////////////////////////////////////////////////////////////////////////
270364
// Iterator over def-ids of supertraits
365+
///////////////////////////////////////////////////////////////////////////
271366

272367
pub struct SupertraitDefIds<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
273368
tcx: TyCtxt<'a, 'gcx, 'tcx>,

0 commit comments

Comments
 (0)