@@ -42,6 +42,7 @@ use dataflow::indexes::BorrowIndex;
42
42
use dataflow:: move_paths:: { IllegalMoveOriginKind , MoveError } ;
43
43
use dataflow:: move_paths:: { HasMoveData , LookupResult , MoveData , MovePathIndex } ;
44
44
use util:: borrowck_errors:: { BorrowckErrors , Origin } ;
45
+ use util:: collect_writes:: FindAssignments ;
45
46
46
47
use std:: iter;
47
48
@@ -1550,6 +1551,36 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
1550
1551
}
1551
1552
}
1552
1553
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
+
1553
1584
/// Check the permissions for the given place and read or write kind
1554
1585
///
1555
1586
/// Returns true if an error is reported, false otherwise.
@@ -1576,43 +1607,70 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
1576
1607
self . is_mutable ( place, is_local_mutation_allowed)
1577
1608
{
1578
1609
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) ;
1585
1611
let mut err = self . tcx
1586
1612
. cannot_borrow_path_as_mutable ( span, & item_msg, Origin :: Mir ) ;
1587
1613
err. span_label ( span, "cannot borrow as mutable" ) ;
1588
1614
1589
1615
if place != place_err {
1590
1616
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) ) ;
1592
1619
}
1593
1620
}
1594
1621
1595
1622
err. emit ( ) ;
1596
1623
} ,
1597
1624
Reservation ( WriteKind :: Mutate ) | Write ( WriteKind :: Mutate ) => {
1625
+
1598
1626
if let Err ( place_err) = self . is_mutable ( place, is_local_mutation_allowed) {
1599
1627
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
+ }
1600
1654
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) ;
1612
1660
}
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 ( ) ;
1613
1673
}
1614
-
1615
- err. emit ( ) ;
1616
1674
}
1617
1675
}
1618
1676
Reservation ( WriteKind :: Move )
@@ -1631,9 +1689,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
1631
1689
) ;
1632
1690
}
1633
1691
}
1634
-
1635
1692
Activation ( ..) => { } // permission checks are done at Reservation point.
1636
-
1637
1693
Read ( ReadKind :: Borrow ( BorrowKind :: Unique ) )
1638
1694
| Read ( ReadKind :: Borrow ( BorrowKind :: Mut { .. } ) )
1639
1695
| Read ( ReadKind :: Borrow ( BorrowKind :: Shared ) )
@@ -2255,3 +2311,4 @@ impl ContextKind {
2255
2311
}
2256
2312
}
2257
2313
}
2314
+
0 commit comments