@@ -16,6 +16,8 @@ use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder,
16
16
use rustc_hir as hir;
17
17
use rustc_hir:: def_id:: DefId ;
18
18
use rustc_hir:: intravisit:: Visitor ;
19
+ use rustc_hir:: GenericParam ;
20
+ use rustc_hir:: Item ;
19
21
use rustc_hir:: Node ;
20
22
use rustc_middle:: mir:: abstract_const:: NotConstEvaluatable ;
21
23
use rustc_middle:: ty:: error:: ExpectedFound ;
@@ -1138,6 +1140,20 @@ trait InferCtxtPrivExt<'tcx> {
1138
1140
obligation : & PredicateObligation < ' tcx > ,
1139
1141
) ;
1140
1142
1143
+ fn maybe_suggest_unsized_generics (
1144
+ & self ,
1145
+ err : & mut DiagnosticBuilder < ' tcx > ,
1146
+ span : Span ,
1147
+ node : Node < ' hir > ,
1148
+ ) ;
1149
+
1150
+ fn maybe_indirection_for_unsized (
1151
+ & self ,
1152
+ err : & mut DiagnosticBuilder < ' tcx > ,
1153
+ item : & ' hir Item < ' hir > ,
1154
+ param : & ' hir GenericParam < ' hir > ,
1155
+ ) -> bool ;
1156
+
1141
1157
fn is_recursive_obligation (
1142
1158
& self ,
1143
1159
obligated_types : & mut Vec < & ty:: TyS < ' tcx > > ,
@@ -1816,88 +1832,116 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> {
1816
1832
) => ( pred, item_def_id, span) ,
1817
1833
_ => return ,
1818
1834
} ;
1819
-
1835
+ debug ! (
1836
+ "suggest_unsized_bound_if_applicable: pred={:?} item_def_id={:?} span={:?}" ,
1837
+ pred, item_def_id, span
1838
+ ) ;
1820
1839
let node = match (
1821
1840
self . tcx . hir ( ) . get_if_local ( item_def_id) ,
1822
1841
Some ( pred. def_id ( ) ) == self . tcx . lang_items ( ) . sized_trait ( ) ,
1823
1842
) {
1824
1843
( Some ( node) , true ) => node,
1825
1844
_ => return ,
1826
1845
} ;
1846
+ self . maybe_suggest_unsized_generics ( err, span, node) ;
1847
+ }
1848
+
1849
+ fn maybe_suggest_unsized_generics (
1850
+ & self ,
1851
+ err : & mut DiagnosticBuilder < ' tcx > ,
1852
+ span : Span ,
1853
+ node : Node < ' hir > ,
1854
+ ) {
1827
1855
let generics = match node. generics ( ) {
1828
1856
Some ( generics) => generics,
1829
1857
None => return ,
1830
1858
} ;
1831
- for param in generics. params {
1832
- if param. span != span
1833
- || param. bounds . iter ( ) . any ( |bound| {
1834
- bound. trait_ref ( ) . and_then ( |trait_ref| trait_ref. trait_def_id ( ) )
1835
- == self . tcx . lang_items ( ) . sized_trait ( )
1836
- } )
1837
- {
1838
- continue ;
1839
- }
1840
- match node {
1841
- hir:: Node :: Item (
1842
- item
1843
- @
1844
- hir:: Item {
1845
- kind :
1846
- hir:: ItemKind :: Enum ( ..)
1847
- | hir:: ItemKind :: Struct ( ..)
1848
- | hir:: ItemKind :: Union ( ..) ,
1849
- ..
1850
- } ,
1851
- ) => {
1852
- // Suggesting `T: ?Sized` is only valid in an ADT if `T` is only used in a
1853
- // borrow. `struct S<'a, T: ?Sized>(&'a T);` is valid, `struct S<T: ?Sized>(T);`
1854
- // is not.
1855
- let mut visitor = FindTypeParam {
1856
- param : param. name . ident ( ) . name ,
1857
- invalid_spans : vec ! [ ] ,
1858
- nested : false ,
1859
- } ;
1860
- visitor. visit_item ( item) ;
1861
- if !visitor. invalid_spans . is_empty ( ) {
1862
- let mut multispan: MultiSpan = param. span . into ( ) ;
1863
- multispan. push_span_label (
1864
- param. span ,
1865
- format ! ( "this could be changed to `{}: ?Sized`..." , param. name. ident( ) ) ,
1866
- ) ;
1867
- for sp in visitor. invalid_spans {
1868
- multispan. push_span_label (
1869
- sp,
1870
- format ! (
1871
- "...if indirection were used here: `Box<{}>`" ,
1872
- param. name. ident( ) ,
1873
- ) ,
1874
- ) ;
1875
- }
1876
- err. span_help (
1877
- multispan,
1878
- & format ! (
1879
- "you could relax the implicit `Sized` bound on `{T}` if it were \
1880
- used through indirection like `&{T}` or `Box<{T}>`",
1881
- T = param. name. ident( ) ,
1882
- ) ,
1883
- ) ;
1884
- return ;
1885
- }
1859
+ let sized_trait = self . tcx . lang_items ( ) . sized_trait ( ) ;
1860
+ debug ! ( "maybe_suggest_unsized_generics: generics.params={:?}" , generics. params) ;
1861
+ debug ! ( "maybe_suggest_unsized_generics: generics.where_clause={:?}" , generics. where_clause) ;
1862
+ let param = generics
1863
+ . params
1864
+ . iter ( )
1865
+ . filter ( |param| param. span == span)
1866
+ . filter ( |param| {
1867
+ // Check that none of the explicit trait bounds is `Sized`. Assume that an explicit
1868
+ // `Sized` bound is there intentionally and we don't need to suggest relaxing it.
1869
+ param
1870
+ . bounds
1871
+ . iter ( )
1872
+ . all ( |bound| bound. trait_ref ( ) . and_then ( |tr| tr. trait_def_id ( ) ) != sized_trait)
1873
+ } )
1874
+ . next ( ) ;
1875
+ let param = match param {
1876
+ Some ( param) => param,
1877
+ _ => return ,
1878
+ } ;
1879
+ debug ! ( "maybe_suggest_unsized_generics: param={:?}" , param) ;
1880
+ match node {
1881
+ hir:: Node :: Item (
1882
+ item
1883
+ @
1884
+ hir:: Item {
1885
+ // Only suggest indirection for uses of type parameters in ADTs.
1886
+ kind :
1887
+ hir:: ItemKind :: Enum ( ..) | hir:: ItemKind :: Struct ( ..) | hir:: ItemKind :: Union ( ..) ,
1888
+ ..
1889
+ } ,
1890
+ ) => {
1891
+ if self . maybe_indirection_for_unsized ( err, item, param) {
1892
+ return ;
1886
1893
}
1887
- _ => { }
1888
1894
}
1889
- let ( span, separator) = match param. bounds {
1890
- [ ] => ( span. shrink_to_hi ( ) , ":" ) ,
1891
- [ .., bound] => ( bound. span ( ) . shrink_to_hi ( ) , " +" ) ,
1892
- } ;
1893
- err. span_suggestion_verbose (
1894
- span,
1895
- "consider relaxing the implicit `Sized` restriction" ,
1896
- format ! ( "{} ?Sized" , separator) ,
1897
- Applicability :: MachineApplicable ,
1895
+ _ => { }
1896
+ } ;
1897
+ // Didn't add an indirection suggestion, so add a general suggestion to relax `Sized`.
1898
+ let ( span, separator) = match param. bounds {
1899
+ [ ] => ( span. shrink_to_hi ( ) , ":" ) ,
1900
+ [ .., bound] => ( bound. span ( ) . shrink_to_hi ( ) , " +" ) ,
1901
+ } ;
1902
+ err. span_suggestion_verbose (
1903
+ span,
1904
+ "consider relaxing the implicit `Sized` restriction" ,
1905
+ format ! ( "{} ?Sized" , separator) ,
1906
+ Applicability :: MachineApplicable ,
1907
+ ) ;
1908
+ }
1909
+
1910
+ fn maybe_indirection_for_unsized (
1911
+ & self ,
1912
+ err : & mut DiagnosticBuilder < ' tcx > ,
1913
+ item : & ' hir Item < ' hir > ,
1914
+ param : & ' hir GenericParam < ' hir > ,
1915
+ ) -> bool {
1916
+ // Suggesting `T: ?Sized` is only valid in an ADT if `T` is only used in a
1917
+ // borrow. `struct S<'a, T: ?Sized>(&'a T);` is valid, `struct S<T: ?Sized>(T);`
1918
+ // is not. Look for invalid "bare" parameter uses, and suggest using indirection.
1919
+ let mut visitor =
1920
+ FindTypeParam { param : param. name . ident ( ) . name , invalid_spans : vec ! [ ] , nested : false } ;
1921
+ visitor. visit_item ( item) ;
1922
+ if visitor. invalid_spans . is_empty ( ) {
1923
+ return false ;
1924
+ }
1925
+ let mut multispan: MultiSpan = param. span . into ( ) ;
1926
+ multispan. push_span_label (
1927
+ param. span ,
1928
+ format ! ( "this could be changed to `{}: ?Sized`..." , param. name. ident( ) ) ,
1929
+ ) ;
1930
+ for sp in visitor. invalid_spans {
1931
+ multispan. push_span_label (
1932
+ sp,
1933
+ format ! ( "...if indirection were used here: `Box<{}>`" , param. name. ident( ) ) ,
1898
1934
) ;
1899
- return ;
1900
1935
}
1936
+ err. span_help (
1937
+ multispan,
1938
+ & format ! (
1939
+ "you could relax the implicit `Sized` bound on `{T}` if it were \
1940
+ used through indirection like `&{T}` or `Box<{T}>`",
1941
+ T = param. name. ident( ) ,
1942
+ ) ,
1943
+ ) ;
1944
+ true
1901
1945
}
1902
1946
1903
1947
fn is_recursive_obligation (
@@ -1948,6 +1992,7 @@ impl<'v> Visitor<'v> for FindTypeParam {
1948
1992
if path. segments . len ( ) == 1 && path. segments [ 0 ] . ident . name == self . param =>
1949
1993
{
1950
1994
if !self . nested {
1995
+ debug ! ( "FindTypeParam::visit_ty: ty={:?}" , ty) ;
1951
1996
self . invalid_spans . push ( ty. span ) ;
1952
1997
}
1953
1998
}
0 commit comments