@@ -21,11 +21,13 @@ use super::elaborate_predicates;
2121
2222use hir:: def_id:: DefId ;
2323use 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 } ;
2627use ty:: util:: ExplicitSelf ;
2728use std:: borrow:: Cow ;
28- use syntax:: ast;
29+ use std:: iter:: { self } ;
30+ use syntax:: ast:: { self , Name } ;
2931use syntax_pos:: Span ;
3032
3133#[ derive( Copy , Clone , Debug , PartialEq , Eq , Hash ) ]
@@ -62,8 +64,8 @@ impl ObjectSafetyViolation {
6264 format ! ( "method `{}` references the `Self` type in where clauses" , name) . into ( ) ,
6365 ObjectSafetyViolation :: Method ( name, MethodViolationCode :: Generic ) =>
6466 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 ( ) ,
6769 ObjectSafetyViolation :: AssociatedConst ( name) =>
6870 format ! ( "the trait cannot contain associated consts like `{}`" , name) . into ( ) ,
6971 }
@@ -85,8 +87,8 @@ pub enum MethodViolationCode {
8587 /// e.g., `fn foo<A>()`
8688 Generic ,
8789
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 ,
9092}
9193
9294impl < ' a , ' tcx > TyCtxt < ' a , ' tcx , ' tcx > {
@@ -280,23 +282,20 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {
280282 method : & ty:: AssociatedItem )
281283 -> Option < MethodViolationCode >
282284 {
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`
286286 if !method. method_has_self_argument {
287287 return Some ( MethodViolationCode :: StaticMethod ) ;
288288 }
289289
290290 let sig = self . fn_sig ( method. def_id ) ;
291291
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 ) ;
296296 }
297297
298- // The `Self` type is erased, so it should not appear in list of
299- // arguments or return type apart from the receiver.
298+
300299 for input_ty in & sig. skip_binder ( ) . inputs ( ) [ 1 ..] {
301300 if self . contains_illegal_self_type_reference ( trait_def_id, input_ty) {
302301 return Some ( MethodViolationCode :: ReferencesSelf ) ;
@@ -326,6 +325,83 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {
326325 None
327326 }
328327
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+
329405 fn contains_illegal_self_type_reference ( self ,
330406 trait_def_id : DefId ,
331407 ty : Ty < ' tcx > )
0 commit comments