@@ -15,6 +15,7 @@ use rustc_data_structures::fx::FxHashMap;
15
15
use rustc_errors:: { pluralize, struct_span_err, Applicability , DiagnosticBuilder , ErrorReported } ;
16
16
use rustc_hir as hir;
17
17
use rustc_hir:: def_id:: { DefId , LOCAL_CRATE } ;
18
+ use rustc_hir:: intravisit:: Visitor ;
18
19
use rustc_hir:: Node ;
19
20
use rustc_middle:: mir:: interpret:: ErrorHandled ;
20
21
use rustc_middle:: ty:: error:: ExpectedFound ;
@@ -1695,36 +1696,69 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> {
1695
1696
err : & mut DiagnosticBuilder < ' tcx > ,
1696
1697
obligation : & PredicateObligation < ' tcx > ,
1697
1698
) {
1698
- if let (
1699
- ty:: PredicateKind :: Trait ( pred, _) ,
1700
- ObligationCauseCode :: BindingObligation ( item_def_id, span) ,
1701
- ) = ( obligation. predicate . kind ( ) , & obligation. cause . code )
1699
+ let ( pred, item_def_id, span) = match ( obligation. predicate . kind ( ) , & obligation. cause . code )
1702
1700
{
1703
- if let ( Some ( generics) , true ) = (
1704
- self . tcx . hir ( ) . get_if_local ( * item_def_id) . as_ref ( ) . and_then ( |n| n. generics ( ) ) ,
1705
- Some ( pred. def_id ( ) ) == self . tcx . lang_items ( ) . sized_trait ( ) ,
1706
- ) {
1707
- for param in generics. params {
1708
- if param. span == * span
1709
- && !param. bounds . iter ( ) . any ( |bound| {
1710
- bound. trait_ref ( ) . and_then ( |trait_ref| trait_ref. trait_def_id ( ) )
1711
- == self . tcx . lang_items ( ) . sized_trait ( )
1712
- } )
1713
- {
1714
- let ( span, separator) = match param. bounds {
1715
- [ ] => ( span. shrink_to_hi ( ) , ":" ) ,
1716
- [ .., bound] => ( bound. span ( ) . shrink_to_hi ( ) , " +" ) ,
1717
- } ;
1718
- err. span_suggestion_verbose (
1719
- span,
1720
- "consider relaxing the implicit `Sized` restriction" ,
1721
- format ! ( "{} ?Sized" , separator) ,
1722
- Applicability :: MachineApplicable ,
1723
- ) ;
1724
- return ;
1701
+ (
1702
+ ty:: PredicateKind :: Trait ( pred, _) ,
1703
+ ObligationCauseCode :: BindingObligation ( item_def_id, span) ,
1704
+ ) => ( pred, item_def_id, span) ,
1705
+ _ => return ,
1706
+ } ;
1707
+
1708
+ let node = match (
1709
+ self . tcx . hir ( ) . get_if_local ( * item_def_id) ,
1710
+ Some ( pred. def_id ( ) ) == self . tcx . lang_items ( ) . sized_trait ( ) ,
1711
+ ) {
1712
+ ( Some ( node) , true ) => node,
1713
+ _ => return ,
1714
+ } ;
1715
+ let generics = match node. generics ( ) {
1716
+ Some ( generics) => generics,
1717
+ None => return ,
1718
+ } ;
1719
+ for param in generics. params {
1720
+ if param. span != * span
1721
+ || param. bounds . iter ( ) . any ( |bound| {
1722
+ bound. trait_ref ( ) . and_then ( |trait_ref| trait_ref. trait_def_id ( ) )
1723
+ == self . tcx . lang_items ( ) . sized_trait ( )
1724
+ } )
1725
+ {
1726
+ continue ;
1727
+ }
1728
+ match node {
1729
+ hir:: Node :: Item (
1730
+ item
1731
+ @
1732
+ hir:: Item {
1733
+ kind :
1734
+ hir:: ItemKind :: Enum ( ..)
1735
+ | hir:: ItemKind :: Struct ( ..)
1736
+ | hir:: ItemKind :: Union ( ..) ,
1737
+ ..
1738
+ } ,
1739
+ ) => {
1740
+ // Suggesting `T: ?Sized` is only valid in an ADT if `T` is only used in a
1741
+ // borrow. `struct S<'a, T: ?Sized>(&'a T);` is valid, `struct S<T: ?Sized>(T);`
1742
+ // is not.
1743
+ let mut visitor = FindTypeParam { param : param. name . ident ( ) . name , valid : true } ;
1744
+ visitor. visit_item ( item) ;
1745
+ if !visitor. valid {
1746
+ continue ;
1725
1747
}
1726
1748
}
1749
+ _ => { }
1727
1750
}
1751
+ let ( span, separator) = match param. bounds {
1752
+ [ ] => ( span. shrink_to_hi ( ) , ":" ) ,
1753
+ [ .., bound] => ( bound. span ( ) . shrink_to_hi ( ) , " +" ) ,
1754
+ } ;
1755
+ err. span_suggestion_verbose (
1756
+ span,
1757
+ "consider relaxing the implicit `Sized` restriction" ,
1758
+ format ! ( "{} ?Sized" , separator) ,
1759
+ Applicability :: MachineApplicable ,
1760
+ ) ;
1761
+ return ;
1728
1762
}
1729
1763
}
1730
1764
@@ -1744,6 +1778,34 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> {
1744
1778
}
1745
1779
}
1746
1780
1781
+ /// Look for type `param` in an ADT being used only through a reference to confirm that suggesting
1782
+ /// `param: ?Sized` would be a valid constraint.
1783
+ struct FindTypeParam {
1784
+ param : rustc_span:: Symbol ,
1785
+ valid : bool ,
1786
+ }
1787
+
1788
+ impl < ' v > Visitor < ' v > for FindTypeParam {
1789
+ type Map = rustc_hir:: intravisit:: ErasedMap < ' v > ;
1790
+
1791
+ fn nested_visit_map ( & mut self ) -> hir:: intravisit:: NestedVisitorMap < Self :: Map > {
1792
+ hir:: intravisit:: NestedVisitorMap :: None
1793
+ }
1794
+
1795
+ fn visit_ty ( & mut self , ty : & hir:: Ty < ' _ > ) {
1796
+ match ty. kind {
1797
+ hir:: TyKind :: Ptr ( _) | hir:: TyKind :: Rptr ( ..) | hir:: TyKind :: TraitObject ( ..) => return ,
1798
+ hir:: TyKind :: Path ( hir:: QPath :: Resolved ( None , path) )
1799
+ if path. segments . len ( ) == 1 && path. segments [ 0 ] . ident . name == self . param =>
1800
+ {
1801
+ self . valid = false ;
1802
+ }
1803
+ _ => { }
1804
+ }
1805
+ hir:: intravisit:: walk_ty ( self , ty) ;
1806
+ }
1807
+ }
1808
+
1747
1809
pub fn recursive_type_with_infinite_size_error (
1748
1810
tcx : TyCtxt < ' tcx > ,
1749
1811
type_def_id : DefId ,
0 commit comments