@@ -15,6 +15,7 @@ use rustc_data_structures::fx::FxHashMap;
1515use rustc_errors:: { pluralize, struct_span_err, Applicability , DiagnosticBuilder , ErrorReported } ;
1616use rustc_hir as hir;
1717use rustc_hir:: def_id:: { DefId , LOCAL_CRATE } ;
18+ use rustc_hir:: intravisit:: Visitor ;
1819use rustc_hir:: Node ;
1920use rustc_middle:: mir:: interpret:: ErrorHandled ;
2021use rustc_middle:: ty:: error:: ExpectedFound ;
@@ -1695,36 +1696,69 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> {
16951696 err : & mut DiagnosticBuilder < ' tcx > ,
16961697 obligation : & PredicateObligation < ' tcx > ,
16971698 ) {
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 )
17021700 {
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 ;
17251747 }
17261748 }
1749+ _ => { }
17271750 }
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 ;
17281762 }
17291763 }
17301764
@@ -1744,6 +1778,34 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> {
17441778 }
17451779}
17461780
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+
17471809pub fn recursive_type_with_infinite_size_error (
17481810 tcx : TyCtxt < ' tcx > ,
17491811 type_def_id : DefId ,
0 commit comments