@@ -30,7 +30,7 @@ use rustc_middle::ty::{self, Const, DefIdTree, EarlyBinder, Ty, TyCtxt, TypeFold
3030use rustc_session:: lint:: builtin:: { AMBIGUOUS_ASSOCIATED_ITEMS , BARE_TRAIT_OBJECTS } ;
3131use rustc_span:: edition:: Edition ;
3232use rustc_span:: lev_distance:: find_best_match_for_name;
33- use rustc_span:: symbol:: { Ident , Symbol } ;
33+ use rustc_span:: symbol:: { kw , Ident , Symbol } ;
3434use rustc_span:: { Span , DUMMY_SP } ;
3535use rustc_target:: spec:: abi;
3636use rustc_trait_selection:: traits;
@@ -653,7 +653,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
653653 span, item_def_id, item_segment
654654 ) ;
655655 if tcx. generics_of ( item_def_id) . params . is_empty ( ) {
656- self . prohibit_generics ( slice:: from_ref ( item_segment) . iter ( ) ) ;
656+ self . prohibit_generics ( slice:: from_ref ( item_segment) . iter ( ) , |_| { } ) ;
657657
658658 parent_substs
659659 } else {
@@ -681,7 +681,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
681681 trait_ref : & hir:: TraitRef < ' _ > ,
682682 self_ty : Ty < ' tcx > ,
683683 ) -> ty:: TraitRef < ' tcx > {
684- self . prohibit_generics ( trait_ref. path . segments . split_last ( ) . unwrap ( ) . 1 . iter ( ) ) ;
684+ self . prohibit_generics ( trait_ref. path . segments . split_last ( ) . unwrap ( ) . 1 . iter ( ) , |_| { } ) ;
685685
686686 self . ast_path_to_mono_trait_ref (
687687 trait_ref. path . span ,
@@ -784,7 +784,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
784784 let args = trait_segment. args ( ) ;
785785 let infer_args = trait_segment. infer_args ;
786786
787- self . prohibit_generics ( trait_ref. path . segments . split_last ( ) . unwrap ( ) . 1 . iter ( ) ) ;
787+ self . prohibit_generics ( trait_ref. path . segments . split_last ( ) . unwrap ( ) . 1 . iter ( ) , |_| { } ) ;
788788 self . complain_about_internal_fn_trait ( span, trait_def_id, trait_segment, false ) ;
789789
790790 self . instantiate_poly_trait_ref_inner (
@@ -1776,12 +1776,17 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
17761776 hir_ref_id : hir:: HirId ,
17771777 span : Span ,
17781778 qself_ty : Ty < ' tcx > ,
1779- qself_res : Res ,
1779+ qself : & hir :: Ty < ' _ > ,
17801780 assoc_segment : & hir:: PathSegment < ' _ > ,
17811781 permit_variants : bool ,
17821782 ) -> Result < ( Ty < ' tcx > , DefKind , DefId ) , ErrorGuaranteed > {
17831783 let tcx = self . tcx ( ) ;
17841784 let assoc_ident = assoc_segment. ident ;
1785+ let qself_res = if let hir:: TyKind :: Path ( hir:: QPath :: Resolved ( _, ref path) ) = qself. kind {
1786+ path. res
1787+ } else {
1788+ Res :: Err
1789+ } ;
17851790
17861791 debug ! ( "associated_path_to_ty: {:?}::{}" , qself_ty, assoc_ident) ;
17871792
@@ -1796,7 +1801,55 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
17961801 if let Some ( variant_def) = variant_def {
17971802 if permit_variants {
17981803 tcx. check_stability ( variant_def. def_id , Some ( hir_ref_id) , span, None ) ;
1799- self . prohibit_generics ( slice:: from_ref ( assoc_segment) . iter ( ) ) ;
1804+ self . prohibit_generics ( slice:: from_ref ( assoc_segment) . iter ( ) , |err| {
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}" ) ;
1809+ let Some ( args) = assoc_segment. args else { return ; } ;
1810+ let args_span = assoc_segment. ident . span . shrink_to_hi ( ) . to ( args. span_ext ) ;
1811+ let Ok ( snippet) = tcx. sess . source_map ( ) . span_to_snippet ( args_span) else {
1812+ err. note ( & msg) ;
1813+ return ;
1814+ } ;
1815+ let ( qself_sugg_span, is_self) = if let hir:: TyKind :: Path ( hir:: QPath :: Resolved ( _, ref path) ) = qself. kind {
1816+ // If the path segment already has type params, we want to overwrite
1817+ // them.
1818+ match & path. segments [ ..] {
1819+ [ .., segment, _] => (
1820+ segment. ident . span . shrink_to_hi ( ) . to ( segment. args . map_or (
1821+ segment. ident . span . shrink_to_hi ( ) ,
1822+ |a| a. span_ext ) ) ,
1823+ false ,
1824+ ) ,
1825+ [ segment] => (
1826+ segment. ident . span . shrink_to_hi ( ) . to ( segment. args . map_or (
1827+ segment. ident . span . shrink_to_hi ( ) ,
1828+ |a| a. span_ext ) ) ,
1829+ kw:: SelfUpper == segment. ident . name ,
1830+ ) ,
1831+ _ => unreachable ! ( ) ,
1832+ }
1833+ } else {
1834+ err. note ( & msg) ;
1835+ return ;
1836+ } ;
1837+ let Some ( type_name) = type_name else {
1838+ err. note ( & msg) ;
1839+ return ;
1840+ } ;
1841+ let suggestion = vec ! [
1842+ if is_self {
1843+ // Account for people writing `Self::Variant::<Args>`, where
1844+ // `Self` is the enum.
1845+ ( qself. span, format!( "{type_name}{snippet}" ) )
1846+ } else {
1847+ ( qself_sugg_span, snippet)
1848+ } ,
1849+ ( args_span, String :: new( ) ) ,
1850+ ] ;
1851+ err. multipart_suggestion_verbose ( & msg, suggestion, Applicability :: MaybeIncorrect ) ;
1852+ } ) ;
18001853 return Ok ( ( qself_ty, DefKind :: Variant , variant_def. def_id ) ) ;
18011854 } else {
18021855 variant_resolution = Some ( variant_def. def_id ) ;
@@ -2017,9 +2070,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
20172070 self . normalize_ty ( span, tcx. mk_projection ( item_def_id, item_substs) )
20182071 }
20192072
2020- pub fn prohibit_generics < ' a , T : Iterator < Item = & ' a hir :: PathSegment < ' a > > + Clone > (
2073+ pub fn prohibit_generics < ' a > (
20212074 & self ,
2022- segments : T ,
2075+ segments : impl Iterator < Item = & ' a hir:: PathSegment < ' a > > + Clone ,
2076+ extend : impl Fn ( & mut DiagnosticBuilder < ' tcx , ErrorGuaranteed > ) ,
20232077 ) -> bool {
20242078 let args = segments. clone ( ) . flat_map ( |segment| segment. args ( ) . args ) ;
20252079
@@ -2078,6 +2132,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
20782132 "{kind} arguments are not allowed for this type" ,
20792133 ) ;
20802134 err. span_label ( last_span, format ! ( "{kind} argument{s} not allowed" ) ) ;
2135+ extend ( & mut err) ;
20812136 err. emit ( ) ;
20822137 emitted = true ;
20832138 }
@@ -2239,7 +2294,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
22392294 // Check for desugared `impl Trait`.
22402295 assert ! ( ty:: is_impl_trait_defn( tcx, did) . is_none( ) ) ;
22412296 let item_segment = path. segments . split_last ( ) . unwrap ( ) ;
2242- self . prohibit_generics ( item_segment. 1 . iter ( ) ) ;
2297+ self . prohibit_generics ( item_segment. 1 . iter ( ) , |err| {
2298+ err. note ( "`impl Trait` types can't have type parameters" ) ;
2299+ } ) ;
22432300 let substs = self . ast_path_substs_for_ty ( span, did, item_segment. 0 ) ;
22442301 self . normalize_ty ( span, tcx. mk_opaque ( did, substs) )
22452302 }
@@ -2252,7 +2309,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
22522309 did,
22532310 ) => {
22542311 assert_eq ! ( opt_self_ty, None ) ;
2255- self . prohibit_generics ( path. segments . split_last ( ) . unwrap ( ) . 1 . iter ( ) ) ;
2312+ self . prohibit_generics ( path. segments . split_last ( ) . unwrap ( ) . 1 . iter ( ) , |_| { } ) ;
22562313 self . ast_path_to_ty ( span, did, path. segments . last ( ) . unwrap ( ) )
22572314 }
22582315 Res :: Def ( kind @ DefKind :: Variant , def_id) if permit_variants => {
@@ -2264,18 +2321,26 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
22642321 self . def_ids_for_value_path_segments ( path. segments , None , kind, def_id) ;
22652322 let generic_segs: FxHashSet < _ > =
22662323 path_segs. iter ( ) . map ( |PathSeg ( _, index) | index) . collect ( ) ;
2267- self . prohibit_generics ( path . segments . iter ( ) . enumerate ( ) . filter_map (
2268- |( index, seg) | {
2324+ self . prohibit_generics (
2325+ path . segments . iter ( ) . enumerate ( ) . filter_map ( |( index, seg) | {
22692326 if !generic_segs. contains ( & index) { Some ( seg) } else { None }
2327+ } ) ,
2328+ |err| {
2329+ err. note ( "enum variants can't have type parameters" ) ;
22702330 } ,
2271- ) ) ;
2331+ ) ;
22722332
22732333 let PathSeg ( def_id, index) = path_segs. last ( ) . unwrap ( ) ;
22742334 self . ast_path_to_ty ( span, * def_id, & path. segments [ * index] )
22752335 }
22762336 Res :: Def ( DefKind :: TyParam , def_id) => {
22772337 assert_eq ! ( opt_self_ty, None ) ;
2278- self . prohibit_generics ( path. segments . iter ( ) ) ;
2338+ self . prohibit_generics ( path. segments . iter ( ) , |err| {
2339+ if let Some ( span) = tcx. def_ident_span ( def_id) {
2340+ let name = tcx. item_name ( def_id) ;
2341+ err. span_note ( span, & format ! ( "type parameter `{name}` defined here" ) ) ;
2342+ }
2343+ } ) ;
22792344
22802345 let def_id = def_id. expect_local ( ) ;
22812346 let item_def_id = tcx. hir ( ) . ty_param_owner ( def_id) ;
@@ -2286,15 +2351,63 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
22862351 Res :: SelfTy { trait_ : Some ( _) , alias_to : None } => {
22872352 // `Self` in trait or type alias.
22882353 assert_eq ! ( opt_self_ty, None ) ;
2289- self . prohibit_generics ( path. segments . iter ( ) ) ;
2354+ self . prohibit_generics ( path. segments . iter ( ) , |err| {
2355+ if let [ hir:: PathSegment { args : Some ( args) , ident, .. } ] = & path. segments [ ..] {
2356+ err. span_suggestion_verbose (
2357+ ident. span . shrink_to_hi ( ) . to ( args. span_ext ) ,
2358+ "the `Self` type doesn't accept type parameters" ,
2359+ String :: new ( ) ,
2360+ Applicability :: MaybeIncorrect ,
2361+ ) ;
2362+ }
2363+ } ) ;
22902364 tcx. types . self_param
22912365 }
22922366 Res :: SelfTy { trait_ : _, alias_to : Some ( ( def_id, forbid_generic) ) } => {
22932367 // `Self` in impl (we know the concrete type).
22942368 assert_eq ! ( opt_self_ty, None ) ;
2295- self . prohibit_generics ( path. segments . iter ( ) ) ;
22962369 // Try to evaluate any array length constants.
22972370 let ty = tcx. at ( span) . type_of ( def_id) ;
2371+ 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+ self . prohibit_generics ( path. segments . iter ( ) , |err| {
2375+ let def_id = match * ty. kind ( ) {
2376+ ty:: Adt ( self_def, _) => self_def. did ( ) ,
2377+ _ => return ,
2378+ } ;
2379+
2380+ let type_name = tcx. item_name ( def_id) ;
2381+ let span_of_ty = tcx. def_ident_span ( def_id) ;
2382+
2383+ let msg = format ! ( "the `Self` type is `{ty}`" ) ;
2384+ if let ( Ok ( i_sp) , Some ( t_sp) ) = ( span_of_impl, span_of_ty) {
2385+ let i_sp = tcx. sess . source_map ( ) . guess_head_span ( i_sp) ;
2386+ let mut span: MultiSpan = vec ! [ t_sp] . into ( ) ;
2387+ span. push_span_label (
2388+ i_sp,
2389+ & format ! ( "`Self` is `{type_name}` in this `impl`" ) ,
2390+ ) ;
2391+ span. push_span_label ( t_sp, "`Self` corresponds to this type" ) ;
2392+ err. span_note ( span, & msg) ;
2393+ } else {
2394+ err. note ( & msg) ;
2395+ }
2396+ 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+ ) ;
2408+ }
2409+ }
2410+ } ) ;
22982411 // HACK(min_const_generics): Forbid generic `Self` types
22992412 // here as we can't easily do that during nameres.
23002413 //
@@ -2334,7 +2447,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
23342447 }
23352448 Res :: Def ( DefKind :: AssocTy , def_id) => {
23362449 debug_assert ! ( path. segments. len( ) >= 2 ) ;
2337- self . prohibit_generics ( path. segments [ ..path. segments . len ( ) - 2 ] . iter ( ) ) ;
2450+ self . prohibit_generics ( path. segments [ ..path. segments . len ( ) - 2 ] . iter ( ) , |_| { } ) ;
23382451 self . qpath_to_ty (
23392452 span,
23402453 opt_self_ty,
@@ -2345,7 +2458,19 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
23452458 }
23462459 Res :: PrimTy ( prim_ty) => {
23472460 assert_eq ! ( opt_self_ty, None ) ;
2348- self . prohibit_generics ( path. segments . iter ( ) ) ;
2461+ self . prohibit_generics ( path. segments . iter ( ) , |err| {
2462+ let name = prim_ty. name_str ( ) ;
2463+ for segment in path. segments {
2464+ if let Some ( args) = segment. args {
2465+ err. span_suggestion_verbose (
2466+ segment. ident . span . shrink_to_hi ( ) . to ( args. span_ext ) ,
2467+ & format ! ( "primitive type `{name}` doesn't have type parameters" ) ,
2468+ String :: new ( ) ,
2469+ Applicability :: MaybeIncorrect ,
2470+ ) ;
2471+ }
2472+ }
2473+ } ) ;
23492474 match prim_ty {
23502475 hir:: PrimTy :: Bool => tcx. types . bool ,
23512476 hir:: PrimTy :: Char => tcx. types . char ,
@@ -2436,13 +2561,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
24362561 hir:: TyKind :: Path ( hir:: QPath :: TypeRelative ( ref qself, ref segment) ) => {
24372562 debug ! ( ?qself, ?segment) ;
24382563 let ty = self . ast_ty_to_ty_inner ( qself, false , true ) ;
2439-
2440- let res = if let hir:: TyKind :: Path ( hir:: QPath :: Resolved ( _, path) ) = qself. kind {
2441- path. res
2442- } else {
2443- Res :: Err
2444- } ;
2445- self . associated_path_to_ty ( ast_ty. hir_id , ast_ty. span , ty, res, segment, false )
2564+ self . associated_path_to_ty ( ast_ty. hir_id , ast_ty. span , ty, qself, segment, false )
24462565 . map ( |( ty, _, _) | ty)
24472566 . unwrap_or_else ( |_| tcx. ty_error ( ) )
24482567 }
0 commit comments