@@ -29,6 +29,8 @@ use rustc_data_structures::indexed_set::IdxSetBuf;
29
29
use rustc_data_structures:: indexed_vec:: Idx ;
30
30
use rustc_data_structures:: small_vec:: SmallVec ;
31
31
32
+ use core:: unicode:: property:: Pattern_White_Space ;
33
+
32
34
use std:: rc:: Rc ;
33
35
34
36
use syntax_pos:: Span ;
@@ -1837,17 +1839,45 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
1837
1839
Place :: Projection ( box Projection {
1838
1840
base : Place :: Local ( local) ,
1839
1841
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) ;
1842
+ } ) if self . mir . local_decls [ * local] . is_user_variable . is_some ( ) => {
1843
+ let local_decl = & self . mir . local_decls [ * local] ;
1844
+ let ( err_help_span, suggested_code) = match local_decl. is_user_variable {
1845
+ Some ( ClearCrossCrate :: Set ( mir:: BindingForm :: ImplicitSelf ) ) => {
1846
+ suggest_ampmut_self ( local_decl)
1847
+ } ,
1848
+
1849
+ Some ( ClearCrossCrate :: Set ( mir:: BindingForm :: Var ( mir:: VarBindingForm {
1850
+ binding_mode : ty:: BindingMode :: BindByValue ( _) ,
1851
+ opt_ty_info,
1852
+ ..
1853
+ } ) ) ) => {
1854
+ if let Some ( x) = try_suggest_ampmut_rhs (
1855
+ self . tcx , self . mir , * local,
1856
+ ) {
1857
+ x
1858
+ } else {
1859
+ suggest_ampmut_type ( local_decl, opt_ty_info)
1860
+ }
1861
+ } ,
1862
+
1863
+ Some ( ClearCrossCrate :: Set ( mir:: BindingForm :: Var ( mir:: VarBindingForm {
1864
+ binding_mode : ty:: BindingMode :: BindByReference ( _) ,
1865
+ ..
1866
+ } ) ) ) => {
1867
+ suggest_ref_mut ( self . tcx , local_decl)
1868
+ } ,
1869
+
1870
+ Some ( ClearCrossCrate :: Clear ) => bug ! ( "saw cleared local state" ) ,
1871
+
1872
+ None => bug ! ( ) ,
1873
+ } ;
1874
+
1844
1875
err. span_suggestion (
1845
1876
err_help_span,
1846
1877
"consider changing this to be a mutable reference" ,
1847
1878
suggested_code,
1848
1879
) ;
1849
1880
1850
- let local_decl = & self . mir . local_decls [ * local] ;
1851
1881
if let Some ( name) = local_decl. name {
1852
1882
err. span_label (
1853
1883
span,
@@ -1874,13 +1904,16 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
1874
1904
err. emit ( ) ;
1875
1905
return true ;
1876
1906
1877
- // Returns the span to highlight and the associated text to
1878
- // present when suggesting that the user use an `&mut`.
1879
- //
1907
+ fn suggest_ampmut_self < ' cx , ' gcx , ' tcx > (
1908
+ local_decl : & mir:: LocalDecl < ' tcx > ,
1909
+ ) -> ( Span , String ) {
1910
+ ( local_decl. source_info . span , "&mut self" . to_string ( ) )
1911
+ }
1912
+
1880
1913
// When we want to suggest a user change a local variable to be a `&mut`, there
1881
1914
// are three potential "obvious" things to highlight:
1882
1915
//
1883
- // let ident [: Type] [= RightHandSideExresssion ];
1916
+ // let ident [: Type] [= RightHandSideExpression ];
1884
1917
// ^^^^^ ^^^^ ^^^^^^^^^^^^^^^^^^^^^^^
1885
1918
// (1.) (2.) (3.)
1886
1919
//
@@ -1889,48 +1922,58 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
1889
1922
// for example, if the RHS is present and the Type is not, then the type is going to
1890
1923
// be inferred *from* the RHS, which means we should highlight that (and suggest
1891
1924
// that they borrow the RHS mutably).
1892
- fn find_place_to_suggest_ampmut < ' cx , ' gcx , ' tcx > (
1925
+ //
1926
+ // This implementation attempts to emulate AST-borrowck prioritization
1927
+ // by trying (3.), then (2.) and finally falling back on (1.).
1928
+
1929
+ fn try_suggest_ampmut_rhs < ' cx , ' gcx , ' tcx > (
1893
1930
tcx : TyCtxt < ' cx , ' gcx , ' tcx > ,
1894
1931
mir : & Mir < ' tcx > ,
1895
1932
local : Local ,
1896
- ) -> ( Span , String ) {
1897
- // This implementation attempts to emulate AST-borrowck prioritization
1898
- // by trying (3.), then (2.) and finally falling back on (1.).
1933
+ ) -> Option < ( Span , String ) > {
1899
1934
let locations = mir. find_assignments ( local) ;
1900
1935
if locations. len ( ) > 0 {
1901
1936
let assignment_rhs_span = mir. source_info ( locations[ 0 ] ) . span ;
1902
1937
let snippet = tcx. sess . codemap ( ) . span_to_snippet ( assignment_rhs_span) ;
1903
1938
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 ".
1908
1939
if src. starts_with ( '&' ) {
1909
1940
let borrowed_expr = src[ 1 ..] . to_string ( ) ;
1910
- return ( assignment_rhs_span, format ! ( "&mut {}" , borrowed_expr) ) ;
1941
+ return Some ( ( assignment_rhs_span, format ! ( "&mut {}" , borrowed_expr) ) ) ;
1911
1942
}
1912
1943
}
1913
1944
}
1945
+ None
1946
+ }
1914
1947
1915
- let local_decl = & mir. local_decls [ local] ;
1916
- let highlight_span = match local_decl. is_user_variable {
1948
+ fn suggest_ampmut_type < ' tcx > (
1949
+ local_decl : & mir:: LocalDecl < ' tcx > ,
1950
+ opt_ty_info : Option < Span > ,
1951
+ ) -> ( Span , String ) {
1952
+ let highlight_span = match opt_ty_info {
1917
1953
// if this is a variable binding with an explicit type,
1918
1954
// 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" ) ,
1955
+ Some ( ty_span) => ty_span,
1925
1956
1926
1957
// otherwise, just highlight the span associated with
1927
1958
// the (MIR) LocalDecl.
1928
- _ => local_decl. source_info . span ,
1959
+ None => local_decl. source_info . span ,
1929
1960
} ;
1930
1961
1931
1962
let ty_mut = local_decl. ty . builtin_deref ( true ) . unwrap ( ) ;
1932
1963
assert_eq ! ( ty_mut. mutbl, hir:: MutImmutable ) ;
1933
- return ( highlight_span, format ! ( "&mut {}" , ty_mut. ty) ) ;
1964
+ ( highlight_span, format ! ( "&mut {}" , ty_mut. ty) )
1965
+ }
1966
+
1967
+ fn suggest_ref_mut < ' cx , ' gcx , ' tcx > (
1968
+ tcx : TyCtxt < ' cx , ' gcx , ' tcx > ,
1969
+ local_decl : & mir:: LocalDecl < ' tcx > ,
1970
+ ) -> ( Span , String ) {
1971
+ let hi_span = local_decl. source_info . span ;
1972
+ let hi_src = tcx. sess . codemap ( ) . span_to_snippet ( hi_span) . unwrap ( ) ;
1973
+ assert ! ( hi_src. starts_with( "ref" ) ) ;
1974
+ assert ! ( hi_src[ "ref" . len( ) ..] . starts_with( Pattern_White_Space ) ) ;
1975
+ let suggestion = format ! ( "ref mut{}" , & hi_src[ "ref" . len( ) ..] ) ;
1976
+ ( hi_span, suggestion)
1934
1977
}
1935
1978
}
1936
1979
0 commit comments