@@ -31,6 +31,7 @@ use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _;
3131use rustc_trait_selection:: traits:: { self , TraitEngine , TraitEngineExt as _} ;
3232use rustc_type_ir:: fold:: TypeFoldable ;
3333
34+ use std:: cell:: LazyCell ;
3435use std:: ops:: ControlFlow ;
3536
3637pub 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) {
520521 }
521522 }
522523 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) ;
526525 }
527526 DefKind :: ForeignMod => {
528527 let it = tcx. hir ( ) . expect_item ( def_id) ;
@@ -1269,28 +1268,51 @@ fn detect_discriminant_duplicate<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>)
12691268 }
12701269}
12711270
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+ }
12801277
1278+ let generics = tcx. generics_of ( def_id) ;
12811279 if generics. own_counts ( ) . types == 0 {
12821280 return ;
12831281 }
12841282
1285- let mut params_used = BitSet :: new_empty ( generics. params . len ( ) ) ;
1286-
1283+ let ty = tcx. type_of ( def_id) . instantiate_identity ( ) ;
12871284 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.
12901286 assert ! ( tcx. dcx( ) . has_errors( ) . is_some( ) ) ;
12911287 return ;
12921288 }
12931289
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 ( ) ) ;
12941316 for leaf in ty. walk ( ) {
12951317 if let GenericArgKind :: Type ( leaf_ty) = leaf. unpack ( )
12961318 && let ty:: Param ( param) = leaf_ty. kind ( )
@@ -1305,15 +1327,24 @@ pub(super) fn check_type_params_are_used<'tcx>(
13051327 && let ty:: GenericParamDefKind :: Type { .. } = param. kind
13061328 {
13071329 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 {
13101340 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 ( ) ;
13171348 }
13181349 }
13191350}
0 commit comments