@@ -31,6 +31,7 @@ use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _;
31
31
use rustc_trait_selection:: traits:: { self , TraitEngine , TraitEngineExt as _} ;
32
32
use rustc_type_ir:: fold:: TypeFoldable ;
33
33
34
+ use std:: cell:: LazyCell ;
34
35
use std:: ops:: ControlFlow ;
35
36
36
37
pub fn check_abi ( tcx : TyCtxt < ' _ > , hir_id : hir:: HirId , span : Span , abi : Abi ) {
@@ -520,9 +521,7 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) {
520
521
}
521
522
}
522
523
DefKind :: TyAlias => {
523
- let pty_ty = tcx. type_of ( def_id) . instantiate_identity ( ) ;
524
- let generics = tcx. generics_of ( def_id) ;
525
- check_type_params_are_used ( tcx, generics, pty_ty) ;
524
+ check_type_alias_type_params_are_used ( tcx, def_id) ;
526
525
}
527
526
DefKind :: ForeignMod => {
528
527
let it = tcx. hir ( ) . expect_item ( def_id) ;
@@ -1269,28 +1268,51 @@ fn detect_discriminant_duplicate<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>)
1269
1268
}
1270
1269
}
1271
1270
1272
- pub ( super ) fn check_type_params_are_used < ' tcx > (
1273
- tcx : TyCtxt < ' tcx > ,
1274
- generics : & ty:: Generics ,
1275
- ty : Ty < ' tcx > ,
1276
- ) {
1277
- debug ! ( "check_type_params_are_used(generics={:?}, ty={:?})" , generics, ty) ;
1278
-
1279
- assert_eq ! ( generics. parent, None ) ;
1271
+ fn check_type_alias_type_params_are_used < ' tcx > ( tcx : TyCtxt < ' tcx > , def_id : LocalDefId ) {
1272
+ if tcx. type_alias_is_lazy ( def_id) {
1273
+ // Since we compute the variances for lazy type aliases and already reject bivariant
1274
+ // parameters as unused, we can and should skip this check for lazy type aliases.
1275
+ return ;
1276
+ }
1280
1277
1278
+ let generics = tcx. generics_of ( def_id) ;
1281
1279
if generics. own_counts ( ) . types == 0 {
1282
1280
return ;
1283
1281
}
1284
1282
1285
- let mut params_used = BitSet :: new_empty ( generics. params . len ( ) ) ;
1286
-
1283
+ let ty = tcx. type_of ( def_id) . instantiate_identity ( ) ;
1287
1284
if ty. references_error ( ) {
1288
- // If there is already another error, do not emit
1289
- // an error for not using a type parameter.
1285
+ // If there is already another error, do not emit an error for not using a type parameter.
1290
1286
assert ! ( tcx. dcx( ) . has_errors( ) . is_some( ) ) ;
1291
1287
return ;
1292
1288
}
1293
1289
1290
+ // Lazily calculated because it is only needed in case of an error.
1291
+ let bounded_params = LazyCell :: new ( || {
1292
+ tcx. explicit_predicates_of ( def_id)
1293
+ . predicates
1294
+ . iter ( )
1295
+ . filter_map ( |( predicate, span) | {
1296
+ let bounded_ty = match predicate. kind ( ) . skip_binder ( ) {
1297
+ ty:: ClauseKind :: Trait ( pred) => pred. trait_ref . self_ty ( ) ,
1298
+ ty:: ClauseKind :: TypeOutlives ( pred) => pred. 0 ,
1299
+ _ => return None ,
1300
+ } ;
1301
+ if let ty:: Param ( param) = bounded_ty. kind ( ) {
1302
+ Some ( ( param. index , span) )
1303
+ } else {
1304
+ None
1305
+ }
1306
+ } )
1307
+ // FIXME: This assumes that elaborated `Sized` bounds come first (which does hold at the
1308
+ // time of writing). This is a bit fragile since we later use the span to detect elaborated
1309
+ // `Sized` bounds. If they came last for example, this would break `Trait + /*elab*/Sized`
1310
+ // since it would overwrite the span of the user-written bound. This could be fixed by
1311
+ // folding the spans with `Span::to` which requires a bit of effort I think.
1312
+ . collect :: < FxHashMap < _ , _ > > ( )
1313
+ } ) ;
1314
+
1315
+ let mut params_used = BitSet :: new_empty ( generics. params . len ( ) ) ;
1294
1316
for leaf in ty. walk ( ) {
1295
1317
if let GenericArgKind :: Type ( leaf_ty) = leaf. unpack ( )
1296
1318
&& let ty:: Param ( param) = leaf_ty. kind ( )
@@ -1305,15 +1327,24 @@ pub(super) fn check_type_params_are_used<'tcx>(
1305
1327
&& let ty:: GenericParamDefKind :: Type { .. } = param. kind
1306
1328
{
1307
1329
let span = tcx. def_span ( param. def_id ) ;
1308
- struct_span_code_err ! (
1309
- tcx. dcx( ) ,
1330
+ let param_name = Ident :: new ( param. name , span) ;
1331
+
1332
+ // The corresponding predicates are post-`Sized`-elaboration. Therefore we
1333
+ // * check for emptiness to detect lone user-written `?Sized` bounds
1334
+ // * compare the param span to the pred span to detect lone user-written `Sized` bounds
1335
+ let has_explicit_bounds = bounded_params. is_empty ( )
1336
+ || ( * bounded_params) . get ( & param. index ) . is_some_and ( |& & pred_sp| pred_sp != span) ;
1337
+ let const_param_help = ( !has_explicit_bounds) . then_some ( ( ) ) ;
1338
+
1339
+ let mut diag = tcx. dcx ( ) . create_err ( errors:: UnusedGenericParameter {
1310
1340
span,
1311
- E0091 ,
1312
- "type parameter `{}` is unused" ,
1313
- param. name,
1314
- )
1315
- . with_span_label ( span, "unused type parameter" )
1316
- . emit ( ) ;
1341
+ param_name,
1342
+ param_def_kind : tcx. def_descr ( param. def_id ) ,
1343
+ help : errors:: UnusedGenericParameterHelp :: TyAlias { param_name } ,
1344
+ const_param_help,
1345
+ } ) ;
1346
+ diag. code ( E0091 ) ;
1347
+ diag. emit ( ) ;
1317
1348
}
1318
1349
}
1319
1350
}
0 commit comments