@@ -21,11 +21,13 @@ use super::elaborate_predicates;
21
21
22
22
use hir:: def_id:: DefId ;
23
23
use lint;
24
- use traits;
25
- use ty:: { self , Ty , TyCtxt , TypeFoldable } ;
24
+ use traits:: { self , Obligation , ObligationCause } ;
25
+ use ty:: { self , Ty , TyCtxt , TypeFoldable , Predicate , ToPredicate } ;
26
+ use ty:: subst:: { Subst , Substs } ;
26
27
use ty:: util:: ExplicitSelf ;
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 > {
@@ -280,23 +282,20 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {
280
282
method : & ty:: AssociatedItem )
281
283
-> Option < MethodViolationCode >
282
284
{
283
- // The method's first parameter must be something that derefs (or
284
- // autorefs) to `&self`. For now, we only accept `self`, `&self`
285
- // and `Box<Self>`.
285
+ // The method's first parameter must be named `self`
286
286
if !method. method_has_self_argument {
287
287
return Some ( MethodViolationCode :: StaticMethod ) ;
288
288
}
289
289
290
290
let sig = self . fn_sig ( method. def_id ) ;
291
291
292
- let self_ty = self . mk_self_type ( ) ;
293
- let self_arg_ty = sig . skip_binder ( ) . inputs ( ) [ 0 ] ;
294
- if let ExplicitSelf :: Other = ExplicitSelf :: determine ( self_arg_ty , |ty| ty == self_ty ) {
295
- return Some ( MethodViolationCode :: NonStandardSelfType ) ;
292
+ let receiver_ty = sig . skip_binder ( ) . inputs ( ) [ 0 ] ;
293
+
294
+ if ! self . receiver_is_coercible ( method , receiver_ty ) {
295
+ return Some ( MethodViolationCode :: UncoercibleReceiver ) ;
296
296
}
297
297
298
- // The `Self` type is erased, so it should not appear in list of
299
- // arguments or return type apart from the receiver.
298
+
300
299
for input_ty in & sig. skip_binder ( ) . inputs ( ) [ 1 ..] {
301
300
if self . contains_illegal_self_type_reference ( trait_def_id, input_ty) {
302
301
return Some ( MethodViolationCode :: ReferencesSelf ) ;
@@ -326,6 +325,83 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {
326
325
None
327
326
}
328
327
328
+ // checks the type of the self argument, and makes sure it implements
329
+ // the CoerceUnsized requirement:
330
+ // forall (U) {
331
+ // if (Self: Unsize<U>) {
332
+ // Receiver: CoerceUnsized<Receiver<Self=U>>
333
+ // }
334
+ // }
335
+ #[ allow( dead_code) ]
336
+ fn receiver_is_coercible (
337
+ self ,
338
+ method : & ty:: AssociatedItem ,
339
+ receiver_ty : Ty < ' tcx >
340
+ ) -> bool
341
+ {
342
+ let traits = ( self . lang_items ( ) . unsize_trait ( ) ,
343
+ self . lang_items ( ) . coerce_unsized_trait ( ) ) ;
344
+ let ( unsize_did, coerce_unsized_did) = if let ( Some ( u) , Some ( cu) ) = traits {
345
+ ( u, cu)
346
+ } else {
347
+ debug ! ( "receiver_is_coercible: Missing Unsize or CoerceUnsized traits" ) ;
348
+ return false ;
349
+ } ;
350
+
351
+ // use a bogus type parameter to mimick a forall(U) query
352
+ // using u32::MAX for now. This is BAD and will probably break when
353
+ // this method is called recursively, or at least if someone does a hacky thing
354
+ // like this elsewhere in the compiler
355
+ let target_self_ty: Ty < ' tcx > = self . mk_ty_param (
356
+ :: std:: u32:: MAX ,
357
+ Name :: intern ( "mikeyhewROCKS" ) . as_interned_str ( ) ,
358
+ ) ;
359
+
360
+ // create a modified param env, with
361
+ // `Self: Unsize<U>` added to the caller bounds
362
+ let param_env = {
363
+ let mut param_env = self . param_env ( method. def_id ) ;
364
+
365
+ let predicate = ty:: TraitRef {
366
+ def_id : unsize_did,
367
+ substs : self . mk_substs_trait ( self . mk_self_type ( ) , & [ target_self_ty. into ( ) ] ) ,
368
+ } . to_predicate ( ) ;
369
+
370
+ let caller_bounds: Vec < Predicate < ' tcx > > = param_env. caller_bounds . iter ( ) . cloned ( )
371
+ . chain ( iter:: once ( predicate) )
372
+ . collect ( ) ;
373
+
374
+ param_env. caller_bounds = self . intern_predicates ( & caller_bounds) ;
375
+
376
+ param_env
377
+ } ;
378
+
379
+ // the type `Receiver<Self=U>` in the query
380
+ let target_receiver_ty = receiver_ty. subst (
381
+ self ,
382
+ self . mk_substs_trait ( target_self_ty, & [ ] ) ,
383
+ ) ;
384
+
385
+ // Receiver: CoerceUnsized<Receiver<Self=U>>
386
+ let obligation = {
387
+ let predicate = ty:: TraitRef {
388
+ def_id : coerce_unsized_did,
389
+ substs : self . mk_substs_trait ( self . mk_self_type ( ) , & [ target_receiver_ty. into ( ) ] ) ,
390
+ } . to_predicate ( ) ;
391
+
392
+ Obligation :: new (
393
+ ObligationCause :: dummy ( ) ,
394
+ param_env,
395
+ predicate,
396
+ )
397
+ } ;
398
+
399
+ // return whether `Receiver: CoerceUnsized<Receiver<Self=U>>` holds
400
+ self . infer_ctxt ( ) . enter ( |ref infcx| {
401
+ infcx. predicate_must_hold ( & obligation)
402
+ } )
403
+ }
404
+
329
405
fn contains_illegal_self_type_reference ( self ,
330
406
trait_def_id : DefId ,
331
407
ty : Ty < ' tcx > )
0 commit comments