@@ -16,7 +16,7 @@ use rustc::hir::def_id::DefId;
1616use rustc:: hir:: map:: definitions:: DefPathData ;
1717use rustc:: infer:: InferCtxt ;
1818use rustc:: lint:: builtin:: UNUSED_MUT ;
19- use rustc:: mir:: { self , AggregateKind , BasicBlock , BorrowCheckResult , BorrowKind } ;
19+ use rustc:: mir:: { AggregateKind , BasicBlock , BorrowCheckResult , BorrowKind } ;
2020use rustc:: mir:: { ClearCrossCrate , Local , Location , Mir , Mutability , Operand , Place } ;
2121use rustc:: mir:: { Field , Projection , ProjectionElem , Rvalue , Statement , StatementKind } ;
2222use rustc:: mir:: { Terminator , TerminatorKind } ;
@@ -43,27 +43,27 @@ use dataflow::{do_dataflow, DebugFormatted};
4343use dataflow:: { EverInitializedPlaces , MovingOutStatements } ;
4444use dataflow:: { MaybeInitializedPlaces , MaybeUninitializedPlaces } ;
4545use util:: borrowck_errors:: { BorrowckErrors , Origin } ;
46- use util:: collect_writes:: FindAssignments ;
47- use util:: suggest_ref_mut;
4846
4947use self :: borrow_set:: { BorrowData , BorrowSet } ;
5048use self :: flows:: Flows ;
5149use self :: location:: LocationTable ;
5250use self :: prefixes:: PrefixSet ;
5351use self :: MutateMode :: { JustWrite , WriteAndRead } ;
52+ use self :: mutability_errors:: AccessKind ;
5453
5554use self :: path_utils:: * ;
5655
5756crate mod borrow_set;
5857mod error_reporting;
5958mod flows;
6059mod location;
60+ mod move_errors;
61+ mod mutability_errors;
6162mod path_utils;
6263crate mod place_ext;
6364mod places_conflict;
6465mod prefixes;
6566mod used_muts;
66- mod move_errors;
6767
6868pub ( crate ) mod nll;
6969
@@ -922,7 +922,13 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
922922 }
923923
924924 let mutability_error =
925- self . check_access_permissions ( place_span, rw, is_local_mutation_allowed, flow_state) ;
925+ self . check_access_permissions (
926+ place_span,
927+ rw,
928+ is_local_mutation_allowed,
929+ flow_state,
930+ context. loc ,
931+ ) ;
926932 let conflict_error =
927933 self . check_access_for_conflict ( context, place_span, sd, rw, flow_state) ;
928934
@@ -1668,6 +1674,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
16681674 }
16691675 }
16701676
1677+
16711678 /// Check the permissions for the given place and read or write kind
16721679 ///
16731680 /// Returns true if an error is reported, false otherwise.
@@ -1677,17 +1684,13 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
16771684 kind : ReadOrWrite ,
16781685 is_local_mutation_allowed : LocalMutationIsAllowed ,
16791686 flow_state : & Flows < ' cx , ' gcx , ' tcx > ,
1687+ location : Location ,
16801688 ) -> bool {
16811689 debug ! (
16821690 "check_access_permissions({:?}, {:?}, {:?})" ,
16831691 place, kind, is_local_mutation_allowed
16841692 ) ;
16851693
1686- #[ derive( Copy , Clone , Debug ) ]
1687- enum AccessKind {
1688- MutableBorrow ,
1689- Mutate ,
1690- }
16911694 let error_access;
16921695 let the_place_err;
16931696
@@ -1756,206 +1759,14 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
17561759 }
17571760
17581761 // at this point, we have set up the error reporting state.
1759-
1760- let mut err;
1761- let item_msg = match self . describe_place ( place) {
1762- Some ( name) => format ! ( "immutable item `{}`" , name) ,
1763- None => "immutable item" . to_owned ( ) ,
1764- } ;
1765-
1766- // `act` and `acted_on` are strings that let us abstract over
1767- // the verbs used in some diagnostic messages.
1768- let act;
1769- let acted_on;
1770-
1771- match error_access {
1772- AccessKind :: Mutate => {
1773- let item_msg = match the_place_err {
1774- Place :: Projection ( box Projection {
1775- base : _,
1776- elem : ProjectionElem :: Deref ,
1777- } ) => match self . describe_place ( place) {
1778- Some ( description) => {
1779- format ! ( "`{}` which is behind a `&` reference" , description)
1780- }
1781- None => format ! ( "data in a `&` reference" ) ,
1782- } ,
1783- _ => item_msg,
1784- } ;
1785- err = self . tcx . cannot_assign ( span, & item_msg, Origin :: Mir ) ;
1786- act = "assign" ;
1787- acted_on = "written" ;
1788- }
1789- AccessKind :: MutableBorrow => {
1790- err = self
1791- . tcx
1792- . cannot_borrow_path_as_mutable ( span, & item_msg, Origin :: Mir ) ;
1793- act = "borrow as mutable" ;
1794- acted_on = "borrowed as mutable" ;
1795- }
1796- }
1797-
1798- match the_place_err {
1799- // We want to suggest users use `let mut` for local (user
1800- // variable) mutations...
1801- Place :: Local ( local) if self . mir . local_decls [ * local] . can_be_made_mutable ( ) => {
1802- // ... but it doesn't make sense to suggest it on
1803- // variables that are `ref x`, `ref mut x`, `&self`,
1804- // or `&mut self` (such variables are simply not
1805- // mutable)..
1806- let local_decl = & self . mir . local_decls [ * local] ;
1807- assert_eq ! ( local_decl. mutability, Mutability :: Not ) ;
1808-
1809- err. span_label ( span, format ! ( "cannot {ACT}" , ACT = act) ) ;
1810- err. span_suggestion (
1811- local_decl. source_info . span ,
1812- "consider changing this to be mutable" ,
1813- format ! ( "mut {}" , local_decl. name. unwrap( ) ) ,
1814- ) ;
1815- }
1816-
1817- // complete hack to approximate old AST-borrowck
1818- // diagnostic: if the span starts with a mutable borrow of
1819- // a local variable, then just suggest the user remove it.
1820- Place :: Local ( _)
1821- if {
1822- if let Ok ( snippet) = self . tcx . sess . codemap ( ) . span_to_snippet ( span) {
1823- snippet. starts_with ( "&mut " )
1824- } else {
1825- false
1826- }
1827- } =>
1828- {
1829- err. span_label ( span, format ! ( "cannot {ACT}" , ACT = act) ) ;
1830- err. span_label ( span, "try removing `&mut` here" ) ;
1831- }
1832-
1833- // We want to point out when a `&` can be readily replaced
1834- // with an `&mut`.
1835- //
1836- // FIXME: can this case be generalized to work for an
1837- // arbitrary base for the projection?
1838- Place :: Projection ( box Projection {
1839- base : Place :: Local ( local) ,
1840- elem : ProjectionElem :: Deref ,
1841- } ) if self . mir . local_decls [ * local] . is_user_variable . is_some ( ) => {
1842- 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-
1876- if let Some ( name) = local_decl. name {
1877- err. span_label (
1878- span,
1879- format ! (
1880- "`{NAME}` is a `&` reference, \
1881- so the data it refers to cannot be {ACTED_ON}",
1882- NAME = name,
1883- ACTED_ON = acted_on
1884- ) ,
1885- ) ;
1886- } else {
1887- err. span_label (
1888- span,
1889- format ! ( "cannot {ACT} through `&`-reference" , ACT = act) ,
1890- ) ;
1891- }
1892- }
1893-
1894- _ => {
1895- err. span_label ( span, format ! ( "cannot {ACT}" , ACT = act) ) ;
1896- }
1897- }
1898-
1899- err. emit ( ) ;
1762+ self . report_mutability_error (
1763+ place,
1764+ span,
1765+ the_place_err,
1766+ error_access,
1767+ location,
1768+ ) ;
19001769 return true ;
1901-
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-
1908- // When we want to suggest a user change a local variable to be a `&mut`, there
1909- // are three potential "obvious" things to highlight:
1910- //
1911- // let ident [: Type] [= RightHandSideExpression];
1912- // ^^^^^ ^^^^ ^^^^^^^^^^^^^^^^^^^^^^^
1913- // (1.) (2.) (3.)
1914- //
1915- // We can always fallback on highlighting the first. But chances are good that
1916- // the user experience will be better if we highlight one of the others if possible;
1917- // for example, if the RHS is present and the Type is not, then the type is going to
1918- // be inferred *from* the RHS, which means we should highlight that (and suggest
1919- // that they borrow the RHS mutably).
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 > (
1924- tcx : TyCtxt < ' cx , ' gcx , ' tcx > ,
1925- mir : & Mir < ' tcx > ,
1926- local : Local ,
1927- local_decl : & mir:: LocalDecl < ' tcx > ,
1928- opt_ty_info : Option < Span > ,
1929- ) -> ( Span , String ) {
1930- let locations = mir. find_assignments ( local) ;
1931- if locations. len ( ) > 0 {
1932- let assignment_rhs_span = mir. source_info ( locations[ 0 ] ) . span ;
1933- let snippet = tcx. sess . codemap ( ) . span_to_snippet ( assignment_rhs_span) ;
1934- if let Ok ( src) = snippet {
1935- if src. starts_with ( '&' ) {
1936- let borrowed_expr = src[ 1 ..] . to_string ( ) ;
1937- return (
1938- assignment_rhs_span,
1939- format ! ( "&mut {}" , borrowed_expr) ,
1940- ) ;
1941- }
1942- }
1943- }
1944-
1945- let highlight_span = match opt_ty_info {
1946- // if this is a variable binding with an explicit type,
1947- // try to highlight that for the suggestion.
1948- Some ( ty_span) => ty_span,
1949-
1950- // otherwise, just highlight the span associated with
1951- // the (MIR) LocalDecl.
1952- None => local_decl. source_info . span ,
1953- } ;
1954-
1955- let ty_mut = local_decl. ty . builtin_deref ( true ) . unwrap ( ) ;
1956- assert_eq ! ( ty_mut. mutbl, hir:: MutImmutable ) ;
1957- ( highlight_span, format ! ( "&mut {}" , ty_mut. ty) )
1958- }
19591770 }
19601771
19611772 /// Adds the place into the used mutable variables set
0 commit comments