@@ -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 ;
@@ -25,7 +26,7 @@ use rustc_middle::ty::{
25
26
TypeFoldable , WithConstness ,
26
27
} ;
27
28
use rustc_session:: DiagnosticMessageId ;
28
- use rustc_span:: { ExpnKind , Span , DUMMY_SP } ;
29
+ use rustc_span:: { ExpnKind , MultiSpan , Span , DUMMY_SP } ;
29
30
use std:: fmt;
30
31
31
32
use crate :: traits:: query:: evaluate_obligation:: InferCtxtExt as _;
@@ -1695,36 +1696,95 @@ 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 )
1702
- {
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 ,
1699
+ let ( pred, item_def_id, span) =
1700
+ match ( obligation. predicate . kind ( ) , & obligation. cause . code . peel_derives ( ) ) {
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 {
1744
+ param : param. name . ident ( ) . name ,
1745
+ invalid_spans : vec ! [ ] ,
1746
+ nested : false ,
1747
+ } ;
1748
+ visitor. visit_item ( item) ;
1749
+ if !visitor. invalid_spans . is_empty ( ) {
1750
+ let mut multispan: MultiSpan = param. span . into ( ) ;
1751
+ multispan. push_span_label (
1752
+ param. span ,
1753
+ format ! ( "this could be changed to `{}: ?Sized`..." , param. name. ident( ) ) ,
1754
+ ) ;
1755
+ for sp in visitor. invalid_spans {
1756
+ multispan. push_span_label (
1757
+ sp,
1758
+ format ! (
1759
+ "...if indirection was used here: `Box<{}>`" ,
1760
+ param. name. ident( ) ,
1761
+ ) ,
1762
+ ) ;
1763
+ }
1764
+ err. span_help (
1765
+ multispan,
1766
+ & format ! (
1767
+ "you could relax the implicit `Sized` bound on `{T}` if it were \
1768
+ used through indirection like `&{T}` or `Box<{T}>`",
1769
+ T = param. name. ident( ) ,
1770
+ ) ,
1723
1771
) ;
1724
1772
return ;
1725
1773
}
1726
1774
}
1775
+ _ => { }
1727
1776
}
1777
+ let ( span, separator) = match param. bounds {
1778
+ [ ] => ( span. shrink_to_hi ( ) , ":" ) ,
1779
+ [ .., bound] => ( bound. span ( ) . shrink_to_hi ( ) , " +" ) ,
1780
+ } ;
1781
+ err. span_suggestion_verbose (
1782
+ span,
1783
+ "consider relaxing the implicit `Sized` restriction" ,
1784
+ format ! ( "{} ?Sized" , separator) ,
1785
+ Applicability :: MachineApplicable ,
1786
+ ) ;
1787
+ return ;
1728
1788
}
1729
1789
}
1730
1790
@@ -1744,6 +1804,50 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> {
1744
1804
}
1745
1805
}
1746
1806
1807
+ /// Look for type `param` in an ADT being used only through a reference to confirm that suggesting
1808
+ /// `param: ?Sized` would be a valid constraint.
1809
+ struct FindTypeParam {
1810
+ param : rustc_span:: Symbol ,
1811
+ invalid_spans : Vec < Span > ,
1812
+ nested : bool ,
1813
+ }
1814
+
1815
+ impl < ' v > Visitor < ' v > for FindTypeParam {
1816
+ type Map = rustc_hir:: intravisit:: ErasedMap < ' v > ;
1817
+
1818
+ fn nested_visit_map ( & mut self ) -> hir:: intravisit:: NestedVisitorMap < Self :: Map > {
1819
+ hir:: intravisit:: NestedVisitorMap :: None
1820
+ }
1821
+
1822
+ fn visit_ty ( & mut self , ty : & hir:: Ty < ' _ > ) {
1823
+ // We collect the spans of all uses of the "bare" type param, like in `field: T` or
1824
+ // `field: (T, T)` where we could make `T: ?Sized` while skipping cases that are known to be
1825
+ // valid like `field: &'a T` or `field: *mut T` and cases that *might* have further `Sized`
1826
+ // obligations like `Box<T>` and `Vec<T>`, but we perform no extra analysis for those cases
1827
+ // and suggest `T: ?Sized` regardless of their obligations. This is fine because the errors
1828
+ // in that case should make what happened clear enough.
1829
+ match ty. kind {
1830
+ hir:: TyKind :: Ptr ( _) | hir:: TyKind :: Rptr ( ..) | hir:: TyKind :: TraitObject ( ..) => { }
1831
+ hir:: TyKind :: Path ( hir:: QPath :: Resolved ( None , path) )
1832
+ if path. segments . len ( ) == 1 && path. segments [ 0 ] . ident . name == self . param =>
1833
+ {
1834
+ if !self . nested {
1835
+ self . invalid_spans . push ( ty. span ) ;
1836
+ }
1837
+ }
1838
+ hir:: TyKind :: Path ( _) => {
1839
+ let prev = self . nested ;
1840
+ self . nested = true ;
1841
+ hir:: intravisit:: walk_ty ( self , ty) ;
1842
+ self . nested = prev;
1843
+ }
1844
+ _ => {
1845
+ hir:: intravisit:: walk_ty ( self , ty) ;
1846
+ }
1847
+ }
1848
+ }
1849
+ }
1850
+
1747
1851
pub fn recursive_type_with_infinite_size_error (
1748
1852
tcx : TyCtxt < ' tcx > ,
1749
1853
type_def_id : DefId ,
0 commit comments