Skip to content

Commit a68e2e1

Browse files
committed
Emit suggestions on both lhs and rhs
1 parent bf93a77 commit a68e2e1

File tree

3 files changed

+115
-47
lines changed

3 files changed

+115
-47
lines changed

Cargo.lock

+26-16
Original file line numberDiff line numberDiff line change
@@ -546,7 +546,7 @@ dependencies = [
546546
"filetime",
547547
"futures",
548548
"if_chain",
549-
"itertools",
549+
"itertools 0.10.5",
550550
"parking_lot 0.12.1",
551551
"quote",
552552
"regex",
@@ -579,7 +579,7 @@ dependencies = [
579579
"aho-corasick 0.7.20",
580580
"clap",
581581
"indoc",
582-
"itertools",
582+
"itertools 0.10.5",
583583
"opener",
584584
"shell-escape",
585585
"walkdir",
@@ -594,7 +594,7 @@ dependencies = [
594594
"clippy_config",
595595
"clippy_utils",
596596
"declare_clippy_lint",
597-
"itertools",
597+
"itertools 0.10.5",
598598
"quine-mc_cluskey",
599599
"regex",
600600
"regex-syntax 0.7.2",
@@ -616,7 +616,7 @@ version = "0.1.76"
616616
dependencies = [
617617
"arrayvec",
618618
"clippy_config",
619-
"itertools",
619+
"itertools 0.10.5",
620620
"rustc-semver",
621621
]
622622

@@ -999,7 +999,7 @@ checksum = "a0afaad2b26fa326569eb264b1363e8ae3357618c43982b3f285f0774ce76b69"
999999
name = "declare_clippy_lint"
10001000
version = "0.1.76"
10011001
dependencies = [
1002-
"itertools",
1002+
"itertools 0.10.5",
10031003
"quote",
10041004
"syn 2.0.29",
10051005
]
@@ -2067,6 +2067,15 @@ dependencies = [
20672067
"either",
20682068
]
20692069

2070+
[[package]]
2071+
name = "itertools"
2072+
version = "0.12.0"
2073+
source = "registry+https://github.com/rust-lang/crates.io-index"
2074+
checksum = "25db6b064527c5d482d0423354fcd07a89a2dfe07b67892e62411946db7f07b0"
2075+
dependencies = [
2076+
"either",
2077+
]
2078+
20702079
[[package]]
20712080
name = "itoa"
20722081
version = "1.0.6"
@@ -3451,7 +3460,7 @@ dependencies = [
34513460
name = "rustc_ast_passes"
34523461
version = "0.0.0"
34533462
dependencies = [
3454-
"itertools",
3463+
"itertools 0.10.5",
34553464
"rustc_ast",
34563465
"rustc_ast_pretty",
34573466
"rustc_attr",
@@ -3510,7 +3519,7 @@ name = "rustc_borrowck"
35103519
version = "0.0.0"
35113520
dependencies = [
35123521
"either",
3513-
"itertools",
3522+
"itertools 0.10.5",
35143523
"polonius-engine",
35153524
"rustc_data_structures",
35163525
"rustc_errors",
@@ -3565,7 +3574,7 @@ version = "0.0.0"
35653574
dependencies = [
35663575
"bitflags 1.3.2",
35673576
"cstr",
3568-
"itertools",
3577+
"itertools 0.10.5",
35693578
"libc",
35703579
"measureme",
35713580
"object",
@@ -3601,7 +3610,7 @@ dependencies = [
36013610
"ar_archive_writer",
36023611
"bitflags 1.3.2",
36033612
"cc",
3604-
"itertools",
3613+
"itertools 0.10.5",
36053614
"jobserver",
36063615
"libc",
36073616
"object",
@@ -3670,7 +3679,7 @@ dependencies = [
36703679
"elsa",
36713680
"ena",
36723681
"indexmap",
3673-
"itertools",
3682+
"itertools 0.10.5",
36743683
"jobserver",
36753684
"libc",
36763685
"measureme",
@@ -4252,7 +4261,7 @@ version = "0.0.0"
42524261
dependencies = [
42534262
"coverage_test_macros",
42544263
"either",
4255-
"itertools",
4264+
"itertools 0.10.5",
42564265
"rustc_arena",
42574266
"rustc_ast",
42584267
"rustc_attr",
@@ -4326,7 +4335,7 @@ dependencies = [
43264335
name = "rustc_passes"
43274336
version = "0.0.0"
43284337
dependencies = [
4329-
"itertools",
4338+
"itertools 0.10.5",
43304339
"rustc_ast",
43314340
"rustc_ast_pretty",
43324341
"rustc_attr",
@@ -4552,6 +4561,7 @@ checksum = "8ba09476327c4b70ccefb6180f046ef588c26a24cf5d269a9feba316eb4f029f"
45524561
name = "rustc_trait_selection"
45534562
version = "0.0.0"
45544563
dependencies = [
4564+
"itertools 0.12.0",
45554565
"rustc_ast",
45564566
"rustc_attr",
45574567
"rustc_data_structures",
@@ -4590,7 +4600,7 @@ dependencies = [
45904600
name = "rustc_transmute"
45914601
version = "0.0.0"
45924602
dependencies = [
4593-
"itertools",
4603+
"itertools 0.10.5",
45944604
"rustc_data_structures",
45954605
"rustc_hir",
45964606
"rustc_infer",
@@ -4605,7 +4615,7 @@ dependencies = [
46054615
name = "rustc_ty_utils"
46064616
version = "0.0.0"
46074617
dependencies = [
4608-
"itertools",
4618+
"itertools 0.10.5",
46094619
"rustc_data_structures",
46104620
"rustc_errors",
46114621
"rustc_fluent_macro",
@@ -4652,7 +4662,7 @@ dependencies = [
46524662
"askama",
46534663
"expect-test",
46544664
"indexmap",
4655-
"itertools",
4665+
"itertools 0.10.5",
46564666
"minifier",
46574667
"once_cell",
46584668
"regex",
@@ -4734,7 +4744,7 @@ dependencies = [
47344744
"dirs",
47354745
"getopts",
47364746
"ignore",
4737-
"itertools",
4747+
"itertools 0.10.5",
47384748
"lazy_static",
47394749
"regex",
47404750
"rustfmt-config_proc_macro",

compiler/rustc_trait_selection/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ edition = "2021"
55

66
[dependencies]
77
# tidy-alphabetical-start
8+
itertools = "0.12.0"
89
rustc_ast = { path = "../rustc_ast" }
910
rustc_attr = { path = "../rustc_attr" }
1011
rustc_data_structures = { path = "../rustc_data_structures" }

compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs

+88-31
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,9 @@ use crate::traits::error_reporting::type_err_ctxt_ext::InferCtxtPrivExt;
4747
use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
4848
use rustc_middle::ty::print::{with_forced_trimmed_paths, with_no_trimmed_paths};
4949

50+
use itertools::EitherOrBoth;
51+
use itertools::Itertools;
52+
5053
#[derive(Debug)]
5154
pub enum CoroutineInteriorOrUpvar {
5255
// span of interior type
@@ -838,78 +841,132 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
838841
}
839842
}
840843
}
841-
} else if let (ObligationCauseCode::BinOp { lhs_hir_id, rhs_hir_id: Some(_rhs_hir_id), .. }, predicate) =
842-
code.peel_derives_with_predicate()
844+
} else if let (
845+
ObligationCauseCode::BinOp { lhs_hir_id, rhs_hir_id: Some(rhs_hir_id), .. },
846+
predicate,
847+
) = code.peel_derives_with_predicate()
848+
&& let Some(typeck_results) = &self.typeck_results
843849
&& let hir::Node::Expr(lhs) = self.tcx.hir().get(*lhs_hir_id)
850+
&& let hir::Node::Expr(rhs) = self.tcx.hir().get(*rhs_hir_id)
851+
&& let Some(rhs_ty) = typeck_results.expr_ty_opt(rhs)
844852
{
845853
let trait_pred = predicate.unwrap_or(trait_pred);
846854
let lhs_ty = self.tcx.instantiate_bound_regions_with_erased(trait_pred.self_ty());
847855
let lhs_autoderef = (self.autoderef_steps)(lhs_ty);
848-
if let Some(mut steps) =
849-
lhs_autoderef.into_iter().enumerate().find_map(|(steps, (ty, obligations))| {
850-
// Remapping bound vars here
851-
let trait_pred_and_ty =
852-
trait_pred.map_bound(|inner_trait_pred| (inner_trait_pred, ty));
856+
let rhs_autoderef = (self.autoderef_steps)(rhs_ty);
857+
let first_lhs = lhs_autoderef.first().unwrap().clone();
858+
let first_rhs = rhs_autoderef.first().unwrap().clone();
859+
let mut autoderefs = lhs_autoderef
860+
.into_iter()
861+
.enumerate()
862+
.rev()
863+
.zip_longest(rhs_autoderef.into_iter().enumerate().rev())
864+
.map(|t| match t {
865+
EitherOrBoth::Both(a, b) => (a, b),
866+
EitherOrBoth::Left(a) => (a, (0, first_rhs.clone())),
867+
EitherOrBoth::Right(b) => ((0, first_lhs.clone()), b),
868+
})
869+
.rev();
870+
if let Some((lsteps, rsteps)) =
871+
autoderefs.find_map(|((lsteps, (l_ty, _)), (rsteps, (r_ty, _)))| {
872+
let trait_pred_and_ty = trait_pred.map_bound(|inner| {
873+
(
874+
ty::TraitPredicate {
875+
trait_ref: ty::TraitRef::new(
876+
self.tcx,
877+
inner.trait_ref.def_id,
878+
self.tcx.mk_args(&[l_ty.into(), r_ty.into()]),
879+
),
880+
polarity: inner.polarity,
881+
},
882+
l_ty,
883+
)
884+
});
853885
let obligation = self.mk_trait_obligation_with_new_self_ty(
854886
obligation.param_env,
855887
trait_pred_and_ty,
856888
);
857-
858-
let may_hold = obligations
859-
.iter()
860-
.chain([&obligation])
861-
.all(|obligation| self.predicate_may_hold(obligation))
862-
.then_some(steps);
863-
864-
may_hold
889+
self.predicate_may_hold(&obligation).then_some(match (lsteps, rsteps) {
890+
(_, 0) => (Some(lsteps), None),
891+
(0, _) => (None, Some(rsteps)),
892+
_ => (Some(lsteps), Some(rsteps)),
893+
})
865894
})
866895
{
867-
if steps > 0 {
868-
// Suggest `&*` rather than `*&`
869-
let span = lhs.peel_borrows().span;
870-
871-
let mut lhs = lhs;
872-
let mut prefix_span = lhs.span.shrink_to_lo();
896+
let make_sugg = |mut expr: &Expr<'_>, mut steps| {
897+
let mut prefix_span = expr.span.shrink_to_lo();
873898
let mut msg = "consider dereferencing here";
874-
if let hir::ExprKind::AddrOf(_, _, inner) = lhs.kind {
899+
if let hir::ExprKind::AddrOf(_, _, inner) = expr.kind {
875900
msg = "consider removing the borrow and dereferencing instead";
876901
if let hir::ExprKind::AddrOf(..) = inner.kind {
877902
msg = "consider removing the borrows and dereferencing instead";
878903
}
879904
}
880-
while let hir::ExprKind::AddrOf(_, _, inner) = lhs.kind
905+
while let hir::ExprKind::AddrOf(_, _, inner) = expr.kind
881906
&& steps > 0
882907
{
883908
prefix_span = prefix_span.with_hi(inner.span.lo());
884-
lhs = inner;
909+
expr = inner;
885910
steps -= 1;
886911
}
887912
if steps == 0 {
888913
msg = msg.trim_end_matches(" and dereferencing instead");
889914
}
890-
891915
let derefs = "*".repeat(steps);
892916
let needs_parens = steps > 0
893-
&& match lhs.kind {
917+
&& match expr.kind {
894918
hir::ExprKind::Cast(_, _) | hir::ExprKind::Binary(_, _, _) => true,
895-
_ if is_range_literal(lhs) => true,
919+
_ if is_range_literal(expr) => true,
896920
_ => false,
897921
};
898922
let mut suggestion = if needs_parens {
899923
vec![
900-
(span.shrink_to_lo(), format!("{derefs}(")),
901-
(span.shrink_to_hi(), ")".to_string()),
924+
(
925+
expr.span.with_lo(prefix_span.hi()).shrink_to_lo(),
926+
format!("{derefs}("),
927+
),
928+
(expr.span.shrink_to_hi(), ")".to_string()),
902929
]
903930
} else {
904-
vec![(span.shrink_to_lo(), format!("{derefs}"))]
931+
vec![(
932+
expr.span.with_lo(prefix_span.hi()).shrink_to_lo(),
933+
format!("{derefs}"),
934+
)]
905935
};
906936
suggestion.push((prefix_span, "".to_string()));
937+
(msg, suggestion)
938+
};
939+
940+
if let Some(lsteps) = lsteps
941+
&& let Some(rsteps) = rsteps
942+
&& lsteps > 0
943+
&& rsteps > 0
944+
{
945+
let mut suggestion = make_sugg(lhs, lsteps).1;
946+
suggestion.append(&mut make_sugg(rhs, rsteps).1);
947+
err.multipart_suggestion_verbose(
948+
"consider dereferencing both sides",
949+
suggestion,
950+
Applicability::MachineApplicable,
951+
);
952+
} else if let Some(lsteps) = lsteps
953+
&& lsteps > 0
954+
{
955+
let (msg, suggestion) = make_sugg(lhs, lsteps);
956+
err.multipart_suggestion_verbose(
957+
msg,
958+
suggestion,
959+
Applicability::MachineApplicable,
960+
);
961+
} else if let Some(rsteps) = rsteps
962+
&& rsteps > 0
963+
{
964+
let (msg, suggestion) = make_sugg(rhs, rsteps);
907965
err.multipart_suggestion_verbose(
908966
msg,
909967
suggestion,
910968
Applicability::MachineApplicable,
911969
);
912-
return true;
913970
}
914971
}
915972
}

0 commit comments

Comments
 (0)