Skip to content

Commit a842069

Browse files
committed
---
yaml --- r: 167387 b: refs/heads/snap-stage3 c: 5b53b11 h: refs/heads/master i: 167385: 5bfe9f4 167383: a778e7e v: v3
1 parent 3d2fbb4 commit a842069

File tree

2 files changed

+99
-6
lines changed

2 files changed

+99
-6
lines changed

[refs]

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
---
22
refs/heads/master: 023dfb0c898d851dee6ace2f8339b73b5287136b
33
refs/heads/snap-stage1: e33de59e47c5076a89eadeb38f4934f58a3618a6
4-
refs/heads/snap-stage3: becbd81aaa1b8c60eb13fee898163d1a2ac33de3
4+
refs/heads/snap-stage3: 5b53b11ad9aed822ce4c573714de6cb28289f321
55
refs/heads/try: 5204084bd2e46af7cc6e0147430e44dd0d657bbb
66
refs/tags/release-0.1: 1f5c5126e96c79d22cb7862f75304136e204f105
77
refs/heads/dist-snap: ba4081a5a8573875fed17545846f6f6902c8ba8d

branches/snap-stage3/src/librustc_typeck/check/vtable.rs

Lines changed: 98 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
// except according to those terms.
1010

1111
use check::{FnCtxt, structurally_resolved_type};
12-
use middle::subst::{FnSpace};
12+
use middle::subst::{FnSpace, SelfSpace};
1313
use middle::traits;
1414
use middle::traits::{Obligation, ObligationCause};
1515
use middle::traits::report_fulfillment_errors;
@@ -141,15 +141,15 @@ pub fn check_object_safety<'tcx>(tcx: &ty::ctxt<'tcx>,
141141
}
142142

143143
fn check_object_safety_inner<'tcx>(tcx: &ty::ctxt<'tcx>,
144-
object_trait: &ty::PolyTraitRef<'tcx>,
145-
span: Span) {
144+
object_trait: &ty::PolyTraitRef<'tcx>,
145+
span: Span) {
146146
let trait_items = ty::trait_items(tcx, object_trait.def_id());
147147

148148
let mut errors = Vec::new();
149149
for item in trait_items.iter() {
150150
match *item {
151151
ty::MethodTraitItem(ref m) => {
152-
errors.push(check_object_safety_of_method(tcx, &**m))
152+
errors.push(check_object_safety_of_method(tcx, object_trait, &**m))
153153
}
154154
ty::TypeTraitItem(_) => {}
155155
}
@@ -173,6 +173,7 @@ fn check_object_safety_inner<'tcx>(tcx: &ty::ctxt<'tcx>,
173173
/// type is not known (that's the whole point of a trait instance, after all, to obscure the
174174
/// self type) and (b) the call must go through a vtable and hence cannot be monomorphized.
175175
fn check_object_safety_of_method<'tcx>(tcx: &ty::ctxt<'tcx>,
176+
object_trait: &ty::PolyTraitRef<'tcx>,
176177
method: &ty::Method<'tcx>)
177178
-> Vec<String> {
178179
let mut msgs = Vec::new();
@@ -196,7 +197,7 @@ fn check_object_safety_inner<'tcx>(tcx: &ty::ctxt<'tcx>,
196197

197198
// reason (a) above
198199
let check_for_self_ty = |ty| {
199-
if ty::type_has_self(ty) {
200+
if contains_illegal_self_type_reference(tcx, object_trait.def_id(), ty) {
200201
Some(format!(
201202
"cannot call a method (`{}`) whose type contains \
202203
a self-type (`{}`) through a trait object",
@@ -225,6 +226,98 @@ fn check_object_safety_inner<'tcx>(tcx: &ty::ctxt<'tcx>,
225226

226227
msgs
227228
}
229+
230+
fn contains_illegal_self_type_reference<'tcx>(tcx: &ty::ctxt<'tcx>,
231+
trait_def_id: ast::DefId,
232+
ty: Ty<'tcx>)
233+
-> bool
234+
{
235+
// This is somewhat subtle. In general, we want to forbid
236+
// references to `Self` in the argument and return types,
237+
// since the value of `Self` is erased. However, there is one
238+
// exception: it is ok to reference `Self` in order to access
239+
// an associated type of the current trait, since we retain
240+
// the value of those associated types in the object type
241+
// itself.
242+
//
243+
// ```rust
244+
// trait SuperTrait {
245+
// type X;
246+
// }
247+
//
248+
// trait Trait : SuperTrait {
249+
// type Y;
250+
// fn foo(&self, x: Self) // bad
251+
// fn foo(&self) -> Self // bad
252+
// fn foo(&self) -> Option<Self> // bad
253+
// fn foo(&self) -> Self::Y // OK, desugars to next example
254+
// fn foo(&self) -> <Self as Trait>::Y // OK
255+
// fn foo(&self) -> Self::X // OK, desugars to next example
256+
// fn foo(&self) -> <Self as SuperTrait>::X // OK
257+
// }
258+
// ```
259+
//
260+
// However, it is not as simple as allowing `Self` in a projected
261+
// type, because there are illegal ways to use `Self` as well:
262+
//
263+
// ```rust
264+
// trait Trait : SuperTrait {
265+
// ...
266+
// fn foo(&self) -> <Self as SomeOtherTrait>::X;
267+
// }
268+
// ```
269+
//
270+
// Here we will not have the type of `X` recorded in the
271+
// object type, and we cannot resolve `Self as SomeOtherTrait`
272+
// without knowing what `Self` is.
273+
274+
let mut supertraits: Option<Vec<ty::PolyTraitRef<'tcx>>> = None;
275+
let mut error = false;
276+
ty::maybe_walk_ty(ty, |ty| {
277+
match ty.sty {
278+
ty::ty_param(ref param_ty) => {
279+
if param_ty.space == SelfSpace {
280+
error = true;
281+
}
282+
283+
false // no contained types to walk
284+
}
285+
286+
ty::ty_projection(ref data) => {
287+
// This is a projected type `<Foo as SomeTrait>::X`.
288+
289+
// Compute supertraits of current trait lazilly.
290+
if supertraits.is_none() {
291+
let trait_def = ty::lookup_trait_def(tcx, trait_def_id);
292+
let trait_ref = ty::Binder(trait_def.trait_ref.clone());
293+
supertraits = Some(traits::supertraits(tcx, trait_ref).collect());
294+
}
295+
296+
// Determine whether the trait reference `Foo as
297+
// SomeTrait` is in fact a supertrait of the
298+
// current trait. In that case, this type is
299+
// legal, because the type `X` will be specified
300+
// in the object type. Note that we can just use
301+
// direct equality here because all of these types
302+
// are part of the formal parameter listing, and
303+
// hence there should be no inference variables.
304+
let projection_trait_ref = ty::Binder(data.trait_ref.clone());
305+
let is_supertrait_of_current_trait =
306+
supertraits.as_ref().unwrap().contains(&projection_trait_ref);
307+
308+
if is_supertrait_of_current_trait {
309+
false // do not walk contained types, do not report error, do collect $200
310+
} else {
311+
true // DO walk contained types, POSSIBLY reporting an error
312+
}
313+
}
314+
315+
_ => true, // walk contained types, if any
316+
}
317+
});
318+
319+
error
320+
}
228321
}
229322

230323
pub fn register_object_cast_obligations<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,

0 commit comments

Comments
 (0)