Skip to content

Commit deb7c05

Browse files
authored
Unrolled build for #132469
Rollup merge of #132469 - estebank:issue-132041, r=Nadrieril Do not suggest borrow that is already there in fully-qualified call When encountering `&str::from("value")` do not suggest `&&str::from("value")`. Fix #132041.
2 parents 2f8eeb2 + 7603adc commit deb7c05

File tree

4 files changed

+169
-7
lines changed

4 files changed

+169
-7
lines changed

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

Lines changed: 77 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1187,6 +1187,13 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
11871187
has_custom_message: bool,
11881188
) -> bool {
11891189
let span = obligation.cause.span;
1190+
let param_env = obligation.param_env;
1191+
1192+
let mk_result = |trait_pred_and_new_ty| {
1193+
let obligation =
1194+
self.mk_trait_obligation_with_new_self_ty(param_env, trait_pred_and_new_ty);
1195+
self.predicate_must_hold_modulo_regions(&obligation)
1196+
};
11901197

11911198
let code = match obligation.cause.code() {
11921199
ObligationCauseCode::FunctionArg { parent_code, .. } => parent_code,
@@ -1195,6 +1202,76 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
11951202
c @ ObligationCauseCode::WhereClauseInExpr(_, _, hir_id, _)
11961203
if self.tcx.hir_span(*hir_id).lo() == span.lo() =>
11971204
{
1205+
// `hir_id` corresponds to the HIR node that introduced a `where`-clause obligation.
1206+
// If that obligation comes from a type in an associated method call, we need
1207+
// special handling here.
1208+
if let hir::Node::Expr(expr) = self.tcx.parent_hir_node(*hir_id)
1209+
&& let hir::ExprKind::Call(base, _) = expr.kind
1210+
&& let hir::ExprKind::Path(hir::QPath::TypeRelative(ty, segment)) = base.kind
1211+
&& let hir::Node::Expr(outer) = self.tcx.parent_hir_node(expr.hir_id)
1212+
&& let hir::ExprKind::AddrOf(hir::BorrowKind::Ref, mtbl, _) = outer.kind
1213+
&& ty.span == span
1214+
{
1215+
// We've encountered something like `&str::from("")`, where the intended code
1216+
// was likely `<&str>::from("")`. The former is interpreted as "call method
1217+
// `from` on `str` and borrow the result", while the latter means "call method
1218+
// `from` on `&str`".
1219+
1220+
let trait_pred_and_imm_ref = poly_trait_pred.map_bound(|p| {
1221+
(p, Ty::new_imm_ref(self.tcx, self.tcx.lifetimes.re_static, p.self_ty()))
1222+
});
1223+
let trait_pred_and_mut_ref = poly_trait_pred.map_bound(|p| {
1224+
(p, Ty::new_mut_ref(self.tcx, self.tcx.lifetimes.re_static, p.self_ty()))
1225+
});
1226+
1227+
let imm_ref_self_ty_satisfies_pred = mk_result(trait_pred_and_imm_ref);
1228+
let mut_ref_self_ty_satisfies_pred = mk_result(trait_pred_and_mut_ref);
1229+
let sugg_msg = |pre: &str| {
1230+
format!(
1231+
"you likely meant to call the associated function `{FN}` for type \
1232+
`&{pre}{TY}`, but the code as written calls associated function `{FN}` on \
1233+
type `{TY}`",
1234+
FN = segment.ident,
1235+
TY = poly_trait_pred.self_ty(),
1236+
)
1237+
};
1238+
match (imm_ref_self_ty_satisfies_pred, mut_ref_self_ty_satisfies_pred, mtbl) {
1239+
(true, _, hir::Mutability::Not) | (_, true, hir::Mutability::Mut) => {
1240+
err.multipart_suggestion_verbose(
1241+
sugg_msg(mtbl.prefix_str()),
1242+
vec![
1243+
(outer.span.shrink_to_lo(), "<".to_string()),
1244+
(span.shrink_to_hi(), ">".to_string()),
1245+
],
1246+
Applicability::MachineApplicable,
1247+
);
1248+
}
1249+
(true, _, hir::Mutability::Mut) => {
1250+
// There's an associated function found on the immutable borrow of the
1251+
err.multipart_suggestion_verbose(
1252+
sugg_msg("mut "),
1253+
vec![
1254+
(outer.span.shrink_to_lo().until(span), "<&".to_string()),
1255+
(span.shrink_to_hi(), ">".to_string()),
1256+
],
1257+
Applicability::MachineApplicable,
1258+
);
1259+
}
1260+
(_, true, hir::Mutability::Not) => {
1261+
err.multipart_suggestion_verbose(
1262+
sugg_msg(""),
1263+
vec![
1264+
(outer.span.shrink_to_lo().until(span), "<&mut ".to_string()),
1265+
(span.shrink_to_hi(), ">".to_string()),
1266+
],
1267+
Applicability::MachineApplicable,
1268+
);
1269+
}
1270+
_ => {}
1271+
}
1272+
// If we didn't return early here, we would instead suggest `&&str::from("")`.
1273+
return false;
1274+
}
11981275
c
11991276
}
12001277
c if matches!(
@@ -1220,8 +1297,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
12201297
never_suggest_borrow.push(def_id);
12211298
}
12221299

1223-
let param_env = obligation.param_env;
1224-
12251300
// Try to apply the original trait bound by borrowing.
12261301
let mut try_borrowing = |old_pred: ty::PolyTraitPredicate<'tcx>,
12271302
blacklist: &[DefId]|
@@ -1243,11 +1318,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
12431318
)
12441319
});
12451320

1246-
let mk_result = |trait_pred_and_new_ty| {
1247-
let obligation =
1248-
self.mk_trait_obligation_with_new_self_ty(param_env, trait_pred_and_new_ty);
1249-
self.predicate_must_hold_modulo_regions(&obligation)
1250-
};
12511321
let imm_ref_self_ty_satisfies_pred = mk_result(trait_pred_and_imm_ref);
12521322
let mut_ref_self_ty_satisfies_pred = mk_result(trait_pred_and_mut_ref);
12531323

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
//@ run-rustfix
2+
3+
struct S;
4+
trait Trait {
5+
fn foo() {}
6+
}
7+
impl Trait for &S {}
8+
impl Trait for &mut S {}
9+
fn main() {
10+
let _ = <&str>::from("value");
11+
//~^ ERROR the trait bound `str: From<_>` is not satisfied
12+
//~| ERROR the size for values of type `str` cannot be known at compilation time
13+
let _ = <&mut S>::foo();
14+
//~^ ERROR the trait bound `S: Trait` is not satisfied
15+
let _ = <&S>::foo();
16+
//~^ ERROR the trait bound `S: Trait` is not satisfied
17+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
//@ run-rustfix
2+
3+
struct S;
4+
trait Trait {
5+
fn foo() {}
6+
}
7+
impl Trait for &S {}
8+
impl Trait for &mut S {}
9+
fn main() {
10+
let _ = &str::from("value");
11+
//~^ ERROR the trait bound `str: From<_>` is not satisfied
12+
//~| ERROR the size for values of type `str` cannot be known at compilation time
13+
let _ = &mut S::foo();
14+
//~^ ERROR the trait bound `S: Trait` is not satisfied
15+
let _ = &S::foo();
16+
//~^ ERROR the trait bound `S: Trait` is not satisfied
17+
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
error[E0277]: the trait bound `str: From<_>` is not satisfied
2+
--> $DIR/dont-suggest-borrowing-existing-borrow.rs:10:14
3+
|
4+
LL | let _ = &str::from("value");
5+
| ^^^ the trait `From<_>` is not implemented for `str`
6+
|
7+
= help: the following other types implement trait `From<T>`:
8+
`String` implements `From<&String>`
9+
`String` implements `From<&mut str>`
10+
`String` implements `From<&str>`
11+
`String` implements `From<Box<str>>`
12+
`String` implements `From<Cow<'_, str>>`
13+
`String` implements `From<char>`
14+
help: you likely meant to call the associated function `from` for type `&str`, but the code as written calls associated function `from` on type `str`
15+
|
16+
LL | let _ = <&str>::from("value");
17+
| + +
18+
19+
error[E0277]: the trait bound `S: Trait` is not satisfied
20+
--> $DIR/dont-suggest-borrowing-existing-borrow.rs:13:18
21+
|
22+
LL | let _ = &mut S::foo();
23+
| ^ the trait `Trait` is not implemented for `S`
24+
|
25+
= help: the following other types implement trait `Trait`:
26+
&S
27+
&mut S
28+
help: you likely meant to call the associated function `foo` for type `&mut S`, but the code as written calls associated function `foo` on type `S`
29+
|
30+
LL | let _ = <&mut S>::foo();
31+
| + +
32+
33+
error[E0277]: the trait bound `S: Trait` is not satisfied
34+
--> $DIR/dont-suggest-borrowing-existing-borrow.rs:15:14
35+
|
36+
LL | let _ = &S::foo();
37+
| ^ the trait `Trait` is not implemented for `S`
38+
|
39+
= help: the following other types implement trait `Trait`:
40+
&S
41+
&mut S
42+
help: you likely meant to call the associated function `foo` for type `&S`, but the code as written calls associated function `foo` on type `S`
43+
|
44+
LL | let _ = <&S>::foo();
45+
| + +
46+
47+
error[E0277]: the size for values of type `str` cannot be known at compilation time
48+
--> $DIR/dont-suggest-borrowing-existing-borrow.rs:10:14
49+
|
50+
LL | let _ = &str::from("value");
51+
| ^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
52+
|
53+
= help: the trait `Sized` is not implemented for `str`
54+
= note: the return type of a function must have a statically known size
55+
56+
error: aborting due to 4 previous errors
57+
58+
For more information about this error, try `rustc --explain E0277`.

0 commit comments

Comments
 (0)