@@ -42,6 +42,7 @@ use dataflow::indexes::BorrowIndex;
4242use dataflow:: move_paths:: { IllegalMoveOriginKind , MoveError } ;
4343use dataflow:: move_paths:: { HasMoveData , LookupResult , MoveData , MovePathIndex } ;
4444use util:: borrowck_errors:: { BorrowckErrors , Origin } ;
45+ use util:: collect_writes:: FindAssignments ;
4546
4647use std:: iter;
4748
@@ -1550,6 +1551,36 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
15501551 }
15511552 }
15521553
1554+ fn specialized_description ( & self , place : & Place < ' tcx > ) -> Option < String > {
1555+ if let Some ( _name) = self . describe_place ( place) {
1556+ Some ( format ! ( "data in a `&` reference" ) )
1557+ } else {
1558+ None
1559+ }
1560+ }
1561+
1562+ fn get_default_err_msg ( & self , place : & Place < ' tcx > ) -> String {
1563+ match self . describe_place ( place) {
1564+ Some ( name) => format ! ( "immutable item `{}`" , name) ,
1565+ None => "immutable item" . to_owned ( ) ,
1566+ }
1567+ }
1568+
1569+ fn get_secondary_err_msg ( & self , place : & Place < ' tcx > ) -> String {
1570+ match self . specialized_description ( place) {
1571+ Some ( _) => format ! ( "data in a `&` reference" ) ,
1572+ None => self . get_default_err_msg ( place)
1573+ }
1574+ }
1575+
1576+ fn get_primary_err_msg ( & self , place : & Place < ' tcx > ) -> String {
1577+ if let Some ( name) = self . describe_place ( place) {
1578+ format ! ( "`{}` is a `&` reference, so the data it refers to cannot be written" , name)
1579+ } else {
1580+ format ! ( "cannot assign through `&`-reference" )
1581+ }
1582+ }
1583+
15531584 /// Check the permissions for the given place and read or write kind
15541585 ///
15551586 /// Returns true if an error is reported, false otherwise.
@@ -1576,43 +1607,70 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
15761607 self . is_mutable ( place, is_local_mutation_allowed)
15771608 {
15781609 error_reported = true ;
1579-
1580- let item_msg = match self . describe_place ( place) {
1581- Some ( name) => format ! ( "immutable item `{}`" , name) ,
1582- None => "immutable item" . to_owned ( ) ,
1583- } ;
1584-
1610+ let item_msg = self . get_default_err_msg ( place) ;
15851611 let mut err = self . tcx
15861612 . cannot_borrow_path_as_mutable ( span, & item_msg, Origin :: Mir ) ;
15871613 err. span_label ( span, "cannot borrow as mutable" ) ;
15881614
15891615 if place != place_err {
15901616 if let Some ( name) = self . describe_place ( place_err) {
1591- err. note ( & format ! ( "Value not mutable causing this error: `{}`" , name) ) ;
1617+ err. note ( & format ! ( "the value which is causing this path not to be mutable \
1618+ is...: `{}`", name) ) ;
15921619 }
15931620 }
15941621
15951622 err. emit ( ) ;
15961623 } ,
15971624 Reservation ( WriteKind :: Mutate ) | Write ( WriteKind :: Mutate ) => {
1625+
15981626 if let Err ( place_err) = self . is_mutable ( place, is_local_mutation_allowed) {
15991627 error_reported = true ;
1628+ let mut err_info = None ;
1629+ match * place_err {
1630+
1631+ Place :: Projection ( box Projection {
1632+ ref base, elem : ProjectionElem :: Deref } ) => {
1633+ match * base {
1634+ Place :: Local ( local) => {
1635+ let locations = self . mir . find_assignments ( local) ;
1636+ if locations. len ( ) > 0 {
1637+ let item_msg = if error_reported {
1638+ self . get_secondary_err_msg ( base)
1639+ } else {
1640+ self . get_default_err_msg ( place)
1641+ } ;
1642+ err_info = Some ( (
1643+ self . mir . source_info ( locations[ 0 ] ) . span ,
1644+ "consider changing this to be a \
1645+ mutable reference: `&mut`", item_msg,
1646+ self . get_primary_err_msg ( base) ) ) ;
1647+ }
1648+ } ,
1649+ _ => { } ,
1650+ }
1651+ } ,
1652+ _ => { } ,
1653+ }
16001654
1601- let item_msg = match self . describe_place ( place) {
1602- Some ( name) => format ! ( "immutable item `{}`" , name) ,
1603- None => "immutable item" . to_owned ( ) ,
1604- } ;
1605-
1606- let mut err = self . tcx . cannot_assign ( span, & item_msg, Origin :: Mir ) ;
1607- err. span_label ( span, "cannot mutate" ) ;
1608-
1609- if place != place_err {
1610- if let Some ( name) = self . describe_place ( place_err) {
1611- err. note ( & format ! ( "Value not mutable causing this error: `{}`" , name) ) ;
1655+ if let Some ( ( err_help_span, err_help_stmt, item_msg, sec_span) ) = err_info {
1656+ let mut err = self . tcx . cannot_assign ( span, & item_msg, Origin :: Mir ) ;
1657+ err. span_suggestion ( err_help_span, err_help_stmt, format ! ( "" ) ) ;
1658+ if place != place_err {
1659+ err. span_label ( span, sec_span) ;
16121660 }
1661+ err. emit ( )
1662+ } else {
1663+ let item_msg_ = self . get_default_err_msg ( place) ;
1664+ let mut err = self . tcx . cannot_assign ( span, & item_msg_, Origin :: Mir ) ;
1665+ err. span_label ( span, "cannot mutate" ) ;
1666+ if place != place_err {
1667+ if let Some ( name) = self . describe_place ( place_err) {
1668+ err. note ( & format ! ( "the value which is causing this path not to be \
1669+ mutable is...: `{}`", name) ) ;
1670+ }
1671+ }
1672+ err. emit ( ) ;
16131673 }
1614-
1615- err. emit ( ) ;
16161674 }
16171675 }
16181676 Reservation ( WriteKind :: Move )
@@ -1631,9 +1689,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
16311689 ) ;
16321690 }
16331691 }
1634-
16351692 Activation ( ..) => { } // permission checks are done at Reservation point.
1636-
16371693 Read ( ReadKind :: Borrow ( BorrowKind :: Unique ) )
16381694 | Read ( ReadKind :: Borrow ( BorrowKind :: Mut { .. } ) )
16391695 | Read ( ReadKind :: Borrow ( BorrowKind :: Shared ) )
@@ -2255,3 +2311,4 @@ impl ContextKind {
22552311 }
22562312 }
22572313}
2314+
0 commit comments