13
13
//! object if all of their methods meet certain criteria. In particular,
14
14
//! they must:
15
15
//!
16
- //! - have a suitable receiver from which we can extract a vtable;
16
+ //! - have a suitable receiver from which we can extract a vtable and coerce to a "thin" version
17
+ //! that doesn't contain the vtable;
17
18
//! - not reference the erased type `Self` except for in this receiver;
18
19
//! - not have generic type parameters
19
20
20
21
use super :: elaborate_predicates;
21
22
22
23
use hir:: def_id:: DefId ;
23
24
use lint;
24
- use traits;
25
- use ty:: { self , Ty , TyCtxt , TypeFoldable } ;
26
- use ty:: util :: ExplicitSelf ;
25
+ use traits:: { self , Obligation , ObligationCause } ;
26
+ use ty:: { self , Ty , TyCtxt , TypeFoldable , Predicate , ToPredicate } ;
27
+ use ty:: subst :: { Subst , Substs } ;
27
28
use std:: borrow:: Cow ;
28
- use syntax:: ast;
29
+ use std:: iter:: { self } ;
30
+ use syntax:: ast:: { self , Name } ;
29
31
use syntax_pos:: Span ;
30
32
31
33
#[ derive( Copy , Clone , Debug , PartialEq , Eq , Hash ) ]
@@ -62,8 +64,8 @@ impl ObjectSafetyViolation {
62
64
format ! ( "method `{}` references the `Self` type in where clauses" , name) . into ( ) ,
63
65
ObjectSafetyViolation :: Method ( name, MethodViolationCode :: Generic ) =>
64
66
format ! ( "method `{}` has generic type parameters" , name) . into ( ) ,
65
- ObjectSafetyViolation :: Method ( name, MethodViolationCode :: NonStandardSelfType ) =>
66
- format ! ( "method `{}` has a non-standard `self` type" , name) . into ( ) ,
67
+ ObjectSafetyViolation :: Method ( name, MethodViolationCode :: UncoercibleReceiver ) =>
68
+ format ! ( "method `{}` has an uncoercible receiver type" , name) . into ( ) ,
67
69
ObjectSafetyViolation :: AssociatedConst ( name) =>
68
70
format ! ( "the trait cannot contain associated consts like `{}`" , name) . into ( ) ,
69
71
}
@@ -85,8 +87,8 @@ pub enum MethodViolationCode {
85
87
/// e.g., `fn foo<A>()`
86
88
Generic ,
87
89
88
- /// arbitrary ` self` type, e.g. `self: Rc< Self>`
89
- NonStandardSelfType ,
90
+ /// the self argument can't be coerced from Self=dyn Trait to Self=T where T: Trait
91
+ UncoercibleReceiver ,
90
92
}
91
93
92
94
impl < ' a , ' tcx > TyCtxt < ' a , ' tcx , ' tcx > {
@@ -113,6 +115,8 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {
113
115
pub fn object_safety_violations ( self , trait_def_id : DefId )
114
116
-> Vec < ObjectSafetyViolation >
115
117
{
118
+ debug ! ( "object_safety_violations: {:?}" , trait_def_id) ;
119
+
116
120
traits:: supertrait_def_ids ( self , trait_def_id)
117
121
. flat_map ( |def_id| self . object_safety_violations_for_trait ( def_id) )
118
122
. collect ( )
@@ -277,23 +281,13 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {
277
281
method : & ty:: AssociatedItem )
278
282
-> Option < MethodViolationCode >
279
283
{
280
- // The method's first parameter must be something that derefs (or
281
- // autorefs) to `&self`. For now, we only accept `self`, `&self`
282
- // and `Box<Self>`.
284
+ // The method's first parameter must be named `self`
283
285
if !method. method_has_self_argument {
284
286
return Some ( MethodViolationCode :: StaticMethod ) ;
285
287
}
286
288
287
289
let sig = self . fn_sig ( method. def_id ) ;
288
290
289
- let self_ty = self . mk_self_type ( ) ;
290
- let self_arg_ty = sig. skip_binder ( ) . inputs ( ) [ 0 ] ;
291
- if let ExplicitSelf :: Other = ExplicitSelf :: determine ( self_arg_ty, |ty| ty == self_ty) {
292
- return Some ( MethodViolationCode :: NonStandardSelfType ) ;
293
- }
294
-
295
- // The `Self` type is erased, so it should not appear in list of
296
- // arguments or return type apart from the receiver.
297
291
for input_ty in & sig. skip_binder ( ) . inputs ( ) [ 1 ..] {
298
292
if self . contains_illegal_self_type_reference ( trait_def_id, input_ty) {
299
293
return Some ( MethodViolationCode :: ReferencesSelf ) ;
@@ -320,9 +314,139 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {
320
314
return Some ( MethodViolationCode :: WhereClauseReferencesSelf ( span) ) ;
321
315
}
322
316
317
+ let receiver_ty = self . liberate_late_bound_regions (
318
+ method. def_id ,
319
+ & sig. map_bound ( |sig| sig. inputs ( ) [ 0 ] ) ,
320
+ ) ;
321
+
322
+ // until `unsized_locals` is fully implemented, `self: Self` can't be coerced from
323
+ // `Self=dyn Trait` to `Self=T`. However, this is already considered object-safe. We allow
324
+ // it as a special case here.
325
+ // FIXME(mikeyhew) get rid of this `if` statement once `receiver_is_coercible` allows
326
+ // `Receiver: Unsize<Receiver[Self => dyn Trait]>`
327
+ if receiver_ty != self . mk_self_type ( ) {
328
+ if !self . receiver_is_coercible ( method, receiver_ty) {
329
+ return Some ( MethodViolationCode :: UncoercibleReceiver ) ;
330
+ }
331
+ }
332
+
323
333
None
324
334
}
325
335
336
+ /// checks the method's receiver (the `self` argument) can be coerced from
337
+ /// a fat pointer, including the trait object vtable, to a thin pointer.
338
+ /// e.g. from `Rc<dyn Trait>` to `Rc<T>`, where `T` is the erased type of the underlying object.
339
+ /// More formally:
340
+ /// - let `Receiver` be the type of the `self` argument, i.e `Self`, `&Self`, `Rc<Self>`
341
+ /// - require the following bound:
342
+ /// forall(T: Trait) {
343
+ /// Receiver[Self => dyn Trait]: CoerceSized<Receiver[Self => T]>
344
+ /// }
345
+ /// where `Foo[X => Y]` means "the same type as `Foo`, but with `X` replaced with `Y`"
346
+ /// (substitution notation).
347
+ ///
348
+ /// some examples of receiver types and their required obligation
349
+ /// - `&'a mut self` requires `&'a mut dyn Trait: CoerceSized<&'a mut T>`
350
+ /// - `self: Rc<Self>` requires `Rc<dyn Trait>: CoerceSized<Rc<T>>`
351
+ ///
352
+ /// The only case where the receiver is not coercible, but is still a valid receiver
353
+ /// type (just not object-safe), is when there is more than one level of pointer indirection.
354
+ /// e.g. `self: &&Self`, `self: &Rc<Self>`, `self: Box<Box<Self>>`. In these cases, there
355
+ /// is no way, or at least no inexpensive way, to coerce the receiver, because the object that
356
+ /// needs to be coerced is behind a pointer.
357
+ ///
358
+ /// In practice, there are issues with the above bound: `where` clauses that apply to `Self`
359
+ /// would have to apply to `T`, trait object types have a lot of parameters that need to
360
+ /// be filled in (lifetime and type parameters, and the lifetime of the actual object), and
361
+ /// I'm pretty sure using `dyn Trait` in the query causes another object-safety query for
362
+ /// `Trait`, resulting in cyclic queries. So in the implementation, we use the following,
363
+ /// more general bound:
364
+ ///
365
+ /// forall (U: ?Sized) {
366
+ /// if (Self: Unsize<U>) {
367
+ /// Receiver[Self => U]: CoerceSized<Receiver>
368
+ /// }
369
+ /// }
370
+ ///
371
+ /// for `self: &'a mut Self`, this means `&'a mut U: CoerceSized<&'a mut Self>`
372
+ /// for `self: Rc<Self>`, this means `Rc<U>: CoerceSized<Rc<Self>>`
373
+ //
374
+ // FIXME(mikeyhew) when unsized receivers are implemented as part of unsized rvalues, add this
375
+ // fallback query: `Receiver: Unsize<Receiver[Self => U]>` to support receivers like
376
+ // `self: Wrapper<Self>`.
377
+ #[ allow( dead_code) ]
378
+ fn receiver_is_coercible (
379
+ self ,
380
+ method : & ty:: AssociatedItem ,
381
+ receiver_ty : Ty < ' tcx > ,
382
+ ) -> bool {
383
+ debug ! ( "receiver_is_coercible: method = {:?}, receiver_ty = {:?}" , method, receiver_ty) ;
384
+
385
+ let traits = ( self . lang_items ( ) . unsize_trait ( ) ,
386
+ self . lang_items ( ) . coerce_sized_trait ( ) ) ;
387
+ let ( unsize_did, coerce_sized_did) = if let ( Some ( u) , Some ( cu) ) = traits {
388
+ ( u, cu)
389
+ } else {
390
+ debug ! ( "receiver_is_coercible: Missing Unsize or CoerceSized traits" ) ;
391
+ return false ;
392
+ } ;
393
+
394
+ // use a bogus type parameter to mimick a forall(U) query using u32::MAX for now.
395
+ // FIXME(mikeyhew) this is a total hack, and we should replace it when real forall queries
396
+ // are implemented
397
+ let target_self_ty: Ty < ' tcx > = self . mk_ty_param (
398
+ :: std:: u32:: MAX ,
399
+ Name :: intern ( "RustaceansAreAwesome" ) . as_interned_str ( ) ,
400
+ ) ;
401
+
402
+ // create a modified param env, with `Self: Unsize<U>` added to the caller bounds
403
+ let param_env = {
404
+ let mut param_env = self . param_env ( method. def_id ) ;
405
+
406
+ let predicate = ty:: TraitRef {
407
+ def_id : unsize_did,
408
+ substs : self . mk_substs_trait ( self . mk_self_type ( ) , & [ target_self_ty. into ( ) ] ) ,
409
+ } . to_predicate ( ) ;
410
+
411
+ let caller_bounds: Vec < Predicate < ' tcx > > = param_env. caller_bounds . iter ( ) . cloned ( )
412
+ . chain ( iter:: once ( predicate) )
413
+ . collect ( ) ;
414
+
415
+ param_env. caller_bounds = self . intern_predicates ( & caller_bounds) ;
416
+
417
+ param_env
418
+ } ;
419
+
420
+ let receiver_substs = Substs :: for_item ( self , method. def_id , |param, _| {
421
+ if param. index == 0 {
422
+ target_self_ty. into ( )
423
+ } else {
424
+ self . mk_param_from_def ( param)
425
+ }
426
+ } ) ;
427
+ // the type `Receiver[Self => U]` in the query
428
+ let unsized_receiver_ty = receiver_ty. subst ( self , receiver_substs) ;
429
+
430
+ // Receiver[Self => U]: CoerceSized<Receiver>
431
+ let obligation = {
432
+ let predicate = ty:: TraitRef {
433
+ def_id : coerce_sized_did,
434
+ substs : self . mk_substs_trait ( unsized_receiver_ty, & [ receiver_ty. into ( ) ] ) ,
435
+ } . to_predicate ( ) ;
436
+
437
+ Obligation :: new (
438
+ ObligationCause :: dummy ( ) ,
439
+ param_env,
440
+ predicate,
441
+ )
442
+ } ;
443
+
444
+ self . infer_ctxt ( ) . enter ( |ref infcx| {
445
+ // the receiver is coercible iff the obligation holds
446
+ infcx. predicate_must_hold ( & obligation)
447
+ } )
448
+ }
449
+
326
450
fn contains_illegal_self_type_reference ( self ,
327
451
trait_def_id : DefId ,
328
452
ty : Ty < ' tcx > )
0 commit comments