@@ -1202,36 +1202,42 @@ fn suggest_ampmut<'tcx>(
12021202 opt_assignment_rhs_span : Option < Span > ,
12031203 opt_ty_info : Option < Span > ,
12041204) -> ( bool , Span , String ) {
1205+ // if there is a RHS and it starts with a `&` from it, then check if it is
1206+ // mutable, and if not, put suggest putting `mut ` to make it mutable.
1207+ // we don't have to worry about lifetime annotations here because they are
1208+ // not valid when taking a reference. For example, the following is not valid Rust:
1209+ //
1210+ // let x: &i32 = &'a 5;
1211+ // ^^ lifetime annotation not allowed
1212+ //
12051213 if let Some ( assignment_rhs_span) = opt_assignment_rhs_span
12061214 && let Ok ( src) = tcx. sess . source_map ( ) . span_to_snippet ( assignment_rhs_span)
1215+ && let Some ( stripped) = src. strip_prefix ( '&' )
12071216 {
1208- let is_mutbl = |ty : & str | -> bool {
1209- if let Some ( rest) = ty. strip_prefix ( "mut" ) {
1210- match rest. chars ( ) . next ( ) {
1211- // e.g. `&mut x`
1212- Some ( c) if c. is_whitespace ( ) => true ,
1213- // e.g. `&mut(x)`
1214- Some ( '(' ) => true ,
1215- // e.g. `&mut{x}`
1216- Some ( '{' ) => true ,
1217- // e.g. `&mutablevar`
1218- _ => false ,
1219- }
1220- } else {
1221- false
1217+ let is_mut = if let Some ( rest) = stripped. trim_start ( ) . strip_prefix ( "mut" ) {
1218+ match rest. chars ( ) . next ( ) {
1219+ // e.g. `&mut x`
1220+ Some ( c) if c. is_whitespace ( ) => true ,
1221+ // e.g. `&mut(x)`
1222+ Some ( '(' ) => true ,
1223+ // e.g. `&mut{x}`
1224+ Some ( '{' ) => true ,
1225+ // e.g. `&mutablevar`
1226+ _ => false ,
12221227 }
1228+ } else {
1229+ false
12231230 } ;
1224- if let ( true , Some ( ws_pos) ) = ( src. starts_with ( "&'" ) , src. find ( char:: is_whitespace) ) {
1225- let lt_name = & src[ 1 ..ws_pos] ;
1226- let ty = src[ ws_pos..] . trim_start ( ) ;
1227- if !is_mutbl ( ty) {
1228- return ( true , assignment_rhs_span, format ! ( "&{lt_name} mut {ty}" ) ) ;
1229- }
1230- } else if let Some ( stripped) = src. strip_prefix ( '&' ) {
1231- let stripped = stripped. trim_start ( ) ;
1232- if !is_mutbl ( stripped) {
1233- return ( true , assignment_rhs_span, format ! ( "&mut {stripped}" ) ) ;
1234- }
1231+ // if the reference is already mutable then there is nothing we can do
1232+ // here.
1233+ if !is_mut {
1234+ let span = assignment_rhs_span;
1235+ // shrink the span to just after the `&` in `&variable`
1236+ let span = span. with_lo ( span. lo ( ) + BytePos ( 1 ) ) . shrink_to_lo ( ) ;
1237+
1238+ // FIXME(Ezrashaw): returning is bad because we still might want to
1239+ // update the annotated type, see #106857.
1240+ return ( true , span, "mut " . to_owned ( ) ) ;
12351241 }
12361242 }
12371243
0 commit comments