Skip to content

Commit 16f4f18

Browse files
committed
Optimize and eliminate panic
1 parent 8bc8af3 commit 16f4f18

File tree

3 files changed

+54
-44
lines changed

3 files changed

+54
-44
lines changed

clippy_lints/src/dereference.rs

Lines changed: 50 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ use rustc_infer::infer::TyCtxtInferExt;
1717
use rustc_lint::{LateContext, LateLintPass};
1818
use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability};
1919
use rustc_middle::ty::{
20-
self, subst::Subst, EarlyBinder, FnSig, ParamTy, PredicateKind, ProjectionPredicate, TraitPredicate, Ty, TyCtxt,
21-
TypeVisitable, TypeckResults,
20+
self, subst::Subst, EarlyBinder, FnSig, ParamTy, PredicateKind, ProjectionPredicate, TraitPredicate, TraitRef, Ty,
21+
TyCtxt, TypeVisitable, TypeckResults,
2222
};
2323
use rustc_session::{declare_tool_lint, impl_lint_pass};
2424
use rustc_span::{symbol::sym, Span, Symbol};
@@ -971,18 +971,6 @@ fn needless_borrow_impl_arg_position<'tcx>(
971971
});
972972

973973
let predicates = cx.tcx.param_env(callee_def_id).caller_bounds();
974-
let trait_predicates_for_param_ty = predicates
975-
.iter()
976-
.filter_map(|predicate| {
977-
if let PredicateKind::Trait(trait_predicate) = predicate.kind().skip_binder()
978-
&& trait_predicate.trait_ref.self_ty() == param_ty.to_ty(cx.tcx)
979-
{
980-
Some(trait_predicate)
981-
} else {
982-
None
983-
}
984-
})
985-
.collect::<Vec<_>>();
986974
let projection_predicates = predicates
987975
.iter()
988976
.filter_map(|predicate| {
@@ -994,18 +982,26 @@ fn needless_borrow_impl_arg_position<'tcx>(
994982
})
995983
.collect::<Vec<_>>();
996984

985+
let mut trait_with_ref_mut_self_method = false;
986+
997987
// If no traits were found, or only the `Sized` or `Any` traits were found, return.
998-
if trait_predicates_for_param_ty.iter().all(|trait_predicate| {
999-
let trait_def_id = trait_predicate.def_id();
1000-
Some(trait_def_id) == sized_trait_def_id || cx.tcx.is_diagnostic_item(sym::Any, trait_def_id)
988+
if predicates.iter().all(|predicate| {
989+
if let PredicateKind::Trait(TraitPredicate {
990+
trait_ref: TraitRef {
991+
def_id: trait_def_id, ..
992+
},
993+
..
994+
}) = predicate.kind().skip_binder()
995+
{
996+
trait_with_ref_mut_self_method |= has_ref_mut_self_method(cx, trait_def_id);
997+
Some(trait_def_id) == sized_trait_def_id || cx.tcx.is_diagnostic_item(sym::Any, trait_def_id)
998+
} else {
999+
true
1000+
}
10011001
}) {
10021002
return Position::Other(precedence);
10031003
}
10041004

1005-
let has_ref_mut_self_method = trait_predicates_for_param_ty
1006-
.iter()
1007-
.any(|TraitPredicate { trait_ref, .. }| has_ref_mut_self_method(cx, trait_ref.def_id));
1008-
10091005
// `substs_with_referent_ty` can be constructed outside of `check_referent` because the same
10101006
// elements are modified each time `check_referent` is called.
10111007
let mut substs_with_referent_ty = substs_with_expr_ty.to_vec();
@@ -1018,7 +1014,7 @@ fn needless_borrow_impl_arg_position<'tcx>(
10181014
}
10191015

10201016
// https://github.com/rust-lang/rust-clippy/pull/9136#pullrequestreview-1037379321
1021-
if has_ref_mut_self_method && !matches!(referent_ty.kind(), ty::Ref(_, _, Mutability::Mut)) {
1017+
if trait_with_ref_mut_self_method && !matches!(referent_ty.kind(), ty::Ref(_, _, Mutability::Mut)) {
10221018
return false;
10231019
}
10241020

@@ -1087,29 +1083,22 @@ fn replace_types<'tcx>(
10871083
substs: &mut [ty::GenericArg<'tcx>],
10881084
) -> bool {
10891085
let mut replaced = BitSet::new_empty(substs.len());
1090-
10911086
let mut deque = VecDeque::with_capacity(substs.len());
1092-
deque.push_back((param_ty, new_ty));
10931087

1094-
while let Some((param_ty, new_ty)) = deque.pop_front() {
1095-
let new_generic_arg = ty::GenericArg::from(new_ty);
1096-
1097-
// If `replaced.is_empty()`, then `param_ty` and `new_ty` are those initially passed in.
1098-
if !(substs[param_ty.index as usize] == new_generic_arg
1099-
|| fn_sig
1100-
.inputs_and_output
1101-
.iter()
1102-
.enumerate()
1103-
.all(|(i, ty)| (replaced.is_empty() && i == arg_index) || !contains_ty(ty, param_ty.to_ty(cx.tcx))))
1104-
{
1105-
return false;
1106-
}
1088+
if fn_sig
1089+
.inputs_and_output
1090+
.iter()
1091+
.enumerate()
1092+
.any(|(i, ty)| i != arg_index && contains_ty(ty, param_ty.to_ty(cx.tcx)))
1093+
{
1094+
return false;
1095+
}
11071096

1108-
// The next line should not panic, but panicking seems better than going into an infinite loop.
1109-
assert!(replaced.insert(param_ty.index));
1097+
substs[param_ty.index as usize] = ty::GenericArg::from(new_ty);
11101098

1111-
substs[param_ty.index as usize] = new_generic_arg;
1099+
deque.push_back((param_ty, new_ty));
11121100

1101+
while let Some((param_ty, new_ty)) = deque.pop_front() {
11131102
for projection_predicate in projection_predicates {
11141103
if projection_predicate.projection_ty.self_ty() == param_ty.to_ty(cx.tcx)
11151104
&& let ty::Term::Ty(term_ty) = projection_predicate.term
@@ -1121,6 +1110,27 @@ fn replace_types<'tcx>(
11211110
.mk_projection(assoc_item.def_id, cx.tcx.mk_substs_trait(new_ty, &[]));
11221111
let projected_ty = cx.tcx.normalize_erasing_regions(cx.param_env, projection);
11231112

1113+
let inserted = replaced.insert(term_param_ty.index);
1114+
1115+
let new_generic_arg = ty::GenericArg::from(projected_ty);
1116+
1117+
if substs[term_param_ty.index as usize] == new_generic_arg {
1118+
continue;
1119+
}
1120+
1121+
// The next line provides some protection against infinite loops.
1122+
assert!(inserted);
1123+
1124+
if fn_sig
1125+
.inputs_and_output
1126+
.iter()
1127+
.any(|ty| contains_ty(ty, term_param_ty.to_ty(cx.tcx)))
1128+
{
1129+
return false;
1130+
}
1131+
1132+
substs[term_param_ty.index as usize] = new_generic_arg;
1133+
11241134
deque.push_back((*term_param_ty, projected_ty));
11251135
}
11261136
}

tests/ui/needless_borrow.fixed

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ fn main() {
138138
let _ = std::any::Any::type_id(&""); // Don't lint. `Any` is only bound
139139
let _ = Box::new(&""); // Don't lint. Type parameter appears in return type
140140
ref_as_ref_path(&""); // Don't lint. Argument type is not a type parameter
141-
multiple_constraints_does_not_normalize_to_same(&[[""]], &[""]); // Don't lint. Projected type appears in arguments
141+
multiple_constraints_normalizes_to_different(&[[""]], &[""]); // Don't lint. Projected type appears in arguments
142142
}
143143

144144
#[allow(clippy::needless_borrowed_reference)]
@@ -237,7 +237,7 @@ where
237237
{
238238
}
239239

240-
fn multiple_constraints_does_not_normalize_to_same<T, U, V>(_: T, _: U)
240+
fn multiple_constraints_normalizes_to_different<T, U, V>(_: T, _: U)
241241
where
242242
T: IntoIterator<Item = U>,
243243
U: IntoIterator<Item = V>,

tests/ui/needless_borrow.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ fn main() {
138138
let _ = std::any::Any::type_id(&""); // Don't lint. `Any` is only bound
139139
let _ = Box::new(&""); // Don't lint. Type parameter appears in return type
140140
ref_as_ref_path(&""); // Don't lint. Argument type is not a type parameter
141-
multiple_constraints_does_not_normalize_to_same(&[[""]], &[""]); // Don't lint. Projected type appears in arguments
141+
multiple_constraints_normalizes_to_different(&[[""]], &[""]); // Don't lint. Projected type appears in arguments
142142
}
143143

144144
#[allow(clippy::needless_borrowed_reference)]
@@ -237,7 +237,7 @@ where
237237
{
238238
}
239239

240-
fn multiple_constraints_does_not_normalize_to_same<T, U, V>(_: T, _: U)
240+
fn multiple_constraints_normalizes_to_different<T, U, V>(_: T, _: U)
241241
where
242242
T: IntoIterator<Item = U>,
243243
U: IntoIterator<Item = V>,

0 commit comments

Comments
 (0)