Store all generic bounds as where predicates.
This commit is contained in:
parent
67241bb03c
commit
e2d923ac3b
@ -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);
|
||||
|
@ -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))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user