Auto merge of #11804 - y21:issue-11803, r=dswij

[`impl_trait_in_params`]: avoid ICE when function with `impl Trait` type has no parameters

Fixes #11803

If I'm reading the old code correctly, it was taking the span of the first parameter (without checking that it exists, which caused the ICE) and uses that to figure out where the generic parameter to insert should go (cc `@blyxyas` you wrote the lint, is that correct?).
This seemed equivalent to just `generics.span`, which doesn't require calculating the spans like that and simplifies it a fair bit

changelog: don't ICE when function has no parameters but generics have an `impl Trait` type
This commit is contained in:
bors 2023-11-15 04:03:44 +00:00
commit 783b914fae
3 changed files with 41 additions and 20 deletions

View file

@ -5,18 +5,10 @@ use rustc_hir as hir;
use rustc_hir::intravisit::FnKind;
use rustc_hir::{Body, GenericParam, Generics, HirId, ImplItem, ImplItemKind, TraitItem, TraitItemKind};
use rustc_lint::LateContext;
use rustc_span::symbol::Ident;
use rustc_span::{BytePos, Span};
use super::IMPL_TRAIT_IN_PARAMS;
fn report(
cx: &LateContext<'_>,
param: &GenericParam<'_>,
ident: &Ident,
generics: &Generics<'_>,
first_param_span: Span,
) {
fn report(cx: &LateContext<'_>, param: &GenericParam<'_>, generics: &Generics<'_>) {
// No generics with nested generics, and no generics like FnMut(x)
span_lint_and_then(
cx,
@ -35,12 +27,7 @@ fn report(
);
} else {
diag.span_suggestion_with_style(
Span::new(
first_param_span.lo() - rustc_span::BytePos(1),
ident.span.hi(),
ident.span.ctxt(),
ident.span.parent(),
),
generics.span,
"add a type parameter",
format!("<{{ /* Generic name */ }}: {}>", &param.name.ident().as_str()[5..]),
rustc_errors::Applicability::HasPlaceholders,
@ -52,13 +39,13 @@ fn report(
}
pub(super) fn check_fn<'tcx>(cx: &LateContext<'_>, kind: &'tcx FnKind<'_>, body: &'tcx Body<'_>, hir_id: HirId) {
if let FnKind::ItemFn(ident, generics, _) = kind
if let FnKind::ItemFn(_, generics, _) = kind
&& cx.tcx.visibility(cx.tcx.hir().body_owner_def_id(body.id())).is_public()
&& !is_in_test_function(cx.tcx, hir_id)
{
for param in generics.params {
if param.is_impl_trait() {
report(cx, param, ident, generics, body.params[0].span);
report(cx, param, generics);
};
}
}
@ -76,7 +63,7 @@ pub(super) fn check_impl_item(cx: &LateContext<'_>, impl_item: &ImplItem<'_>) {
{
for param in impl_item.generics.params {
if param.is_impl_trait() {
report(cx, param, &impl_item.ident, impl_item.generics, body.params[0].span);
report(cx, param, impl_item.generics);
}
}
}
@ -92,8 +79,7 @@ pub(super) fn check_trait_item(cx: &LateContext<'_>, trait_item: &TraitItem<'_>,
{
for param in trait_item.generics.params {
if param.is_impl_trait() {
let sp = trait_item.ident.span.with_hi(trait_item.ident.span.hi() + BytePos(1));
report(cx, param, &trait_item.ident, trait_item.generics, sp.shrink_to_hi());
report(cx, param, trait_item.generics);
}
}
}

View file

@ -0,0 +1,9 @@
//@no-rustfix
#![warn(clippy::impl_trait_in_params)]
pub fn g<T: IntoIterator<Item = impl Iterator<Item = impl Clone>>>() {
extern "C" fn implementation_detail() {}
}
fn main() {}

View file

@ -0,0 +1,26 @@
error: `impl Trait` used as a function parameter
--> $DIR/ice-11803.rs:5:54
|
LL | pub fn g<T: IntoIterator<Item = impl Iterator<Item = impl Clone>>>() {
| ^^^^^^^^^^
|
= note: `-D clippy::impl-trait-in-params` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(clippy::impl_trait_in_params)]`
help: add a type parameter
|
LL | pub fn g<T: IntoIterator<Item = impl Iterator<Item = impl Clone>>, { /* Generic name */ }: Clone>() {
| +++++++++++++++++++++++++++++++
error: `impl Trait` used as a function parameter
--> $DIR/ice-11803.rs:5:33
|
LL | pub fn g<T: IntoIterator<Item = impl Iterator<Item = impl Clone>>>() {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
help: add a type parameter
|
LL | pub fn g<T: IntoIterator<Item = impl Iterator<Item = impl Clone>>, { /* Generic name */ }: Iterator<Item = impl Clone>>() {
| +++++++++++++++++++++++++++++++++++++++++++++++++++++
error: aborting due to 2 previous errors