From 45200456cab5e2d6f73917b37e7484c6c36dd7d7 Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Fri, 25 Feb 2022 05:44:33 +0000 Subject: [PATCH] Do not suggest using a const parameter when there are bounds on an unused type parameter The user wrote the bound, so it's obvious they want a type. --- compiler/rustc_typeck/src/check/wfcheck.rs | 36 ++++++++++++++++--- compiler/rustc_typeck/src/lib.rs | 1 + src/test/ui/issues/issue-17904-2.stderr | 1 - src/test/ui/issues/issue-37534.stderr | 1 - .../ui/variance/variance-unused-type-param.rs | 9 +++++ .../variance-unused-type-param.stderr | 26 +++++++++++++- 6 files changed, 67 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs index 4ab654560ea0d..a42ed9eab6436 100644 --- a/compiler/rustc_typeck/src/check/wfcheck.rs +++ b/compiler/rustc_typeck/src/check/wfcheck.rs @@ -31,6 +31,7 @@ use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode, use std::convert::TryInto; use std::iter; +use std::lazy::Lazy; use std::ops::ControlFlow; /// Helper type of a temporary returned by `.for_item(...)`. @@ -1720,8 +1721,29 @@ fn check_variances_for_type_defn<'tcx>( identify_constrained_generic_params(tcx, ty_predicates, None, &mut constrained_parameters); + // Lazily calculated because it is only needed in case of an error. + let explicitly_bounded_params = Lazy::new(|| { + let icx = crate::collect::ItemCtxt::new(tcx, item.def_id.to_def_id()); + hir_generics + .where_clause + .predicates + .iter() + .filter_map(|predicate| match predicate { + hir::WherePredicate::BoundPredicate(predicate) => { + match icx.to_ty(predicate.bounded_ty).kind() { + ty::Param(data) => Some(Parameter(data.index)), + _ => None, + } + } + _ => None, + }) + .collect::>() + }); + for (index, _) in variances.iter().enumerate() { - if constrained_parameters.contains(&Parameter(index as u32)) { + let parameter = Parameter(index as u32); + + if constrained_parameters.contains(¶meter) { continue; } @@ -1730,13 +1752,19 @@ fn check_variances_for_type_defn<'tcx>( match param.name { hir::ParamName::Error => {} _ => { - report_bivariance(tcx, param); + let has_explicit_bounds = + !param.bounds.is_empty() || explicitly_bounded_params.contains(¶meter); + report_bivariance(tcx, param, has_explicit_bounds); } } } } -fn report_bivariance(tcx: TyCtxt<'_>, param: &rustc_hir::GenericParam<'_>) -> ErrorReported { +fn report_bivariance( + tcx: TyCtxt<'_>, + param: &rustc_hir::GenericParam<'_>, + has_explicit_bounds: bool, +) -> ErrorReported { let span = param.span; let param_name = param.name.ident().name; let mut err = error_392(tcx, span, param_name); @@ -1754,7 +1782,7 @@ fn report_bivariance(tcx: TyCtxt<'_>, param: &rustc_hir::GenericParam<'_>) -> Er }; err.help(&msg); - if matches!(param.kind, rustc_hir::GenericParamKind::Type { .. }) { + if matches!(param.kind, hir::GenericParamKind::Type { .. }) && !has_explicit_bounds { err.help(&format!( "if you intended `{0}` to be a const parameter, use `const {0}: usize` instead", param_name diff --git a/compiler/rustc_typeck/src/lib.rs b/compiler/rustc_typeck/src/lib.rs index d415e37ff0116..bbfe5295fe107 100644 --- a/compiler/rustc_typeck/src/lib.rs +++ b/compiler/rustc_typeck/src/lib.rs @@ -68,6 +68,7 @@ This API is completely unstable and subject to change. #![feature(slice_partition_dedup)] #![feature(control_flow_enum)] #![feature(hash_drain_filter)] +#![feature(once_cell)] #![recursion_limit = "256"] #![cfg_attr(not(bootstrap), allow(rustc::potential_query_instability))] diff --git a/src/test/ui/issues/issue-17904-2.stderr b/src/test/ui/issues/issue-17904-2.stderr index 259e029113d50..62b7b79538c61 100644 --- a/src/test/ui/issues/issue-17904-2.stderr +++ b/src/test/ui/issues/issue-17904-2.stderr @@ -5,7 +5,6 @@ LL | struct Foo where T: Copy; | ^ unused parameter | = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData` - = help: if you intended `T` to be a const parameter, use `const T: usize` instead error: aborting due to previous error diff --git a/src/test/ui/issues/issue-37534.stderr b/src/test/ui/issues/issue-37534.stderr index 82bb51028c977..895479986f1d1 100644 --- a/src/test/ui/issues/issue-37534.stderr +++ b/src/test/ui/issues/issue-37534.stderr @@ -22,7 +22,6 @@ LL | struct Foo { } | ^ unused parameter | = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData` - = help: if you intended `T` to be a const parameter, use `const T: usize` instead error: aborting due to 2 previous errors; 1 warning emitted diff --git a/src/test/ui/variance/variance-unused-type-param.rs b/src/test/ui/variance/variance-unused-type-param.rs index 1e0e403ebcee2..d111406436478 100644 --- a/src/test/ui/variance/variance-unused-type-param.rs +++ b/src/test/ui/variance/variance-unused-type-param.rs @@ -16,4 +16,13 @@ enum ListCell { Nil } +struct WithBounds {} +//~^ ERROR parameter `T` is never used + +struct WithWhereBounds where T: Sized {} +//~^ ERROR parameter `T` is never used + +struct WithOutlivesBounds {} +//~^ ERROR parameter `T` is never used + fn main() {} diff --git a/src/test/ui/variance/variance-unused-type-param.stderr b/src/test/ui/variance/variance-unused-type-param.stderr index 270233c0c9772..e612da118f058 100644 --- a/src/test/ui/variance/variance-unused-type-param.stderr +++ b/src/test/ui/variance/variance-unused-type-param.stderr @@ -25,6 +25,30 @@ LL | enum ListCell { = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData` = help: if you intended `T` to be a const parameter, use `const T: usize` instead -error: aborting due to 3 previous errors +error[E0392]: parameter `T` is never used + --> $DIR/variance-unused-type-param.rs:19:19 + | +LL | struct WithBounds {} + | ^ unused parameter + | + = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData` + +error[E0392]: parameter `T` is never used + --> $DIR/variance-unused-type-param.rs:22:24 + | +LL | struct WithWhereBounds where T: Sized {} + | ^ unused parameter + | + = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData` + +error[E0392]: parameter `T` is never used + --> $DIR/variance-unused-type-param.rs:25:27 + | +LL | struct WithOutlivesBounds {} + | ^ unused parameter + | + = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData` + +error: aborting due to 6 previous errors For more information about this error, try `rustc --explain E0392`.