@@ -1803,52 +1803,84 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
18031803 tcx. check_stability ( variant_def. def_id , Some ( hir_ref_id) , span, None ) ;
18041804 self . prohibit_generics ( slice:: from_ref ( assoc_segment) . iter ( ) , |err| {
18051805 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+ ) ;
18091811 let Some ( args) = assoc_segment. args else { return ; } ;
1812+ // Get the span of the generics args *including* the leading `::`.
18101813 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+ }
18111825 let Ok ( snippet) = tcx. sess . source_map ( ) . span_to_snippet ( args_span) else {
18121826 err. note ( & msg) ;
18131827 return ;
18141828 } ;
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 {
18161832 // If the path segment already has type params, we want to overwrite
18171833 // them.
18181834 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 ( ) ,
18221848 |a| a. span_ext ) ) ,
18231849 false ,
18241850 ) ,
18251851 [ segment] => (
1852+ // We need to include the `::` in `Type::Variant::<Args>`
1853+ // to point the span to `::<Args>`, not just `<Args>`.
18261854 segment. ident . span . shrink_to_hi ( ) . to ( segment. args . map_or (
18271855 segment. ident . span . shrink_to_hi ( ) ,
18281856 |a| a. span_ext ) ) ,
18291857 kw:: SelfUpper == segment. ident . name ,
18301858 ) ,
1831- _ => unreachable ! ( ) ,
1859+ _ => {
1860+ err. note ( & msg) ;
1861+ return ;
1862+ }
18321863 }
18331864 } else {
18341865 err. note ( & msg) ;
18351866 return ;
18361867 } ;
1837- let Some ( type_name) = type_name else {
1838- err. note ( & msg) ;
1839- return ;
1840- } ;
18411868 let suggestion = vec ! [
18421869 if is_self {
18431870 // 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`.
18451873 ( qself. span, format!( "{type_name}{snippet}" ) )
18461874 } else {
18471875 ( qself_sugg_span, snippet)
18481876 } ,
18491877 ( args_span, String :: new( ) ) ,
18501878 ] ;
1851- err. multipart_suggestion_verbose ( & msg, suggestion, Applicability :: MaybeIncorrect ) ;
1879+ err. multipart_suggestion_verbose (
1880+ & msg,
1881+ suggestion,
1882+ Applicability :: MaybeIncorrect ,
1883+ ) ;
18521884 } ) ;
18531885 return Ok ( ( qself_ty, DefKind :: Variant , variant_def. def_id ) ) ;
18541886 } else {
@@ -2369,8 +2401,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
23692401 // Try to evaluate any array length constants.
23702402 let ty = tcx. at ( span) . type_of ( def_id) ;
23712403 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.
23742404 self . prohibit_generics ( path. segments . iter ( ) , |err| {
23752405 let def_id = match * ty. kind ( ) {
23762406 ty:: Adt ( self_def, _) => self_def. did ( ) ,
@@ -2379,32 +2409,52 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
23792409
23802410 let type_name = tcx. item_name ( def_id) ;
23812411 let span_of_ty = tcx. def_ident_span ( def_id) ;
2412+ let generics = tcx. generics_of ( def_id) . count ( ) ;
23822413
2383- let msg = format ! ( "the `Self` type is `{ty}`" ) ;
2414+ let msg = format ! ( "`Self` is of type `{ty}`" ) ;
23842415 if let ( Ok ( i_sp) , Some ( t_sp) ) = ( span_of_impl, span_of_ty) {
23852416 let i_sp = tcx. sess . source_map ( ) . guess_head_span ( i_sp) ;
23862417 let mut span: MultiSpan = vec ! [ t_sp] . into ( ) ;
23872418 span. push_span_label (
23882419 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}" ) ,
23902429 ) ;
2391- span. push_span_label ( t_sp, "`Self` corresponds to this type" ) ;
23922430 err. span_note ( span, & msg) ;
23932431 } else {
23942432 err. note ( & msg) ;
23952433 }
23962434 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+ }
24082458 }
24092459 }
24102460 } ) ;
0 commit comments