@@ -44,6 +44,7 @@ use dataflow::{EverInitializedPlaces, MovingOutStatements};
4444use dataflow:: { MaybeInitializedPlaces , MaybeUninitializedPlaces } ;
4545use util:: borrowck_errors:: { BorrowckErrors , Origin } ;
4646use util:: collect_writes:: FindAssignments ;
47+ use util:: suggest_ref_mut;
4748
4849use self :: borrow_set:: { BorrowData , BorrowSet } ;
4950use self :: flows:: Flows ;
@@ -1837,17 +1838,41 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
18371838 Place :: Projection ( box Projection {
18381839 base : Place :: Local ( local) ,
18391840 elem : ProjectionElem :: Deref ,
1840- } ) if self . mir . local_decls [ * local] . is_nonref_binding ( ) =>
1841- {
1842- let ( err_help_span, suggested_code) =
1843- find_place_to_suggest_ampmut ( self . tcx , self . mir , * local) ;
1844- err. span_suggestion (
1845- err_help_span,
1846- "consider changing this to be a mutable reference" ,
1847- suggested_code,
1848- ) ;
1849-
1841+ } ) if self . mir . local_decls [ * local] . is_user_variable . is_some ( ) => {
18501842 let local_decl = & self . mir . local_decls [ * local] ;
1843+ let suggestion = match local_decl. is_user_variable . as_ref ( ) . unwrap ( ) {
1844+ ClearCrossCrate :: Set ( mir:: BindingForm :: ImplicitSelf ) => {
1845+ Some ( suggest_ampmut_self ( local_decl) )
1846+ } ,
1847+
1848+ ClearCrossCrate :: Set ( mir:: BindingForm :: Var ( mir:: VarBindingForm {
1849+ binding_mode : ty:: BindingMode :: BindByValue ( _) ,
1850+ opt_ty_info,
1851+ ..
1852+ } ) ) => Some ( suggest_ampmut (
1853+ self . tcx ,
1854+ self . mir ,
1855+ * local,
1856+ local_decl,
1857+ * opt_ty_info,
1858+ ) ) ,
1859+
1860+ ClearCrossCrate :: Set ( mir:: BindingForm :: Var ( mir:: VarBindingForm {
1861+ binding_mode : ty:: BindingMode :: BindByReference ( _) ,
1862+ ..
1863+ } ) ) => suggest_ref_mut ( self . tcx , local_decl. source_info . span ) ,
1864+
1865+ ClearCrossCrate :: Clear => bug ! ( "saw cleared local state" ) ,
1866+ } ;
1867+
1868+ if let Some ( ( err_help_span, suggested_code) ) = suggestion {
1869+ err. span_suggestion (
1870+ err_help_span,
1871+ "consider changing this to be a mutable reference" ,
1872+ suggested_code,
1873+ ) ;
1874+ }
1875+
18511876 if let Some ( name) = local_decl. name {
18521877 err. span_label (
18531878 span,
@@ -1874,13 +1899,16 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
18741899 err. emit ( ) ;
18751900 return true ;
18761901
1877- // Returns the span to highlight and the associated text to
1878- // present when suggesting that the user use an `&mut`.
1879- //
1902+ fn suggest_ampmut_self < ' cx , ' gcx , ' tcx > (
1903+ local_decl : & mir:: LocalDecl < ' tcx > ,
1904+ ) -> ( Span , String ) {
1905+ ( local_decl. source_info . span , "&mut self" . to_string ( ) )
1906+ }
1907+
18801908 // When we want to suggest a user change a local variable to be a `&mut`, there
18811909 // are three potential "obvious" things to highlight:
18821910 //
1883- // let ident [: Type] [= RightHandSideExresssion ];
1911+ // let ident [: Type] [= RightHandSideExpression ];
18841912 // ^^^^^ ^^^^ ^^^^^^^^^^^^^^^^^^^^^^^
18851913 // (1.) (2.) (3.)
18861914 //
@@ -1889,48 +1917,44 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
18891917 // for example, if the RHS is present and the Type is not, then the type is going to
18901918 // be inferred *from* the RHS, which means we should highlight that (and suggest
18911919 // that they borrow the RHS mutably).
1892- fn find_place_to_suggest_ampmut < ' cx , ' gcx , ' tcx > (
1920+ //
1921+ // This implementation attempts to emulate AST-borrowck prioritization
1922+ // by trying (3.), then (2.) and finally falling back on (1.).
1923+ fn suggest_ampmut < ' cx , ' gcx , ' tcx > (
18931924 tcx : TyCtxt < ' cx , ' gcx , ' tcx > ,
18941925 mir : & Mir < ' tcx > ,
18951926 local : Local ,
1927+ local_decl : & mir:: LocalDecl < ' tcx > ,
1928+ opt_ty_info : Option < Span > ,
18961929 ) -> ( Span , String ) {
1897- // This implementation attempts to emulate AST-borrowck prioritization
1898- // by trying (3.), then (2.) and finally falling back on (1.).
18991930 let locations = mir. find_assignments ( local) ;
19001931 if locations. len ( ) > 0 {
19011932 let assignment_rhs_span = mir. source_info ( locations[ 0 ] ) . span ;
19021933 let snippet = tcx. sess . codemap ( ) . span_to_snippet ( assignment_rhs_span) ;
19031934 if let Ok ( src) = snippet {
1904- // pnkfelix inherited code; believes intention is
1905- // highlighted text will always be `&<expr>` and
1906- // thus can transform to `&mut` by slicing off
1907- // first ASCII character and prepending "&mut ".
19081935 if src. starts_with ( '&' ) {
19091936 let borrowed_expr = src[ 1 ..] . to_string ( ) ;
1910- return ( assignment_rhs_span, format ! ( "&mut {}" , borrowed_expr) ) ;
1937+ return (
1938+ assignment_rhs_span,
1939+ format ! ( "&mut {}" , borrowed_expr) ,
1940+ ) ;
19111941 }
19121942 }
19131943 }
19141944
1915- let local_decl = & mir. local_decls [ local] ;
1916- let highlight_span = match local_decl. is_user_variable {
1945+ let highlight_span = match opt_ty_info {
19171946 // if this is a variable binding with an explicit type,
19181947 // try to highlight that for the suggestion.
1919- Some ( ClearCrossCrate :: Set ( mir:: BindingForm :: Var ( mir:: VarBindingForm {
1920- opt_ty_info : Some ( ty_span) ,
1921- ..
1922- } ) ) ) => ty_span,
1923-
1924- Some ( ClearCrossCrate :: Clear ) => bug ! ( "saw cleared local state" ) ,
1948+ Some ( ty_span) => ty_span,
19251949
19261950 // otherwise, just highlight the span associated with
19271951 // the (MIR) LocalDecl.
1928- _ => local_decl. source_info . span ,
1952+ None => local_decl. source_info . span ,
19291953 } ;
19301954
19311955 let ty_mut = local_decl. ty . builtin_deref ( true ) . unwrap ( ) ;
19321956 assert_eq ! ( ty_mut. mutbl, hir:: MutImmutable ) ;
1933- return ( highlight_span, format ! ( "&mut {}" , ty_mut. ty) ) ;
1957+ ( highlight_span, format ! ( "&mut {}" , ty_mut. ty) )
19341958 }
19351959 }
19361960
0 commit comments