diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 45a363b97722a..78d27b71015f6 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1095,6 +1095,93 @@ impl<'hir> Generics<'hir> { bound_span.with_lo(bounds[bound_pos - 1].span().hi()) } } + + /// Computes the span representing the removal of a generic parameter at `param_index`. + /// + /// This function identifies the correct slice of source code to delete so that the + /// remaining generic list remains syntactically valid (handling commas and brackets). + /// + /// ### Examples + /// + /// 1. **With a following parameter:** (Includes the trailing comma) + /// - Input: `` (index 0) + /// - Produces span for: `T, ` + /// + /// 2. **With a previous parameter:** (Includes the leading comma and bounds) + /// - Input: `` (index 1) + /// - Produces span for: `, U` + /// + /// 3. **The only parameter:** (Includes the angle brackets) + /// - Input: `` (index 0) + /// - Produces span for: `` + /// + /// 4. **Parameter with where-clause bounds:** + /// - Input: `fn foo() where T: Copy` (index 0) + /// - Produces span for: `T, ` (The where-clause remains for other logic to handle). + pub fn span_for_param_removal(&self, param_index: usize) -> Span { + if param_index >= self.params.len() { + return self.span.shrink_to_hi(); + } + + let is_impl_generic = |par: &&GenericParam<'_>| match par.kind { + GenericParamKind::Type { .. } + | GenericParamKind::Const { .. } + | GenericParamKind::Lifetime { kind: LifetimeParamKind::Explicit } => true, + _ => false, + }; + + // Find the span of the type parameter. + if let Some(next) = self.params[param_index + 1..].iter().find(is_impl_generic) { + self.params[param_index].span.until(next.span) + } else if let Some(prev) = self.params[..param_index].iter().rfind(is_impl_generic) { + let mut prev_span = prev.span; + // Consider the span of the bounds with the previous generic parameter when there is. + if let Some(prev_bounds_span) = self.span_for_param_bounds(prev) { + prev_span = prev_span.to(prev_bounds_span); + } + + // Consider the span of the bounds with the current generic parameter when there is. + prev_span.shrink_to_hi().to( + if let Some(cur_bounds_span) = self.span_for_param_bounds(&self.params[param_index]) + { + cur_bounds_span + } else { + self.params[param_index].span + }, + ) + } else { + // Remove also angle brackets <> when there is just ONE generic parameter. + self.span + } + } + + /// Returns the span of the `WherePredicate` associated with the given `GenericParam`, if any. + /// + /// This looks specifically for predicates in the `where` clause that were generated + /// from the parameter definition (e.g., `T` in `where T: Bound`). + /// + /// ### Example + /// + /// - Input: `param` representing `T` + /// - Context: `where T: Clone + Default, U: Copy` + /// - Returns: Span of `T: Clone + Default` + fn span_for_param_bounds(&self, param: &GenericParam<'hir>) -> Option { + self.predicates + .iter() + .find(|pred| { + if let WherePredicateKind::BoundPredicate(WhereBoundPredicate { + origin: PredicateOrigin::GenericParam, + bounded_ty, + .. + }) = pred.kind + { + bounded_ty.span == param.span + } else { + false + } + }) + .map(|pred| pred.span) + } } /// A single predicate in a where-clause. diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index 1c999f1ffc93a..53556dfb2b8ab 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -15,6 +15,8 @@ pub(crate) mod wrong_number_of_generic_args; mod precise_captures; pub(crate) use precise_captures::*; +pub(crate) mod remove_or_use_generic; + #[derive(Diagnostic)] #[diag("ambiguous associated {$assoc_kind} `{$assoc_ident}` in bounds of `{$qself}`")] pub(crate) struct AmbiguousAssocItem<'a> { diff --git a/compiler/rustc_hir_analysis/src/errors/remove_or_use_generic.rs b/compiler/rustc_hir_analysis/src/errors/remove_or_use_generic.rs new file mode 100644 index 0000000000000..fe8ef454c35b6 --- /dev/null +++ b/compiler/rustc_hir_analysis/src/errors/remove_or_use_generic.rs @@ -0,0 +1,217 @@ +use std::ops::ControlFlow; + +use rustc_errors::{Applicability, Diag}; +use rustc_hir::def::DefKind; +use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_hir::intravisit::{self, Visitor, walk_lifetime}; +use rustc_hir::{GenericArg, HirId, LifetimeKind, Path, QPath, TyKind}; +use rustc_middle::hir::nested_filter::All; +use rustc_middle::ty::{GenericParamDef, GenericParamDefKind, TyCtxt}; + +use crate::hir::def::Res; + +/// Use a Visitor to find usages of the type or lifetime parameter +struct ParamUsageVisitor<'tcx> { + tcx: TyCtxt<'tcx>, + /// The `DefId` of the generic parameter we are looking for. + param_def_id: DefId, + found: bool, +} + +impl<'tcx> Visitor<'tcx> for ParamUsageVisitor<'tcx> { + type NestedFilter = All; + + fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt { + self.tcx + } + + type Result = ControlFlow<()>; + + fn visit_path(&mut self, path: &Path<'tcx>, _id: HirId) -> Self::Result { + if let Some(res_def_id) = path.res.opt_def_id() { + if res_def_id == self.param_def_id { + self.found = true; + return ControlFlow::Break(()); + } + } + intravisit::walk_path(self, path) + } + + fn visit_lifetime(&mut self, lifetime: &'tcx rustc_hir::Lifetime) -> Self::Result { + if let LifetimeKind::Param(id) = lifetime.kind { + if let Some(local_def_id) = self.param_def_id.as_local() { + if id == local_def_id { + self.found = true; + return ControlFlow::Break(()); + } + } + } + walk_lifetime(self, lifetime) + } +} + +/// Adds a suggestion to a diagnostic to either remove an unused generic parameter, or use it. +/// +/// # Examples +/// +/// - `impl Struct { ... }` where `T` is unused -> suggests removing `T` or using it. +/// - `impl<'a> Struct { ... }` where `'a` is unused -> suggests removing `'a`. +/// - `impl Struct { // T used in here }` where `T` is used in the body but not in the self type -> suggests adding `T` to the self type and struct definition. +/// - `impl Struct { ... }` where the struct has a generic parameter with a default -> suggests adding `T` to the self type. +pub(crate) fn suggest_to_remove_or_use_generic( + tcx: TyCtxt<'_>, + diag: &mut Diag<'_>, + impl_def_id: LocalDefId, + param: &GenericParamDef, + is_lifetime: bool, +) { + let node = tcx.hir_node_by_def_id(impl_def_id); + let hir_impl = node.expect_item().expect_impl(); + + let Some((index, _)) = hir_impl + .generics + .params + .iter() + .enumerate() + .find(|(_, par)| par.def_id.to_def_id() == param.def_id) + else { + return; + }; + + // Get the Struct/ADT definition ID from the self type + let struct_def_id = if let TyKind::Path(QPath::Resolved(_, path)) = hir_impl.self_ty.kind + && let Res::Def(DefKind::Struct | DefKind::Enum | DefKind::Union, def_id) = path.res + { + def_id + } else { + return; + }; + + // Count how many generic parameters are defined in the struct definition + let generics = tcx.generics_of(struct_def_id); + let total_params = generics + .own_params + .iter() + .filter(|p| { + if is_lifetime { + matches!(p.kind, GenericParamDefKind::Lifetime) + } else { + matches!(p.kind, GenericParamDefKind::Type { .. }) + } + }) + .count(); + + // Count how many arguments are currently provided in the impl + let mut provided_params = 0; + let mut last_segment_args = None; + + if let TyKind::Path(QPath::Resolved(_, path)) = hir_impl.self_ty.kind + && let Some(seg) = path.segments.last() + && let Some(args) = seg.args + { + last_segment_args = Some(args); + provided_params = args + .args + .iter() + .filter(|arg| match arg { + GenericArg::Lifetime(_) => is_lifetime, + GenericArg::Type(_) => !is_lifetime, + _ => false, + }) + .count(); + } + + let mut visitor = ParamUsageVisitor { tcx, param_def_id: param.def_id, found: false }; + for item_ref in hir_impl.items { + let _ = visitor.visit_impl_item_ref(item_ref); + if visitor.found { + break; + } + } + let is_param_used = visitor.found; + + let mut suggestions = vec![]; + + // Option A: Remove (Only if not used in body) + if !is_param_used { + suggestions.push((hir_impl.generics.span_for_param_removal(index), String::new())); + } + + // Option B: Suggest adding only if there's an available parameter in the struct definition + // or the parameter is already used somewhere, then we suggest adding to the impl struct and the struct definition + if provided_params < total_params || is_param_used { + if let Some(args) = last_segment_args { + // Struct already has <...>, append to it + suggestions.push((args.span().unwrap().shrink_to_hi(), format!(", {}", param.name))); + } else if let TyKind::Path(QPath::Resolved(_, path)) = hir_impl.self_ty.kind { + // Struct has no <...> yet, add it + let seg = path.segments.last().unwrap(); + suggestions.push((seg.ident.span.shrink_to_hi(), format!("<{}>", param.name))); + } + if is_param_used { + // If the parameter is used in the body, we also want to suggest adding it to the struct definition if it's not already there + let struct_span = tcx.def_span(struct_def_id); + let struct_generic_params = tcx + .hir_node_by_def_id(struct_def_id.expect_local()) + .expect_item() + .expect_struct() + .1 + .params; + if struct_generic_params.len() > 0 { + let last_param = struct_generic_params.last().unwrap(); + suggestions.push((last_param.span.shrink_to_hi(), format!(", {}", param.name))); + } else { + suggestions.push((struct_span.shrink_to_hi(), format!("<{}>", param.name))); + } + } + } + + if suggestions.is_empty() { + return; + } + + let parameter_type = if is_lifetime { "lifetime" } else { "type" }; + if is_param_used { + let msg = format!( + "make use of the {} parameter `{}` in the `self` type", + parameter_type, param.name + ); + diag.span_suggestion( + suggestions[0].0, + msg, + suggestions[0].1.clone(), + Applicability::MaybeIncorrect, + ); + let msg2 = format!( + "and add it to the struct definition of {} as well since it's used in the body of the impl", + tcx.def_path_str(struct_def_id) + ); + diag.span_suggestion( + suggestions[1].0, + msg2, + suggestions[1].1.clone(), + Applicability::MaybeIncorrect, + ); + } else { + let msg = if suggestions.len() == 2 { + format!("either remove the unused {} parameter `{}`", parameter_type, param.name) + } else { + format!("remove the unused {} parameter `{}`", parameter_type, param.name) + }; + diag.span_suggestion( + suggestions[0].0, + msg, + suggestions[0].1.clone(), + Applicability::MaybeIncorrect, + ); + if suggestions.len() == 2 { + let msg = format!("or make use of it"); + diag.span_suggestion( + suggestions[1].0, + msg, + suggestions[1].1.clone(), + Applicability::MaybeIncorrect, + ); + } + }; +} diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check.rs b/compiler/rustc_hir_analysis/src/impl_wf_check.rs index 57ee790170384..4d638d378c425 100644 --- a/compiler/rustc_hir_analysis/src/impl_wf_check.rs +++ b/compiler/rustc_hir_analysis/src/impl_wf_check.rs @@ -21,6 +21,7 @@ use rustc_span::{ErrorGuaranteed, kw}; use crate::constrained_generic_params as cgp; use crate::errors::UnconstrainedGenericParameter; +use crate::errors::remove_or_use_generic::suggest_to_remove_or_use_generic; mod min_specialization; @@ -172,6 +173,7 @@ pub(crate) fn enforce_impl_lifetime_params_are_constrained( ); } } + suggest_to_remove_or_use_generic(tcx, &mut diag, impl_def_id, param, true); res = Err(diag.emit()); } } @@ -235,6 +237,7 @@ pub(crate) fn enforce_impl_non_lifetime_params_are_constrained( const_param_note2: const_param_note, }); diag.code(E0207); + suggest_to_remove_or_use_generic(tcx, &mut diag, impl_def_id, ¶m, false); res = Err(diag.emit()); } } diff --git a/tests/rustdoc-ui/not-wf-ambiguous-normalization.stderr b/tests/rustdoc-ui/not-wf-ambiguous-normalization.stderr index 55ab144b92419..b19d965e7c198 100644 --- a/tests/rustdoc-ui/not-wf-ambiguous-normalization.stderr +++ b/tests/rustdoc-ui/not-wf-ambiguous-normalization.stderr @@ -2,7 +2,10 @@ error[E0207]: the type parameter `T` is not constrained by the impl trait, self --> $DIR/not-wf-ambiguous-normalization.rs:14:6 | LL | impl Allocator for DefaultAllocator { - | ^ unconstrained type parameter + | -^- + | || + | |unconstrained type parameter + | help: remove the unused type parameter `T` error: aborting due to 1 previous error diff --git a/tests/rustdoc-ui/synthetic-auto-trait-impls/unconstrained-param-in-impl-ambiguity.stderr b/tests/rustdoc-ui/synthetic-auto-trait-impls/unconstrained-param-in-impl-ambiguity.stderr index 38d1a537fe458..ba644957127ae 100644 --- a/tests/rustdoc-ui/synthetic-auto-trait-impls/unconstrained-param-in-impl-ambiguity.stderr +++ b/tests/rustdoc-ui/synthetic-auto-trait-impls/unconstrained-param-in-impl-ambiguity.stderr @@ -2,7 +2,10 @@ error[E0207]: the type parameter `Q` is not constrained by the impl trait, self --> $DIR/unconstrained-param-in-impl-ambiguity.rs:7:13 | LL | unsafe impl Send for Inner {} - | ^ unconstrained type parameter + | -^-------- + | || + | |unconstrained type parameter + | help: remove the unused type parameter `Q` error: aborting due to 1 previous error diff --git a/tests/ui/associated-inherent-types/hr-do-not-blame-outlives-static-ice.stderr b/tests/ui/associated-inherent-types/hr-do-not-blame-outlives-static-ice.stderr index 4c0726d4ddca9..bada38b639dbf 100644 --- a/tests/ui/associated-inherent-types/hr-do-not-blame-outlives-static-ice.stderr +++ b/tests/ui/associated-inherent-types/hr-do-not-blame-outlives-static-ice.stderr @@ -12,6 +12,15 @@ error[E0207]: the lifetime parameter `'a` is not constrained by the impl trait, | LL | impl<'a> Foo { | ^^ unconstrained lifetime parameter + | +help: make use of the lifetime parameter `'a` in the `self` type + | +LL | impl<'a> Foo { + | ++++ +help: and add it to the struct definition of Foo as well since it's used in the body of the impl + | +LL | struct Foo(T); + | ++++ error[E0308]: mismatched types --> $DIR/hr-do-not-blame-outlives-static-ice.rs:14:11 diff --git a/tests/ui/associated-inherent-types/inherent-assoc-ty-mismatch-issue-153539.stderr b/tests/ui/associated-inherent-types/inherent-assoc-ty-mismatch-issue-153539.stderr index 74d88889223f3..459f5f4c6d68f 100644 --- a/tests/ui/associated-inherent-types/inherent-assoc-ty-mismatch-issue-153539.stderr +++ b/tests/ui/associated-inherent-types/inherent-assoc-ty-mismatch-issue-153539.stderr @@ -2,7 +2,10 @@ error[E0207]: the type parameter `X` is not constrained by the impl trait, self --> $DIR/inherent-assoc-ty-mismatch-issue-153539.rs:9:6 | LL | impl S<'_> { - | ^ unconstrained type parameter + | -^- + | || + | |unconstrained type parameter + | help: remove the unused type parameter `X` error[E0308]: mismatched types --> $DIR/inherent-assoc-ty-mismatch-issue-153539.rs:17:5 diff --git a/tests/ui/associated-types/issue-26262.stderr b/tests/ui/associated-types/issue-26262.stderr index 90e2d0d930164..fd0cabaa67a25 100644 --- a/tests/ui/associated-types/issue-26262.stderr +++ b/tests/ui/associated-types/issue-26262.stderr @@ -3,6 +3,15 @@ error[E0207]: the type parameter `T` is not constrained by the impl trait, self | LL | impl S { | ^ unconstrained type parameter + | +help: make use of the type parameter `T` in the `self` type + | +LL | impl S { + | +++ +help: and add it to the struct definition of S as well since it's used in the body of the impl + | +LL | struct S(T); + | +++ error[E0207]: the lifetime parameter `'a` is not constrained by the impl trait, self type, or predicates --> $DIR/issue-26262.rs:17:6 diff --git a/tests/ui/associated-types/unconstrained-lifetime-assoc-type.stderr b/tests/ui/associated-types/unconstrained-lifetime-assoc-type.stderr index 15d0820c895dd..0087e69672cb9 100644 --- a/tests/ui/associated-types/unconstrained-lifetime-assoc-type.stderr +++ b/tests/ui/associated-types/unconstrained-lifetime-assoc-type.stderr @@ -3,6 +3,15 @@ error[E0207]: the lifetime parameter `'a` is not constrained by the impl trait, | LL | impl<'a> Fun for Holder { | ^^ unconstrained lifetime parameter + | +help: make use of the lifetime parameter `'a` in the `self` type + | +LL | impl<'a> Fun for Holder<'a> { + | ++++ +help: and add it to the struct definition of Holder as well since it's used in the body of the impl + | +LL | struct Holder<'a> { + | ++++ error: aborting due to 1 previous error diff --git a/tests/ui/async-await/issues/issue-78654.full.stderr b/tests/ui/async-await/issues/issue-78654.full.stderr index 0d12a948c68bd..e1f9aa9ce81e7 100644 --- a/tests/ui/async-await/issues/issue-78654.full.stderr +++ b/tests/ui/async-await/issues/issue-78654.full.stderr @@ -8,7 +8,10 @@ error[E0207]: the const parameter `H` is not constrained by the impl trait, self --> $DIR/issue-78654.rs:9:6 | LL | impl Foo { - | ^^^^^^^^^^^^^^^^ unconstrained const parameter + | -^^^^^^^^^^^^^^^^- + | || + | |unconstrained const parameter + | help: remove the unused type parameter `H` | = note: expressions using a const parameter must map each value to a distinct output value = note: proving the result of expressions other than the parameter are unique is not supported diff --git a/tests/ui/async-await/issues/issue-78654.min.stderr b/tests/ui/async-await/issues/issue-78654.min.stderr index 0d12a948c68bd..e1f9aa9ce81e7 100644 --- a/tests/ui/async-await/issues/issue-78654.min.stderr +++ b/tests/ui/async-await/issues/issue-78654.min.stderr @@ -8,7 +8,10 @@ error[E0207]: the const parameter `H` is not constrained by the impl trait, self --> $DIR/issue-78654.rs:9:6 | LL | impl Foo { - | ^^^^^^^^^^^^^^^^ unconstrained const parameter + | -^^^^^^^^^^^^^^^^- + | || + | |unconstrained const parameter + | help: remove the unused type parameter `H` | = note: expressions using a const parameter must map each value to a distinct output value = note: proving the result of expressions other than the parameter are unique is not supported diff --git a/tests/ui/const-generics/adt_const_params/unsized-anon-const-err-2.stderr b/tests/ui/const-generics/adt_const_params/unsized-anon-const-err-2.stderr index d538bb0af09aa..962b83832ac0b 100644 --- a/tests/ui/const-generics/adt_const_params/unsized-anon-const-err-2.stderr +++ b/tests/ui/const-generics/adt_const_params/unsized-anon-const-err-2.stderr @@ -46,7 +46,10 @@ error[E0207]: the const parameter `N` is not constrained by the impl trait, self --> $DIR/unsized-anon-const-err-2.rs:14:6 | LL | impl Copy for S {} - | ^^^^^^^^^^^^ unconstrained const parameter + | -^^^^^^^^^^^^- + | || + | |unconstrained const parameter + | help: remove the unused type parameter `N` | = note: expressions using a const parameter must map each value to a distinct output value = note: proving the result of expressions other than the parameter are unique is not supported @@ -55,7 +58,10 @@ error[E0207]: the const parameter `M` is not constrained by the impl trait, self --> $DIR/unsized-anon-const-err-2.rs:17:6 | LL | impl Copy for S {} - | ^^^^^^^^^^^^^^ unconstrained const parameter + | -^^^^^^^^^^^^^^- + | || + | |unconstrained const parameter + | help: remove the unused type parameter `M` | = note: expressions using a const parameter must map each value to a distinct output value = note: proving the result of expressions other than the parameter are unique is not supported diff --git a/tests/ui/const-generics/generic_const_exprs/post-analysis-user-facing-param-env.stderr b/tests/ui/const-generics/generic_const_exprs/post-analysis-user-facing-param-env.stderr index 37eb895f9a8d9..9962a6814fcfd 100644 --- a/tests/ui/const-generics/generic_const_exprs/post-analysis-user-facing-param-env.stderr +++ b/tests/ui/const-generics/generic_const_exprs/post-analysis-user-facing-param-env.stderr @@ -33,7 +33,10 @@ error[E0207]: the const parameter `NUM` is not constrained by the impl trait, se --> $DIR/post-analysis-user-facing-param-env.rs:6:10 | LL | impl<'a, const NUM: usize> std::ops::Add<&'a Foo> for Foo - | ^^^^^^^^^^^^^^^^ unconstrained const parameter + | --^^^^^^^^^^^^^^^^ + | | | + | | unconstrained const parameter + | help: remove the unused type parameter `NUM` | = note: expressions using a const parameter must map each value to a distinct output value = note: proving the result of expressions other than the parameter are unique is not supported diff --git a/tests/ui/const-generics/ice-unexpected-inference-var-122549.stderr b/tests/ui/const-generics/ice-unexpected-inference-var-122549.stderr index 311caaede09af..f20c9ab7273d1 100644 --- a/tests/ui/const-generics/ice-unexpected-inference-var-122549.stderr +++ b/tests/ui/const-generics/ice-unexpected-inference-var-122549.stderr @@ -71,6 +71,14 @@ LL | impl<'a, T, const N: usize> Iterator for ConstChunksExact<'a, T, {}> { | = note: expressions using a const parameter must map each value to a distinct output value = note: proving the result of expressions other than the parameter are unique is not supported +help: make use of the type parameter `N` in the `self` type + | +LL | impl<'a, T, const N: usize> Iterator for ConstChunksExact<'a, T, {}, N> { + | +++ +help: and add it to the struct definition of ConstChunksExact as well since it's used in the body of the impl + | +LL | struct ConstChunksExact<'rem, T: 'a, const N: usize, N> {} + | +++ error: aborting due to 8 previous errors diff --git a/tests/ui/const-generics/issues/issue-68366.full.stderr b/tests/ui/const-generics/issues/issue-68366.full.stderr index caed3c1bf3f7d..a6accc2f1d023 100644 --- a/tests/ui/const-generics/issues/issue-68366.full.stderr +++ b/tests/ui/const-generics/issues/issue-68366.full.stderr @@ -14,7 +14,10 @@ error[E0207]: the const parameter `N` is not constrained by the impl trait, self --> $DIR/issue-68366.rs:12:7 | LL | impl Collatz<{Some(N)}> {} - | ^^^^^^^^^^^^^^ unconstrained const parameter + | -^^^^^^^^^^^^^^- + | || + | |unconstrained const parameter + | help: remove the unused type parameter `N` | = note: expressions using a const parameter must map each value to a distinct output value = note: proving the result of expressions other than the parameter are unique is not supported @@ -23,7 +26,10 @@ error[E0207]: the const parameter `N` is not constrained by the impl trait, self --> $DIR/issue-68366.rs:19:6 | LL | impl Foo {} - | ^^^^^^^^^^^^^^ unconstrained const parameter + | -^^^^^^^^^^^^^^- + | || + | |unconstrained const parameter + | help: remove the unused type parameter `N` | = note: expressions using a const parameter must map each value to a distinct output value = note: proving the result of expressions other than the parameter are unique is not supported diff --git a/tests/ui/const-generics/issues/issue-68366.min.stderr b/tests/ui/const-generics/issues/issue-68366.min.stderr index 4d721e958cbc7..e5d3f5508420f 100644 --- a/tests/ui/const-generics/issues/issue-68366.min.stderr +++ b/tests/ui/const-generics/issues/issue-68366.min.stderr @@ -23,7 +23,10 @@ error[E0207]: the const parameter `N` is not constrained by the impl trait, self --> $DIR/issue-68366.rs:12:7 | LL | impl Collatz<{Some(N)}> {} - | ^^^^^^^^^^^^^^ unconstrained const parameter + | -^^^^^^^^^^^^^^- + | || + | |unconstrained const parameter + | help: remove the unused type parameter `N` | = note: expressions using a const parameter must map each value to a distinct output value = note: proving the result of expressions other than the parameter are unique is not supported @@ -32,7 +35,10 @@ error[E0207]: the const parameter `N` is not constrained by the impl trait, self --> $DIR/issue-68366.rs:19:6 | LL | impl Foo {} - | ^^^^^^^^^^^^^^ unconstrained const parameter + | -^^^^^^^^^^^^^^- + | || + | |unconstrained const parameter + | help: remove the unused type parameter `N` | = note: expressions using a const parameter must map each value to a distinct output value = note: proving the result of expressions other than the parameter are unique is not supported diff --git a/tests/ui/const-generics/normalizing_with_unconstrained_impl_params.stderr b/tests/ui/const-generics/normalizing_with_unconstrained_impl_params.stderr index ad89705e1dca8..b084601278956 100644 --- a/tests/ui/const-generics/normalizing_with_unconstrained_impl_params.stderr +++ b/tests/ui/const-generics/normalizing_with_unconstrained_impl_params.stderr @@ -53,6 +53,14 @@ LL | impl<'a, T: std::fmt::Debug, const N: usize> Iterator for ConstChunksExact< | = note: expressions using a const parameter must map each value to a distinct output value = note: proving the result of expressions other than the parameter are unique is not supported +help: make use of the type parameter `N` in the `self` type + | +LL | impl<'a, T: std::fmt::Debug, const N: usize> Iterator for ConstChunksExact<'a, T, {}, N> { + | +++ +help: and add it to the struct definition of ConstChunksExact as well since it's used in the body of the impl + | +LL | struct ConstChunksExact<'a, T: '_, const assert: usize, N> {} + | +++ error[E0308]: mismatched types --> $DIR/normalizing_with_unconstrained_impl_params.rs:6:27 diff --git a/tests/ui/dropck/unconstrained_const_param_on_drop.stderr b/tests/ui/dropck/unconstrained_const_param_on_drop.stderr index 515637dd47fc3..6cf78a06752ba 100644 --- a/tests/ui/dropck/unconstrained_const_param_on_drop.stderr +++ b/tests/ui/dropck/unconstrained_const_param_on_drop.stderr @@ -22,7 +22,10 @@ error[E0207]: the const parameter `UNUSED` is not constrained by the impl trait, --> $DIR/unconstrained_const_param_on_drop.rs:3:6 | LL | impl Drop for Foo {} - | ^^^^^^^^^^^^^^^^^^^ unconstrained const parameter + | -^^^^^^^^^^^^^^^^^^^- + | || + | |unconstrained const parameter + | help: remove the unused type parameter `UNUSED` | = note: expressions using a const parameter must map each value to a distinct output value = note: proving the result of expressions other than the parameter are unique is not supported diff --git a/tests/ui/error-codes/E0207.stderr b/tests/ui/error-codes/E0207.stderr index 01d7c41854412..6d656a6b8c5f7 100644 --- a/tests/ui/error-codes/E0207.stderr +++ b/tests/ui/error-codes/E0207.stderr @@ -3,6 +3,15 @@ error[E0207]: the type parameter `T` is not constrained by the impl trait, self | LL | impl Foo { | ^ unconstrained type parameter + | +help: make use of the type parameter `T` in the `self` type + | +LL | impl Foo { + | +++ +help: and add it to the struct definition of Foo as well since it's used in the body of the impl + | +LL | struct Foo; + | +++ error: aborting due to 1 previous error diff --git a/tests/ui/generic-associated-types/bugs/issue-87735.stderr b/tests/ui/generic-associated-types/bugs/issue-87735.stderr index c3f4f7a73f35f..3e3258d8bedf4 100644 --- a/tests/ui/generic-associated-types/bugs/issue-87735.stderr +++ b/tests/ui/generic-associated-types/bugs/issue-87735.stderr @@ -3,6 +3,15 @@ error[E0207]: the type parameter `U` is not constrained by the impl trait, self | LL | impl<'b, T, U> AsRef2 for Foo | ^ unconstrained type parameter + | +help: make use of the type parameter `U` in the `self` type + | +LL | impl<'b, T, U> AsRef2 for Foo + | +++ +help: and add it to the struct definition of Foo as well since it's used in the body of the impl + | +LL | struct Foo(T); + | +++ error[E0309]: the parameter type `U` may not live long enough --> $DIR/issue-87735.rs:34:3 diff --git a/tests/ui/generic-associated-types/bugs/issue-88526.stderr b/tests/ui/generic-associated-types/bugs/issue-88526.stderr index 5e39eb7a6b95a..ea2962c693f0a 100644 --- a/tests/ui/generic-associated-types/bugs/issue-88526.stderr +++ b/tests/ui/generic-associated-types/bugs/issue-88526.stderr @@ -2,7 +2,10 @@ error[E0207]: the type parameter `I` is not constrained by the impl trait, self --> $DIR/issue-88526.rs:25:13 | LL | impl<'q, Q, I, F> A for TestB - | ^ unconstrained type parameter + | ^-- + | | + | unconstrained type parameter + | help: remove the unused type parameter `I` error[E0309]: the parameter type `F` may not live long enough --> $DIR/issue-88526.rs:16:5 diff --git a/tests/ui/generics/unconstrained-param-default-available.rs b/tests/ui/generics/unconstrained-param-default-available.rs new file mode 100644 index 0000000000000..a602a88cb6d6e --- /dev/null +++ b/tests/ui/generics/unconstrained-param-default-available.rs @@ -0,0 +1,18 @@ +//! Test that making use of parameter is suggested when a parameter with default type is available + +struct S { + _u: U, +} +impl MyTrait for S {} +//~^ ERROR the type parameter `V` is not constrained by the impl trait, self type, or predicates + +struct S2 { + _t: T, + _u: U, +} +impl MyTrait for S2 {} +//~^ ERROR the type parameter `V` is not constrained by the impl trait, self type, or predicates + +trait MyTrait {} + +fn main() {} diff --git a/tests/ui/generics/unconstrained-param-default-available.stderr b/tests/ui/generics/unconstrained-param-default-available.stderr new file mode 100644 index 0000000000000..ea8f02a4cb8a5 --- /dev/null +++ b/tests/ui/generics/unconstrained-param-default-available.stderr @@ -0,0 +1,35 @@ +error[E0207]: the type parameter `V` is not constrained by the impl trait, self type, or predicates + --> $DIR/unconstrained-param-default-available.rs:6:6 + | +LL | impl MyTrait for S {} + | ^ unconstrained type parameter + | +help: either remove the unused type parameter `V` + | +LL - impl MyTrait for S {} +LL + impl MyTrait for S {} + | +help: or make use of it + | +LL | impl MyTrait for S {} + | +++ + +error[E0207]: the type parameter `V` is not constrained by the impl trait, self type, or predicates + --> $DIR/unconstrained-param-default-available.rs:13:9 + | +LL | impl MyTrait for S2 {} + | ^ unconstrained type parameter + | +help: either remove the unused type parameter `V` + | +LL - impl MyTrait for S2 {} +LL + impl MyTrait for S2 {} + | +help: or make use of it + | +LL | impl MyTrait for S2 {} + | +++ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0207`. diff --git a/tests/ui/generics/unconstrained-type-params-inherent-impl.stderr b/tests/ui/generics/unconstrained-type-params-inherent-impl.stderr index 19b02ad396cd3..958b1ff0664ab 100644 --- a/tests/ui/generics/unconstrained-type-params-inherent-impl.stderr +++ b/tests/ui/generics/unconstrained-type-params-inherent-impl.stderr @@ -2,13 +2,19 @@ error[E0207]: the type parameter `T` is not constrained by the impl trait, self --> $DIR/unconstrained-type-params-inherent-impl.rs:11:6 | LL | impl MyType { - | ^ unconstrained type parameter + | -^- + | || + | |unconstrained type parameter + | help: remove the unused type parameter `T` error[E0207]: the type parameter `U` is not constrained by the impl trait, self type, or predicates --> $DIR/unconstrained-type-params-inherent-impl.rs:20:9 | LL | impl MyType1 { - | ^ unconstrained type parameter + | --^ + | | | + | | unconstrained type parameter + | help: remove the unused type parameter `U` error: aborting due to 2 previous errors diff --git a/tests/ui/generics/unconstrained-used-param.rs b/tests/ui/generics/unconstrained-used-param.rs new file mode 100644 index 0000000000000..592880fcf7527 --- /dev/null +++ b/tests/ui/generics/unconstrained-used-param.rs @@ -0,0 +1,23 @@ +//! Test that making use of parameter is suggested when the parameter is used in the impl +//! but not in the trait or self type + +struct S; +impl S { +//~^ ERROR the type parameter `T` is not constrained by the impl trait, self type, or predicates + fn foo(&self, x: T) { + // use T here + } +} + + +struct S2 { + _f: F, +} +impl S2 { +//~^ ERROR the type parameter `T` is not constrained by the impl trait, self type, or predicates + fn foo(&self, x: T) { + // use T here + } +} + +fn main() {} diff --git a/tests/ui/generics/unconstrained-used-param.stderr b/tests/ui/generics/unconstrained-used-param.stderr new file mode 100644 index 0000000000000..039e7fce62d35 --- /dev/null +++ b/tests/ui/generics/unconstrained-used-param.stderr @@ -0,0 +1,33 @@ +error[E0207]: the type parameter `T` is not constrained by the impl trait, self type, or predicates + --> $DIR/unconstrained-used-param.rs:5:6 + | +LL | impl S { + | ^ unconstrained type parameter + | +help: make use of the type parameter `T` in the `self` type + | +LL | impl S { + | +++ +help: and add it to the struct definition of S as well since it's used in the body of the impl + | +LL | struct S; + | +++ + +error[E0207]: the type parameter `T` is not constrained by the impl trait, self type, or predicates + --> $DIR/unconstrained-used-param.rs:16:9 + | +LL | impl S2 { + | ^ unconstrained type parameter + | +help: make use of the type parameter `T` in the `self` type + | +LL | impl S2 { + | +++ +help: and add it to the struct definition of S2 as well since it's used in the body of the impl + | +LL | struct S2 { + | +++ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0207`. diff --git a/tests/ui/issues/issue-16562.stderr b/tests/ui/issues/issue-16562.stderr index efbd7f712a45a..ac957fdb069d0 100644 --- a/tests/ui/issues/issue-16562.stderr +++ b/tests/ui/issues/issue-16562.stderr @@ -2,7 +2,10 @@ error[E0207]: the type parameter `T` is not constrained by the impl trait, self --> $DIR/issue-16562.rs:10:6 | LL | impl Collection for Col { - | ^ unconstrained type parameter + | ^-- + | | + | unconstrained type parameter + | help: remove the unused type parameter `T` error: aborting due to 1 previous error diff --git a/tests/ui/issues/issue-22886.stderr b/tests/ui/issues/issue-22886.stderr index a04fa677f9ec5..0d27b14e0a2a1 100644 --- a/tests/ui/issues/issue-22886.stderr +++ b/tests/ui/issues/issue-22886.stderr @@ -3,6 +3,15 @@ error[E0207]: the lifetime parameter `'a` is not constrained by the impl trait, | LL | impl<'a> Iterator for Newtype { | ^^ unconstrained lifetime parameter + | +help: make use of the lifetime parameter `'a` in the `self` type + | +LL | impl<'a> Iterator for Newtype<'a> { + | ++++ +help: and add it to the struct definition of Newtype as well since it's used in the body of the impl + | +LL | struct Newtype<'a>(Option>); + | ++++ error: aborting due to 1 previous error diff --git a/tests/ui/issues/issue-35139.stderr b/tests/ui/issues/issue-35139.stderr index 875af70483224..c6af22100360c 100644 --- a/tests/ui/issues/issue-35139.stderr +++ b/tests/ui/issues/issue-35139.stderr @@ -3,6 +3,15 @@ error[E0207]: the lifetime parameter `'a` is not constrained by the impl trait, | LL | impl<'a> MethodType for MTFn { | ^^ unconstrained lifetime parameter + | +help: make use of the lifetime parameter `'a` in the `self` type + | +LL | impl<'a> MethodType for MTFn<'a> { + | ++++ +help: and add it to the struct definition of MTFn as well since it's used in the body of the impl + | +LL | pub struct MTFn<'a>; + | ++++ error: aborting due to 1 previous error diff --git a/tests/ui/traits/error-reporting/leaking-vars-in-cause-code-2.stderr b/tests/ui/traits/error-reporting/leaking-vars-in-cause-code-2.stderr index 9e8194b46c04f..193e144d17cd6 100644 --- a/tests/ui/traits/error-reporting/leaking-vars-in-cause-code-2.stderr +++ b/tests/ui/traits/error-reporting/leaking-vars-in-cause-code-2.stderr @@ -2,7 +2,10 @@ error[E0207]: the type parameter `U` is not constrained by the impl trait, self --> $DIR/leaking-vars-in-cause-code-2.rs:19:9 | LL | impl Trait<()> for B - | ^ unconstrained type parameter + | --^ + | | | + | | unconstrained type parameter + | help: remove the unused type parameter `U` error[E0277]: the trait bound `(): IncompleteGuidance` is not satisfied --> $DIR/leaking-vars-in-cause-code-2.rs:29:19 diff --git a/tests/ui/traits/unconstrained-projection-normalization-2.current.stderr b/tests/ui/traits/unconstrained-projection-normalization-2.current.stderr index 9ce0e8d957dab..ee178fd5720e7 100644 --- a/tests/ui/traits/unconstrained-projection-normalization-2.current.stderr +++ b/tests/ui/traits/unconstrained-projection-normalization-2.current.stderr @@ -3,6 +3,15 @@ error[E0207]: the type parameter `T` is not constrained by the impl trait, self | LL | impl Every for Thing { | ^ unconstrained type parameter + | +help: make use of the type parameter `T` in the `self` type + | +LL | impl Every for Thing { + | +++ +help: and add it to the struct definition of Thing as well since it's used in the body of the impl + | +LL | struct Thing; + | +++ error[E0277]: the size for values of type `T` cannot be known at compilation time --> $DIR/unconstrained-projection-normalization-2.rs:16:18 diff --git a/tests/ui/traits/unconstrained-projection-normalization-2.next.stderr b/tests/ui/traits/unconstrained-projection-normalization-2.next.stderr index 2da655afa935c..6cabb1ad1216a 100644 --- a/tests/ui/traits/unconstrained-projection-normalization-2.next.stderr +++ b/tests/ui/traits/unconstrained-projection-normalization-2.next.stderr @@ -3,6 +3,15 @@ error[E0207]: the type parameter `T` is not constrained by the impl trait, self | LL | impl Every for Thing { | ^ unconstrained type parameter + | +help: make use of the type parameter `T` in the `self` type + | +LL | impl Every for Thing { + | +++ +help: and add it to the struct definition of Thing as well since it's used in the body of the impl + | +LL | struct Thing; + | +++ error[E0277]: the size for values of type `T` cannot be known at compilation time --> $DIR/unconstrained-projection-normalization-2.rs:16:18 diff --git a/tests/ui/traits/unconstrained-projection-normalization.current.stderr b/tests/ui/traits/unconstrained-projection-normalization.current.stderr index c52e8dd68aa87..f2b1a30ff111e 100644 --- a/tests/ui/traits/unconstrained-projection-normalization.current.stderr +++ b/tests/ui/traits/unconstrained-projection-normalization.current.stderr @@ -3,6 +3,15 @@ error[E0207]: the type parameter `T` is not constrained by the impl trait, self | LL | impl Every for Thing { | ^ unconstrained type parameter + | +help: make use of the type parameter `T` in the `self` type + | +LL | impl Every for Thing { + | +++ +help: and add it to the struct definition of Thing as well since it's used in the body of the impl + | +LL | struct Thing; + | +++ error[E0277]: the size for values of type `T` cannot be known at compilation time --> $DIR/unconstrained-projection-normalization.rs:15:18 diff --git a/tests/ui/traits/unconstrained-projection-normalization.next.stderr b/tests/ui/traits/unconstrained-projection-normalization.next.stderr index c52e8dd68aa87..f2b1a30ff111e 100644 --- a/tests/ui/traits/unconstrained-projection-normalization.next.stderr +++ b/tests/ui/traits/unconstrained-projection-normalization.next.stderr @@ -3,6 +3,15 @@ error[E0207]: the type parameter `T` is not constrained by the impl trait, self | LL | impl Every for Thing { | ^ unconstrained type parameter + | +help: make use of the type parameter `T` in the `self` type + | +LL | impl Every for Thing { + | +++ +help: and add it to the struct definition of Thing as well since it's used in the body of the impl + | +LL | struct Thing; + | +++ error[E0277]: the size for values of type `T` cannot be known at compilation time --> $DIR/unconstrained-projection-normalization.rs:15:18 diff --git a/tests/ui/type-alias-impl-trait/ice-failed-to-resolve-instance-for-110696.stderr b/tests/ui/type-alias-impl-trait/ice-failed-to-resolve-instance-for-110696.stderr index d18a824287c0c..4a06b95485690 100644 --- a/tests/ui/type-alias-impl-trait/ice-failed-to-resolve-instance-for-110696.stderr +++ b/tests/ui/type-alias-impl-trait/ice-failed-to-resolve-instance-for-110696.stderr @@ -3,6 +3,15 @@ error[E0207]: the type parameter `T` is not constrained by the impl trait, self | LL | impl>>, U> MyIndex> for Scope { | ^ unconstrained type parameter + | +help: make use of the type parameter `T` in the `self` type + | +LL | impl>>, U> MyIndex> for Scope { + | +++ +help: and add it to the struct definition of Scope as well since it's used in the body of the impl + | +LL | struct Scope(Phantom2>); + | +++ error: item does not constrain `DummyT::{opaque#0}` --> $DIR/ice-failed-to-resolve-instance-for-110696.rs:30:8 diff --git a/tests/ui/type-alias-impl-trait/issue-74244.stderr b/tests/ui/type-alias-impl-trait/issue-74244.stderr index f5ca56bacccf6..6e01425afec5e 100644 --- a/tests/ui/type-alias-impl-trait/issue-74244.stderr +++ b/tests/ui/type-alias-impl-trait/issue-74244.stderr @@ -2,7 +2,10 @@ error[E0207]: the type parameter `T` is not constrained by the impl trait, self --> $DIR/issue-74244.rs:9:6 | LL | impl Allocator for DefaultAllocator { - | ^ unconstrained type parameter + | -^- + | || + | |unconstrained type parameter + | help: remove the unused type parameter `T` error: aborting due to 1 previous error