@@ -13,6 +13,7 @@ use super::elaborate_predicates;
13
13
use crate :: traits:: { self , Obligation , ObligationCause } ;
14
14
use crate :: ty:: subst:: { InternalSubsts , Subst } ;
15
15
use crate :: ty:: { self , Predicate , ToPredicate , Ty , TyCtxt , TypeFoldable , WithConstness } ;
16
+ use rustc_errors:: Applicability ;
16
17
use rustc_hir as hir;
17
18
use rustc_hir:: def_id:: DefId ;
18
19
use rustc_session:: lint:: builtin:: WHERE_CLAUSES_OBJECT_SAFETY ;
@@ -48,14 +49,20 @@ impl ObjectSafetyViolation {
48
49
"it cannot use `Self` as a type parameter in the supertraits or `where`-clauses"
49
50
. into ( )
50
51
}
51
- ObjectSafetyViolation :: Method ( name, MethodViolationCode :: StaticMethod , _) => {
52
+ ObjectSafetyViolation :: Method ( name, MethodViolationCode :: StaticMethod ( _ ) , _) => {
52
53
format ! ( "associated function `{}` has no `self` parameter" , name) . into ( )
53
54
}
54
- ObjectSafetyViolation :: Method ( name, MethodViolationCode :: ReferencesSelf , _) => format ! (
55
- "method `{}` references the `Self` type in its parameters or return type" ,
55
+ ObjectSafetyViolation :: Method (
56
56
name,
57
- )
58
- . into ( ) ,
57
+ MethodViolationCode :: ReferencesSelfInput ( _) ,
58
+ DUMMY_SP ,
59
+ ) => format ! ( "method `{}` references the `Self` type in its parameters" , name) . into ( ) ,
60
+ ObjectSafetyViolation :: Method ( name, MethodViolationCode :: ReferencesSelfInput ( _) , _) => {
61
+ format ! ( "method `{}` references the `Self` type in this parameter" , name) . into ( )
62
+ }
63
+ ObjectSafetyViolation :: Method ( name, MethodViolationCode :: ReferencesSelfOutput , _) => {
64
+ format ! ( "method `{}` references the `Self` type in its return type" , name) . into ( )
65
+ }
59
66
ObjectSafetyViolation :: Method (
60
67
name,
61
68
MethodViolationCode :: WhereClauseReferencesSelf ,
@@ -78,23 +85,31 @@ impl ObjectSafetyViolation {
78
85
}
79
86
}
80
87
81
- pub fn solution ( & self ) -> Option < String > {
88
+ pub fn solution ( & self ) -> Option < ( String , Option < ( String , Span ) > ) > {
82
89
Some ( match * self {
83
90
ObjectSafetyViolation :: SizedSelf ( _) | ObjectSafetyViolation :: SupertraitSelf => {
84
91
return None ;
85
92
}
86
- ObjectSafetyViolation :: Method ( name, MethodViolationCode :: StaticMethod , _) => format ! (
87
- "consider turning `{}` into a method by giving it a `&self` argument or \
88
- constraining it with `where Self: Sized`",
89
- name
93
+ ObjectSafetyViolation :: Method ( name, MethodViolationCode :: StaticMethod ( sugg) , _) => (
94
+ format ! (
95
+ "consider turning `{}` into a method by giving it a `&self` argument or \
96
+ constraining it so it does not apply to trait objects",
97
+ name
98
+ ) ,
99
+ sugg. map ( |( sugg, sp) | ( sugg. to_string ( ) , sp) ) ,
90
100
) ,
91
- ObjectSafetyViolation :: Method ( name, MethodViolationCode :: UndispatchableReceiver , _) => {
101
+ ObjectSafetyViolation :: Method (
102
+ name,
103
+ MethodViolationCode :: UndispatchableReceiver ,
104
+ span,
105
+ ) => (
92
106
format ! ( "consider changing method `{}`'s `self` parameter to be `&self`" , name)
93
- . into ( )
94
- }
107
+ . into ( ) ,
108
+ Some ( ( "&Self" . to_string ( ) , span) ) ,
109
+ ) ,
95
110
ObjectSafetyViolation :: AssocConst ( name, _)
96
111
| ObjectSafetyViolation :: Method ( name, ..) => {
97
- format ! ( "consider moving `{}` to another trait" , name)
112
+ ( format ! ( "consider moving `{}` to another trait" , name) , None )
98
113
}
99
114
} )
100
115
}
@@ -119,10 +134,13 @@ impl ObjectSafetyViolation {
119
134
#[ derive( Copy , Clone , Debug , PartialEq , Eq , Hash ) ]
120
135
pub enum MethodViolationCode {
121
136
/// e.g., `fn foo()`
122
- StaticMethod ,
137
+ StaticMethod ( Option < ( & ' static str , Span ) > ) ,
138
+
139
+ /// e.g., `fn foo(&self, x: Self)`
140
+ ReferencesSelfInput ( usize ) ,
123
141
124
- /// e.g., `fn foo(&self, x: Self)` or `fn foo(&self ) -> Self`
125
- ReferencesSelf ,
142
+ /// e.g., `fn foo(&self) -> Self`
143
+ ReferencesSelfOutput ,
126
144
127
145
/// e.g., `fn foo(&self) where Self: Clone`
128
146
WhereClauseReferencesSelf ,
@@ -193,7 +211,7 @@ fn object_safety_violations_for_trait(
193
211
. filter ( |item| item. kind == ty:: AssocKind :: Method )
194
212
. filter_map ( |item| {
195
213
object_safety_violation_for_method ( tcx, trait_def_id, & item)
196
- . map ( |code| ObjectSafetyViolation :: Method ( item. ident . name , code, item . ident . span ) )
214
+ . map ( |( code, span ) | ObjectSafetyViolation :: Method ( item. ident . name , code, span) )
197
215
} )
198
216
. filter ( |violation| {
199
217
if let ObjectSafetyViolation :: Method (
@@ -224,9 +242,15 @@ fn object_safety_violations_for_trait(
224
242
)
225
243
} ;
226
244
err. span_label ( * span, & msg) ;
227
- if let ( Some ( _) , Some ( note) ) = ( node, violation. solution ( ) ) {
245
+ match ( node, violation. solution ( ) ) {
246
+ ( Some ( _) , Some ( ( note, None ) ) ) => {
247
+ err. help ( & note) ;
248
+ }
249
+ ( Some ( _) , Some ( ( note, Some ( ( sugg, span) ) ) ) ) => {
250
+ err. span_suggestion ( span, & note, sugg, Applicability :: MachineApplicable ) ;
251
+ }
228
252
// Only provide the help if its a local trait, otherwise it's not actionable.
229
- err . help ( & note ) ;
253
+ _ => { }
230
254
}
231
255
err. emit ( ) ;
232
256
false
@@ -398,15 +422,34 @@ fn object_safety_violation_for_method(
398
422
tcx : TyCtxt < ' _ > ,
399
423
trait_def_id : DefId ,
400
424
method : & ty:: AssocItem ,
401
- ) -> Option < MethodViolationCode > {
425
+ ) -> Option < ( MethodViolationCode , Span ) > {
402
426
debug ! ( "object_safety_violation_for_method({:?}, {:?})" , trait_def_id, method) ;
403
427
// Any method that has a `Self : Sized` requisite is otherwise
404
428
// exempt from the regulations.
405
429
if generics_require_sized_self ( tcx, method. def_id ) {
406
430
return None ;
407
431
}
408
432
409
- virtual_call_violation_for_method ( tcx, trait_def_id, method)
433
+ let violation = virtual_call_violation_for_method ( tcx, trait_def_id, method) ;
434
+ // Get an accurate span depending on the violation.
435
+ violation. map ( |v| {
436
+ let node = tcx. hir ( ) . get_if_local ( method. def_id ) ;
437
+ let span = match ( v, node) {
438
+ ( MethodViolationCode :: ReferencesSelfInput ( arg) , Some ( node) ) => node
439
+ . fn_decl ( )
440
+ . and_then ( |decl| decl. inputs . get ( arg + 1 ) )
441
+ . map_or ( method. ident . span , |arg| arg. span ) ,
442
+ ( MethodViolationCode :: UndispatchableReceiver , Some ( node) ) => node
443
+ . fn_decl ( )
444
+ . and_then ( |decl| decl. inputs . get ( 0 ) )
445
+ . map_or ( method. ident . span , |arg| arg. span ) ,
446
+ ( MethodViolationCode :: ReferencesSelfOutput , Some ( node) ) => {
447
+ node. fn_decl ( ) . map_or ( method. ident . span , |decl| decl. output . span ( ) )
448
+ }
449
+ _ => method. ident . span ,
450
+ } ;
451
+ ( v, span)
452
+ } )
410
453
}
411
454
412
455
/// Returns `Some(_)` if this method cannot be called on a trait
@@ -420,18 +463,26 @@ fn virtual_call_violation_for_method<'tcx>(
420
463
) -> Option < MethodViolationCode > {
421
464
// The method's first parameter must be named `self`
422
465
if !method. method_has_self_argument {
423
- return Some ( MethodViolationCode :: StaticMethod ) ;
466
+ // We'll attempt to provide a structured suggestion for `Self: Sized`.
467
+ let sugg =
468
+ tcx. hir ( ) . get_if_local ( method. def_id ) . as_ref ( ) . and_then ( |node| node. generics ( ) ) . map (
469
+ |generics| match generics. where_clause . predicates {
470
+ [ ] => ( " where Self: Sized" , generics. where_clause . span ) ,
471
+ [ .., pred] => ( ", Self: Sized" , pred. span ( ) . shrink_to_hi ( ) ) ,
472
+ } ,
473
+ ) ;
474
+ return Some ( MethodViolationCode :: StaticMethod ( sugg) ) ;
424
475
}
425
476
426
477
let sig = tcx. fn_sig ( method. def_id ) ;
427
478
428
- for input_ty in & sig. skip_binder ( ) . inputs ( ) [ 1 ..] {
479
+ for ( i , input_ty) in sig. skip_binder ( ) . inputs ( ) [ 1 ..] . iter ( ) . enumerate ( ) {
429
480
if contains_illegal_self_type_reference ( tcx, trait_def_id, input_ty) {
430
- return Some ( MethodViolationCode :: ReferencesSelf ) ;
481
+ return Some ( MethodViolationCode :: ReferencesSelfInput ( i ) ) ;
431
482
}
432
483
}
433
484
if contains_illegal_self_type_reference ( tcx, trait_def_id, sig. output ( ) . skip_binder ( ) ) {
434
- return Some ( MethodViolationCode :: ReferencesSelf ) ;
485
+ return Some ( MethodViolationCode :: ReferencesSelfOutput ) ;
435
486
}
436
487
437
488
// We can't monomorphize things like `fn foo<A>(...)`.
0 commit comments