@@ -1803,52 +1803,84 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
1803
1803
tcx. check_stability ( variant_def. def_id , Some ( hir_ref_id) , span, None ) ;
1804
1804
self . prohibit_generics ( slice:: from_ref ( assoc_segment) . iter ( ) , |err| {
1805
1805
err. note ( "enum variants can't have type parameters" ) ;
1806
- let type_name = tcx. opt_item_name ( adt_def. did ( ) ) ;
1807
- let the_enum = type_name. map ( |n| format ! ( "enum `{n}`" ) ) . unwrap_or_else ( || "the enum" . to_string ( ) ) ;
1808
- let msg = format ! ( "you might have meant to specity type parameters on {the_enum}" ) ;
1806
+ let type_name = tcx. item_name ( adt_def. did ( ) ) ;
1807
+ let msg = format ! (
1808
+ "you might have meant to specity type parameters on enum \
1809
+ `{type_name}`"
1810
+ ) ;
1809
1811
let Some ( args) = assoc_segment. args else { return ; } ;
1812
+ // Get the span of the generics args *including* the leading `::`.
1810
1813
let args_span = assoc_segment. ident . span . shrink_to_hi ( ) . to ( args. span_ext ) ;
1814
+ if tcx. generics_of ( adt_def. did ( ) ) . count ( ) == 0 {
1815
+ // FIXME(estebank): we could also verify that the arguments being
1816
+ // work for the `enum`, instead of just looking if it takes *any*.
1817
+ err. span_suggestion_verbose (
1818
+ args_span,
1819
+ & format ! ( "{type_name} doesn't have type parameters" ) ,
1820
+ String :: new ( ) ,
1821
+ Applicability :: MachineApplicable ,
1822
+ ) ;
1823
+ return ;
1824
+ }
1811
1825
let Ok ( snippet) = tcx. sess . source_map ( ) . span_to_snippet ( args_span) else {
1812
1826
err. note ( & msg) ;
1813
1827
return ;
1814
1828
} ;
1815
- let ( qself_sugg_span, is_self) = if let hir:: TyKind :: Path ( hir:: QPath :: Resolved ( _, ref path) ) = qself. kind {
1829
+ let ( qself_sugg_span, is_self) = if let hir:: TyKind :: Path (
1830
+ hir:: QPath :: Resolved ( _, ref path)
1831
+ ) = qself. kind {
1816
1832
// If the path segment already has type params, we want to overwrite
1817
1833
// them.
1818
1834
match & path. segments [ ..] {
1819
- [ .., segment, _] => (
1820
- segment. ident . span . shrink_to_hi ( ) . to ( segment. args . map_or (
1821
- segment. ident . span . shrink_to_hi ( ) ,
1835
+ // `segment` is the previous to last element on the path,
1836
+ // which would normally be the `enum` itself, while the last
1837
+ // `_` `PathSegment` corresponds to the variant.
1838
+ [ .., hir:: PathSegment {
1839
+ ident,
1840
+ args,
1841
+ res : Some ( Res :: Def ( DefKind :: Enum , _) ) ,
1842
+ ..
1843
+ } , _] => (
1844
+ // We need to include the `::` in `Type::Variant::<Args>`
1845
+ // to point the span to `::<Args>`, not just `<Args>`.
1846
+ ident. span . shrink_to_hi ( ) . to ( args. map_or (
1847
+ ident. span . shrink_to_hi ( ) ,
1822
1848
|a| a. span_ext ) ) ,
1823
1849
false ,
1824
1850
) ,
1825
1851
[ segment] => (
1852
+ // We need to include the `::` in `Type::Variant::<Args>`
1853
+ // to point the span to `::<Args>`, not just `<Args>`.
1826
1854
segment. ident . span . shrink_to_hi ( ) . to ( segment. args . map_or (
1827
1855
segment. ident . span . shrink_to_hi ( ) ,
1828
1856
|a| a. span_ext ) ) ,
1829
1857
kw:: SelfUpper == segment. ident . name ,
1830
1858
) ,
1831
- _ => unreachable ! ( ) ,
1859
+ _ => {
1860
+ err. note ( & msg) ;
1861
+ return ;
1862
+ }
1832
1863
}
1833
1864
} else {
1834
1865
err. note ( & msg) ;
1835
1866
return ;
1836
1867
} ;
1837
- let Some ( type_name) = type_name else {
1838
- err. note ( & msg) ;
1839
- return ;
1840
- } ;
1841
1868
let suggestion = vec ! [
1842
1869
if is_self {
1843
1870
// Account for people writing `Self::Variant::<Args>`, where
1844
- // `Self` is the enum.
1871
+ // `Self` is the enum, and suggest replacing `Self` with the
1872
+ // appropriate type: `Type::<Args>::Variant`.
1845
1873
( qself. span, format!( "{type_name}{snippet}" ) )
1846
1874
} else {
1847
1875
( qself_sugg_span, snippet)
1848
1876
} ,
1849
1877
( args_span, String :: new( ) ) ,
1850
1878
] ;
1851
- err. multipart_suggestion_verbose ( & msg, suggestion, Applicability :: MaybeIncorrect ) ;
1879
+ err. multipart_suggestion_verbose (
1880
+ & msg,
1881
+ suggestion,
1882
+ Applicability :: MaybeIncorrect ,
1883
+ ) ;
1852
1884
} ) ;
1853
1885
return Ok ( ( qself_ty, DefKind :: Variant , variant_def. def_id ) ) ;
1854
1886
} else {
@@ -2369,8 +2401,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
2369
2401
// Try to evaluate any array length constants.
2370
2402
let ty = tcx. at ( span) . type_of ( def_id) ;
2371
2403
let span_of_impl = tcx. span_of_impl ( def_id) ;
2372
- // TODO: confirm that `def_id`'s type accepts type params at all before suggesting
2373
- // using that instead.
2374
2404
self . prohibit_generics ( path. segments . iter ( ) , |err| {
2375
2405
let def_id = match * ty. kind ( ) {
2376
2406
ty:: Adt ( self_def, _) => self_def. did ( ) ,
@@ -2379,32 +2409,52 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
2379
2409
2380
2410
let type_name = tcx. item_name ( def_id) ;
2381
2411
let span_of_ty = tcx. def_ident_span ( def_id) ;
2412
+ let generics = tcx. generics_of ( def_id) . count ( ) ;
2382
2413
2383
- let msg = format ! ( "the `Self` type is `{ty}`" ) ;
2414
+ let msg = format ! ( "`Self` is of type `{ty}`" ) ;
2384
2415
if let ( Ok ( i_sp) , Some ( t_sp) ) = ( span_of_impl, span_of_ty) {
2385
2416
let i_sp = tcx. sess . source_map ( ) . guess_head_span ( i_sp) ;
2386
2417
let mut span: MultiSpan = vec ! [ t_sp] . into ( ) ;
2387
2418
span. push_span_label (
2388
2419
i_sp,
2389
- & format ! ( "`Self` is `{type_name}` in this `impl`" ) ,
2420
+ & format ! ( "`Self` is or type `{type_name}` in this `impl`" ) ,
2421
+ ) ;
2422
+ let mut postfix = "" ;
2423
+ if generics == 0 {
2424
+ postfix = ", which doesn't have type parameters" ;
2425
+ }
2426
+ span. push_span_label (
2427
+ t_sp,
2428
+ & format ! ( "`Self` corresponds to this type{postfix}" ) ,
2390
2429
) ;
2391
- span. push_span_label ( t_sp, "`Self` corresponds to this type" ) ;
2392
2430
err. span_note ( span, & msg) ;
2393
2431
} else {
2394
2432
err. note ( & msg) ;
2395
2433
}
2396
2434
for segment in path. segments {
2397
- if let Some ( _args) = segment. args && segment. ident . name == kw:: SelfUpper {
2398
- err. span_suggestion_verbose (
2399
- segment. ident . span ,
2400
- format ! (
2401
- "the `Self` type doesn't accept type parameters, use the \
2402
- concrete type's name `{type_name}` instead if you want to \
2403
- specify its type parameters"
2404
- ) ,
2405
- type_name. to_string ( ) ,
2406
- Applicability :: MaybeIncorrect ,
2407
- ) ;
2435
+ if let Some ( args) = segment. args && segment. ident . name == kw:: SelfUpper {
2436
+ if generics == 0 {
2437
+ // FIXME(estebank): we could also verify that the arguments being
2438
+ // work for the `enum`, instead of just looking if it takes *any*.
2439
+ err. span_suggestion_verbose (
2440
+ segment. ident . span . shrink_to_hi ( ) . to ( args. span_ext ) ,
2441
+ "the `Self` type doesn't accept type parameters" ,
2442
+ String :: new ( ) ,
2443
+ Applicability :: MachineApplicable ,
2444
+ ) ;
2445
+ return ;
2446
+ } else {
2447
+ err. span_suggestion_verbose (
2448
+ segment. ident . span ,
2449
+ format ! (
2450
+ "the `Self` type doesn't accept type parameters, use the \
2451
+ concrete type's name `{type_name}` instead if you want to \
2452
+ specify its type parameters"
2453
+ ) ,
2454
+ type_name. to_string ( ) ,
2455
+ Applicability :: MaybeIncorrect ,
2456
+ ) ;
2457
+ }
2408
2458
}
2409
2459
}
2410
2460
} ) ;
0 commit comments