mirror of
https://github.com/rust-lang/rust-clippy
synced 2024-11-23 21:23:56 +00:00
Rollup merge of #97720 - cjgillot:all-fresh, r=petrochenkov
Always create elided lifetime parameters for functions Anonymous and elided lifetimes in functions are sometimes (async fns) --and sometimes not (regular fns)-- desugared to implicit generic parameters. This difference of treatment makes it some downstream analyses more complicated to handle. This step is a pre-requisite to perform lifetime elision resolution on AST. There is currently an inconsistency in the treatment of argument-position impl-trait for functions and async fns: ```rust trait Foo<'a> {} fn foo(t: impl Foo<'_>) {} //~ ERROR missing lifetime specifier async fn async_foo(t: impl Foo<'_>) {} //~ OK fn bar(t: impl Iterator<Item = &'_ u8>) {} //~ ERROR missing lifetime specifier async fn async_bar(t: impl Iterator<Item = &'_ u8>) {} //~ OK ``` The current implementation reports "missing lifetime specifier" on `foo`, but **accepts it** in `async_foo`. This PR **proposes to accept** the anonymous lifetime in both cases as an extra generic lifetime parameter. This change would be insta-stable, so let's ping t-lang. Anonymous lifetimes in GAT bindings keep being forbidden: ```rust fn foo(t: impl Foo<Assoc<'_> = Bar<'_>>) {} ^^ ^^ forbidden ok ``` I started a discussion here: https://rust-lang.zulipchat.com/#narrow/stream/213817-t-lang/topic/Anonymous.20lifetimes.20in.20universal.20impl-trait/near/284968606 r? ``@petrochenkov``
This commit is contained in:
commit
5a6fe3ff58
4 changed files with 12 additions and 7 deletions
|
@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_help;
|
||||||
use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
|
use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
|
||||||
use clippy_utils::{get_trait_def_id, paths, return_ty, trait_ref_of_method};
|
use clippy_utils::{get_trait_def_id, paths, return_ty, trait_ref_of_method};
|
||||||
use if_chain::if_chain;
|
use if_chain::if_chain;
|
||||||
use rustc_hir::{ImplItem, ImplItemKind};
|
use rustc_hir::{GenericParamKind, ImplItem, ImplItemKind};
|
||||||
use rustc_lint::{LateContext, LateLintPass};
|
use rustc_lint::{LateContext, LateLintPass};
|
||||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
||||||
use rustc_span::sym;
|
use rustc_span::sym;
|
||||||
|
@ -102,7 +102,7 @@ impl<'tcx> LateLintPass<'tcx> for InherentToString {
|
||||||
let decl = &signature.decl;
|
let decl = &signature.decl;
|
||||||
if decl.implicit_self.has_implicit_self();
|
if decl.implicit_self.has_implicit_self();
|
||||||
if decl.inputs.len() == 1;
|
if decl.inputs.len() == 1;
|
||||||
if impl_item.generics.params.is_empty();
|
if impl_item.generics.params.iter().all(|p| matches!(p.kind, GenericParamKind::Lifetime { .. }));
|
||||||
|
|
||||||
// Check if return type is String
|
// Check if return type is String
|
||||||
if is_type_diagnostic_item(cx, return_ty(cx, impl_item.hir_id()), sym::String);
|
if is_type_diagnostic_item(cx, return_ty(cx, impl_item.hir_id()), sym::String);
|
||||||
|
|
|
@ -9,8 +9,8 @@ use rustc_hir::intravisit::{
|
||||||
use rustc_hir::FnRetTy::Return;
|
use rustc_hir::FnRetTy::Return;
|
||||||
use rustc_hir::{
|
use rustc_hir::{
|
||||||
BareFnTy, BodyId, FnDecl, GenericArg, GenericBound, GenericParam, GenericParamKind, Generics, Impl, ImplItem,
|
BareFnTy, BodyId, FnDecl, GenericArg, GenericBound, GenericParam, GenericParamKind, Generics, Impl, ImplItem,
|
||||||
ImplItemKind, Item, ItemKind, LangItem, Lifetime, LifetimeName, ParamName, PolyTraitRef, PredicateOrigin,
|
ImplItemKind, Item, ItemKind, LangItem, Lifetime, LifetimeName, LifetimeParamKind, ParamName, PolyTraitRef,
|
||||||
TraitBoundModifier, TraitFn, TraitItem, TraitItemKind, Ty, TyKind, WherePredicate,
|
PredicateOrigin, TraitBoundModifier, TraitFn, TraitItem, TraitItemKind, Ty, TyKind, WherePredicate,
|
||||||
};
|
};
|
||||||
use rustc_lint::{LateContext, LateLintPass};
|
use rustc_lint::{LateContext, LateLintPass};
|
||||||
use rustc_middle::hir::nested_filter as middle_nested_filter;
|
use rustc_middle::hir::nested_filter as middle_nested_filter;
|
||||||
|
@ -338,7 +338,10 @@ fn could_use_elision<'tcx>(
|
||||||
fn allowed_lts_from(named_generics: &[GenericParam<'_>]) -> FxHashSet<RefLt> {
|
fn allowed_lts_from(named_generics: &[GenericParam<'_>]) -> FxHashSet<RefLt> {
|
||||||
let mut allowed_lts = FxHashSet::default();
|
let mut allowed_lts = FxHashSet::default();
|
||||||
for par in named_generics.iter() {
|
for par in named_generics.iter() {
|
||||||
if let GenericParamKind::Lifetime { .. } = par.kind {
|
if let GenericParamKind::Lifetime {
|
||||||
|
kind: LifetimeParamKind::Explicit,
|
||||||
|
} = par.kind
|
||||||
|
{
|
||||||
allowed_lts.insert(RefLt::Named(par.name.ident().name));
|
allowed_lts.insert(RefLt::Named(par.name.ident().name));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -379,6 +382,7 @@ impl<'a, 'tcx> RefVisitor<'a, 'tcx> {
|
||||||
self.lts.push(RefLt::Static);
|
self.lts.push(RefLt::Static);
|
||||||
} else if let LifetimeName::Param(_, ParamName::Fresh) = lt.name {
|
} else if let LifetimeName::Param(_, ParamName::Fresh) = lt.name {
|
||||||
// Fresh lifetimes generated should be ignored.
|
// Fresh lifetimes generated should be ignored.
|
||||||
|
self.lts.push(RefLt::Unnamed);
|
||||||
} else if lt.is_elided() {
|
} else if lt.is_elided() {
|
||||||
self.lts.push(RefLt::Unnamed);
|
self.lts.push(RefLt::Unnamed);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -495,12 +495,13 @@ fn check_mut_from_ref<'tcx>(cx: &LateContext<'tcx>, sig: &FnSig<'_>, body: Optio
|
||||||
if let FnRetTy::Return(ty) = sig.decl.output
|
if let FnRetTy::Return(ty) = sig.decl.output
|
||||||
&& let Some((out, Mutability::Mut, _)) = get_rptr_lm(ty)
|
&& let Some((out, Mutability::Mut, _)) = get_rptr_lm(ty)
|
||||||
{
|
{
|
||||||
|
let out_region = cx.tcx.named_region(out.hir_id);
|
||||||
let args: Option<Vec<_>> = sig
|
let args: Option<Vec<_>> = sig
|
||||||
.decl
|
.decl
|
||||||
.inputs
|
.inputs
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(get_rptr_lm)
|
.filter_map(get_rptr_lm)
|
||||||
.filter(|&(lt, _, _)| lt.name == out.name)
|
.filter(|&(lt, _, _)| cx.tcx.named_region(lt.hir_id) == out_region)
|
||||||
.map(|(_, mutability, span)| (mutability == Mutability::Not).then(|| span))
|
.map(|(_, mutability, span)| (mutability == Mutability::Not).then(|| span))
|
||||||
.collect();
|
.collect();
|
||||||
if let Some(args) = args
|
if let Some(args) = args
|
||||||
|
|
|
@ -31,7 +31,7 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, lt: &Lifetime, m
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
let ltopt = if lt.is_elided() {
|
let ltopt = if lt.name.is_anonymous() {
|
||||||
String::new()
|
String::new()
|
||||||
} else {
|
} else {
|
||||||
format!("{} ", lt.name.ident().as_str())
|
format!("{} ", lt.name.ident().as_str())
|
||||||
|
|
Loading…
Reference in a new issue