Store all generic bounds as where predicates.

This commit is contained in:
Camille GILLOT 2022-02-07 22:58:30 +01:00
parent 67241bb03c
commit e2d923ac3b
3 changed files with 41 additions and 43 deletions

View File

@ -139,28 +139,35 @@ fn check_fn_inner<'tcx>(
.iter()
.filter(|param| matches!(param.kind, GenericParamKind::Type { .. }));
for typ in types {
for bound in typ.bounds {
let mut visitor = RefVisitor::new(cx);
walk_param_bound(&mut visitor, bound);
if visitor.lts.iter().any(|lt| matches!(lt, RefLt::Named(_))) {
return;
for pred in generics.bounds_for_param(cx.tcx.hir().local_def_id(typ.hir_id)) {
if pred.in_where_clause {
// has_where_lifetimes checked that this predicate contains no lifetime.
continue;
}
if let GenericBound::Trait(ref trait_ref, _) = *bound {
let params = &trait_ref
.trait_ref
.path
.segments
.last()
.expect("a path must have at least one segment")
.args;
if let Some(params) = *params {
let lifetimes = params.args.iter().filter_map(|arg| match arg {
GenericArg::Lifetime(lt) => Some(lt),
_ => None,
});
for bound in lifetimes {
if bound.name != LifetimeName::Static && !bound.is_elided() {
return;
for bound in pred.bounds {
let mut visitor = RefVisitor::new(cx);
walk_param_bound(&mut visitor, bound);
if visitor.lts.iter().any(|lt| matches!(lt, RefLt::Named(_))) {
return;
}
if let GenericBound::Trait(ref trait_ref, _) = *bound {
let params = &trait_ref
.trait_ref
.path
.segments
.last()
.expect("a path must have at least one segment")
.args;
if let Some(params) = *params {
let lifetimes = params.args.iter().filter_map(|arg| match arg {
GenericArg::Lifetime(lt) => Some(lt),
_ => None,
});
for bound in lifetimes {
if bound.name != LifetimeName::Static && !bound.is_elided() {
return;
}
}
}
}
@ -322,9 +329,7 @@ fn allowed_lts_from(named_generics: &[GenericParam<'_>]) -> FxHashSet<RefLt> {
let mut allowed_lts = FxHashSet::default();
for par in named_generics.iter() {
if let GenericParamKind::Lifetime { .. } = par.kind {
if par.bounds.is_empty() {
allowed_lts.insert(RefLt::Named(par.name.ident().name));
}
allowed_lts.insert(RefLt::Named(par.name.ident().name));
}
}
allowed_lts.insert(RefLt::Unnamed);

View File

@ -8,8 +8,7 @@
use rustc_errors::Applicability;
use rustc_hir::def::Res;
use rustc_hir::{
GenericBound, Generics, Item, ItemKind, Node, ParamName, Path, PathSegment, QPath, TraitItem, Ty, TyKind,
WherePredicate,
GenericBound, Generics, Item, ItemKind, Node, Path, PathSegment, QPath, TraitItem, Ty, TyKind, WherePredicate,
};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_tool_lint, impl_lint_pass};
@ -219,30 +218,19 @@ fn check_trait_bound_duplication(cx: &LateContext<'_>, gen: &'_ Generics<'_>) {
return;
}
let mut map = FxHashMap::default();
for param in gen.params {
if let ParamName::Plain(ref ident) = param.name {
let res = param
.bounds
.iter()
.filter_map(get_trait_info_from_bound)
.collect::<Vec<_>>();
map.insert(*ident, res);
}
}
let mut map = FxHashMap::<_, Vec<_>>::default();
for predicate in gen.predicates {
if_chain! {
if let WherePredicate::BoundPredicate(ref bound_predicate) = predicate;
if !bound_predicate.span.from_expansion();
if let TyKind::Path(QPath::Resolved(_, Path { segments, .. })) = bound_predicate.bounded_ty.kind;
if let Some(segment) = segments.first();
if let Some(trait_resolutions_direct) = map.get(&segment.ident);
then {
for (res_where, _, _) in bound_predicate.bounds.iter().filter_map(get_trait_info_from_bound) {
if let Some((_, _, span_direct)) = trait_resolutions_direct
for (res_where, _, span_where) in bound_predicate.bounds.iter().filter_map(get_trait_info_from_bound) {
let trait_resolutions_direct = map.entry(segment.ident).or_default();
if let Some((_, span_direct)) = trait_resolutions_direct
.iter()
.find(|(res_direct, _, _)| *res_direct == res_where) {
.find(|(res_direct, _)| *res_direct == res_where) {
span_lint_and_help(
cx,
TRAIT_DUPLICATION_IN_BOUNDS,
@ -252,6 +240,9 @@ fn check_trait_bound_duplication(cx: &LateContext<'_>, gen: &'_ Generics<'_>) {
"consider removing this trait bound",
);
}
else {
trait_resolutions_direct.push((res_where, span_where))
}
}
}
}

View File

@ -104,8 +104,10 @@ fn get_bounds_if_impl_trait<'tcx>(cx: &LateContext<'tcx>, qpath: &QPath<'_>, id:
if let Some(Node::GenericParam(generic_param)) = cx.tcx.hir().get_if_local(did);
if let GenericParamKind::Type { synthetic, .. } = generic_param.kind;
if synthetic;
if let Some(generics) = cx.tcx.hir().get_generics(id.owner);
if let Some(pred) = generics.bounds_for_param(did.expect_local()).next();
then {
Some(generic_param.bounds)
Some(pred.bounds)
} else {
None
}