@@ -30,7 +30,7 @@ use rustc_middle::ty::{self, Const, DefIdTree, EarlyBinder, Ty, TyCtxt, TypeFold
30
30
use rustc_session:: lint:: builtin:: { AMBIGUOUS_ASSOCIATED_ITEMS , BARE_TRAIT_OBJECTS } ;
31
31
use rustc_span:: edition:: Edition ;
32
32
use rustc_span:: lev_distance:: find_best_match_for_name;
33
- use rustc_span:: symbol:: { Ident , Symbol } ;
33
+ use rustc_span:: symbol:: { kw , Ident , Symbol } ;
34
34
use rustc_span:: { Span , DUMMY_SP } ;
35
35
use rustc_target:: spec:: abi;
36
36
use rustc_trait_selection:: traits;
@@ -653,7 +653,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
653
653
span, item_def_id, item_segment
654
654
) ;
655
655
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 ( ) , |_| { } ) ;
657
657
658
658
parent_substs
659
659
} else {
@@ -681,7 +681,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
681
681
trait_ref : & hir:: TraitRef < ' _ > ,
682
682
self_ty : Ty < ' tcx > ,
683
683
) -> 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 ( ) , |_| { } ) ;
685
685
686
686
self . ast_path_to_mono_trait_ref (
687
687
trait_ref. path . span ,
@@ -784,7 +784,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
784
784
let args = trait_segment. args ( ) ;
785
785
let infer_args = trait_segment. infer_args ;
786
786
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 ( ) , |_| { } ) ;
788
788
self . complain_about_internal_fn_trait ( span, trait_def_id, trait_segment, false ) ;
789
789
790
790
self . instantiate_poly_trait_ref_inner (
@@ -1776,12 +1776,17 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
1776
1776
hir_ref_id : hir:: HirId ,
1777
1777
span : Span ,
1778
1778
qself_ty : Ty < ' tcx > ,
1779
- qself_res : Res ,
1779
+ qself : & hir :: Ty < ' _ > ,
1780
1780
assoc_segment : & hir:: PathSegment < ' _ > ,
1781
1781
permit_variants : bool ,
1782
1782
) -> Result < ( Ty < ' tcx > , DefKind , DefId ) , ErrorGuaranteed > {
1783
1783
let tcx = self . tcx ( ) ;
1784
1784
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
+ } ;
1785
1790
1786
1791
debug ! ( "associated_path_to_ty: {:?}::{}" , qself_ty, assoc_ident) ;
1787
1792
@@ -1796,7 +1801,55 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
1796
1801
if let Some ( variant_def) = variant_def {
1797
1802
if permit_variants {
1798
1803
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
+ } ) ;
1800
1853
return Ok ( ( qself_ty, DefKind :: Variant , variant_def. def_id ) ) ;
1801
1854
} else {
1802
1855
variant_resolution = Some ( variant_def. def_id ) ;
@@ -2017,9 +2070,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
2017
2070
self . normalize_ty ( span, tcx. mk_projection ( item_def_id, item_substs) )
2018
2071
}
2019
2072
2020
- pub fn prohibit_generics < ' a , T : Iterator < Item = & ' a hir :: PathSegment < ' a > > + Clone > (
2073
+ pub fn prohibit_generics < ' a > (
2021
2074
& self ,
2022
- segments : T ,
2075
+ segments : impl Iterator < Item = & ' a hir:: PathSegment < ' a > > + Clone ,
2076
+ extend : impl Fn ( & mut DiagnosticBuilder < ' tcx , ErrorGuaranteed > ) ,
2023
2077
) -> bool {
2024
2078
let args = segments. clone ( ) . flat_map ( |segment| segment. args ( ) . args ) ;
2025
2079
@@ -2078,6 +2132,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
2078
2132
"{kind} arguments are not allowed for this type" ,
2079
2133
) ;
2080
2134
err. span_label ( last_span, format ! ( "{kind} argument{s} not allowed" ) ) ;
2135
+ extend ( & mut err) ;
2081
2136
err. emit ( ) ;
2082
2137
emitted = true ;
2083
2138
}
@@ -2239,7 +2294,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
2239
2294
// Check for desugared `impl Trait`.
2240
2295
assert ! ( ty:: is_impl_trait_defn( tcx, did) . is_none( ) ) ;
2241
2296
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
+ } ) ;
2243
2300
let substs = self . ast_path_substs_for_ty ( span, did, item_segment. 0 ) ;
2244
2301
self . normalize_ty ( span, tcx. mk_opaque ( did, substs) )
2245
2302
}
@@ -2252,7 +2309,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
2252
2309
did,
2253
2310
) => {
2254
2311
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 ( ) , |_| { } ) ;
2256
2313
self . ast_path_to_ty ( span, did, path. segments . last ( ) . unwrap ( ) )
2257
2314
}
2258
2315
Res :: Def ( kind @ DefKind :: Variant , def_id) if permit_variants => {
@@ -2264,18 +2321,26 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
2264
2321
self . def_ids_for_value_path_segments ( path. segments , None , kind, def_id) ;
2265
2322
let generic_segs: FxHashSet < _ > =
2266
2323
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) | {
2269
2326
if !generic_segs. contains ( & index) { Some ( seg) } else { None }
2327
+ } ) ,
2328
+ |err| {
2329
+ err. note ( "enum variants can't have type parameters" ) ;
2270
2330
} ,
2271
- ) ) ;
2331
+ ) ;
2272
2332
2273
2333
let PathSeg ( def_id, index) = path_segs. last ( ) . unwrap ( ) ;
2274
2334
self . ast_path_to_ty ( span, * def_id, & path. segments [ * index] )
2275
2335
}
2276
2336
Res :: Def ( DefKind :: TyParam , def_id) => {
2277
2337
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
+ } ) ;
2279
2344
2280
2345
let def_id = def_id. expect_local ( ) ;
2281
2346
let item_def_id = tcx. hir ( ) . ty_param_owner ( def_id) ;
@@ -2286,15 +2351,63 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
2286
2351
Res :: SelfTy { trait_ : Some ( _) , alias_to : None } => {
2287
2352
// `Self` in trait or type alias.
2288
2353
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
+ } ) ;
2290
2364
tcx. types . self_param
2291
2365
}
2292
2366
Res :: SelfTy { trait_ : _, alias_to : Some ( ( def_id, forbid_generic) ) } => {
2293
2367
// `Self` in impl (we know the concrete type).
2294
2368
assert_eq ! ( opt_self_ty, None ) ;
2295
- self . prohibit_generics ( path. segments . iter ( ) ) ;
2296
2369
// Try to evaluate any array length constants.
2297
2370
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
+ } ) ;
2298
2411
// HACK(min_const_generics): Forbid generic `Self` types
2299
2412
// here as we can't easily do that during nameres.
2300
2413
//
@@ -2334,7 +2447,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
2334
2447
}
2335
2448
Res :: Def ( DefKind :: AssocTy , def_id) => {
2336
2449
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 ( ) , |_| { } ) ;
2338
2451
self . qpath_to_ty (
2339
2452
span,
2340
2453
opt_self_ty,
@@ -2345,7 +2458,19 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
2345
2458
}
2346
2459
Res :: PrimTy ( prim_ty) => {
2347
2460
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
+ } ) ;
2349
2474
match prim_ty {
2350
2475
hir:: PrimTy :: Bool => tcx. types . bool ,
2351
2476
hir:: PrimTy :: Char => tcx. types . char ,
@@ -2436,13 +2561,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
2436
2561
hir:: TyKind :: Path ( hir:: QPath :: TypeRelative ( ref qself, ref segment) ) => {
2437
2562
debug ! ( ?qself, ?segment) ;
2438
2563
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 )
2446
2565
. map ( |( ty, _, _) | ty)
2447
2566
. unwrap_or_else ( |_| tcx. ty_error ( ) )
2448
2567
}
0 commit comments