Skip to content

Commit 430673f

Browse files
authored
Rollup merge of #92843 - camelid:str-concat-sugg, r=davidtwco
Improve string concatenation suggestion Before: error[E0369]: cannot add `&str` to `&str` --> file.rs:2:22 | 2 | let _x = "hello" + " world"; | ------- ^ -------- &str | | | | | `+` cannot be used to concatenate two `&str` strings | &str | help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left | 2 | let _x = "hello".to_owned() + " world"; | ~~~~~~~~~~~~~~~~~~ After: error[E0369]: cannot add `&str` to `&str` --> file.rs:2:22 | 2 | let _x = "hello" + " world"; | ------- ^ -------- &str | | | | | `+` cannot be used to concatenate two `&str` strings | &str | = note: string concatenation requires an owned `String` on the left help: create an owned `String` from a string reference | 2 | let _x = "hello".to_owned() + " world"; | +++++++++++
2 parents e38cbc7 + 7c4eca0 commit 430673f

File tree

6 files changed

+81
-85
lines changed

6 files changed

+81
-85
lines changed

compiler/rustc_typeck/src/check/op.rs

+38-55
Original file line numberDiff line numberDiff line change
@@ -549,16 +549,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
549549
is_assign: IsAssign,
550550
op: hir::BinOp,
551551
) -> bool {
552-
let source_map = self.tcx.sess.source_map();
553-
let remove_borrow_msg = "String concatenation appends the string on the right to the \
554-
string on the left and may require reallocation. This \
555-
requires ownership of the string on the left";
556-
557-
let msg = "`to_owned()` can be used to create an owned `String` \
558-
from a string reference. String concatenation \
559-
appends the string on the right to the string \
560-
on the left and may require reallocation. This \
561-
requires ownership of the string on the left";
552+
let str_concat_note = "string concatenation requires an owned `String` on the left";
553+
let rm_borrow_msg = "remove the borrow to obtain an owned `String`";
554+
let to_owned_msg = "create an owned `String` from a string reference";
562555

563556
let string_type = self.tcx.get_diagnostic_item(sym::String);
564557
let is_std_string = |ty: Ty<'tcx>| match ty.ty_adt_def() {
@@ -574,31 +567,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
574567
) =>
575568
{
576569
if let IsAssign::No = is_assign { // Do not supply this message if `&str += &str`
577-
err.span_label(
578-
op.span,
579-
"`+` cannot be used to concatenate two `&str` strings",
580-
);
581-
match source_map.span_to_snippet(lhs_expr.span) {
582-
Ok(lstring) => {
583-
err.span_suggestion(
584-
lhs_expr.span,
585-
if lstring.starts_with('&') {
586-
remove_borrow_msg
587-
} else {
588-
msg
589-
},
590-
if let Some(stripped) = lstring.strip_prefix('&') {
591-
// let a = String::new();
592-
// let _ = &a + "bar";
593-
stripped.to_string()
594-
} else {
595-
format!("{}.to_owned()", lstring)
596-
},
597-
Applicability::MachineApplicable,
598-
)
599-
}
600-
_ => err.help(msg),
601-
};
570+
err.span_label(op.span, "`+` cannot be used to concatenate two `&str` strings");
571+
err.note(str_concat_note);
572+
if let hir::ExprKind::AddrOf(_, _, lhs_inner_expr) = lhs_expr.kind {
573+
err.span_suggestion_verbose(
574+
lhs_expr.span.until(lhs_inner_expr.span),
575+
rm_borrow_msg,
576+
"".to_owned(),
577+
Applicability::MachineApplicable
578+
);
579+
} else {
580+
err.span_suggestion_verbose(
581+
lhs_expr.span.shrink_to_hi(),
582+
to_owned_msg,
583+
".to_owned()".to_owned(),
584+
Applicability::MachineApplicable
585+
);
586+
}
602587
}
603588
true
604589
}
@@ -609,32 +594,30 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
609594
op.span,
610595
"`+` cannot be used to concatenate a `&str` with a `String`",
611596
);
612-
match (
613-
source_map.span_to_snippet(lhs_expr.span),
614-
source_map.span_to_snippet(rhs_expr.span),
615-
is_assign,
616-
) {
617-
(Ok(l), Ok(r), IsAssign::No) => {
618-
let to_string = if let Some(stripped) = l.strip_prefix('&') {
619-
// let a = String::new(); let b = String::new();
620-
// let _ = &a + b;
621-
stripped.to_string()
597+
match is_assign {
598+
IsAssign::No => {
599+
let sugg_msg;
600+
let lhs_sugg = if let hir::ExprKind::AddrOf(_, _, lhs_inner_expr) = lhs_expr.kind {
601+
sugg_msg = "remove the borrow on the left and add one on the right";
602+
(lhs_expr.span.until(lhs_inner_expr.span), "".to_owned())
622603
} else {
623-
format!("{}.to_owned()", l)
604+
sugg_msg = "create an owned `String` on the left and add a borrow on the right";
605+
(lhs_expr.span.shrink_to_hi(), ".to_owned()".to_owned())
624606
};
625-
err.multipart_suggestion(
626-
msg,
627-
vec![
628-
(lhs_expr.span, to_string),
629-
(rhs_expr.span, format!("&{}", r)),
630-
],
607+
let suggestions = vec![
608+
lhs_sugg,
609+
(rhs_expr.span.shrink_to_lo(), "&".to_owned()),
610+
];
611+
err.multipart_suggestion_verbose(
612+
sugg_msg,
613+
suggestions,
631614
Applicability::MachineApplicable,
632615
);
633616
}
634-
_ => {
635-
err.help(msg);
617+
IsAssign::Yes => {
618+
err.note(str_concat_note);
636619
}
637-
};
620+
}
638621
true
639622
}
640623
_ => false,

src/test/ui/issues/issue-47377.stderr

+3-2
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,11 @@ LL | let _a = b + ", World!";
77
| | `+` cannot be used to concatenate two `&str` strings
88
| &str
99
|
10-
help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left
10+
= note: string concatenation requires an owned `String` on the left
11+
help: create an owned `String` from a string reference
1112
|
1213
LL | let _a = b.to_owned() + ", World!";
13-
| ~~~~~~~~~~~~
14+
| +++++++++++
1415

1516
error: aborting due to previous error
1617

src/test/ui/issues/issue-47380.stderr

+3-2
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,11 @@ LL | println!("🦀🦀🦀🦀🦀"); let _a = b + ", World!";
77
| | `+` cannot be used to concatenate two `&str` strings
88
| &str
99
|
10-
help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left
10+
= note: string concatenation requires an owned `String` on the left
11+
help: create an owned `String` from a string reference
1112
|
1213
LL | println!("🦀🦀🦀🦀🦀"); let _a = b.to_owned() + ", World!";
13-
| ~~~~~~~~~~~~
14+
| +++++++++++
1415

1516
error: aborting due to previous error
1617

src/test/ui/span/issue-39018.stderr

+31-22
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,11 @@ LL | let x = "Hello " + "World!";
77
| | `+` cannot be used to concatenate two `&str` strings
88
| &str
99
|
10-
help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left
10+
= note: string concatenation requires an owned `String` on the left
11+
help: create an owned `String` from a string reference
1112
|
1213
LL | let x = "Hello ".to_owned() + "World!";
13-
| ~~~~~~~~~~~~~~~~~~~
14+
| +++++++++++
1415

1516
error[E0369]: cannot add `World` to `World`
1617
--> $DIR/issue-39018.rs:8:26
@@ -46,10 +47,10 @@ LL | let x = "Hello " + "World!".to_owned();
4647
| | `+` cannot be used to concatenate a `&str` with a `String`
4748
| &str
4849
|
49-
help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left
50+
help: create an owned `String` on the left and add a borrow on the right
5051
|
5152
LL | let x = "Hello ".to_owned() + &"World!".to_owned();
52-
| ~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~
53+
| +++++++++++ +
5354

5455
error[E0369]: cannot add `&String` to `&String`
5556
--> $DIR/issue-39018.rs:26:16
@@ -60,10 +61,12 @@ LL | let _ = &a + &b;
6061
| | `+` cannot be used to concatenate two `&str` strings
6162
| &String
6263
|
63-
help: String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left
64+
= note: string concatenation requires an owned `String` on the left
65+
help: remove the borrow to obtain an owned `String`
6466
|
65-
LL | let _ = a + &b;
66-
| ~
67+
LL - let _ = &a + &b;
68+
LL + let _ = a + &b;
69+
|
6770

6871
error[E0369]: cannot add `String` to `&String`
6972
--> $DIR/issue-39018.rs:27:16
@@ -74,10 +77,11 @@ LL | let _ = &a + b;
7477
| | `+` cannot be used to concatenate a `&str` with a `String`
7578
| &String
7679
|
77-
help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left
80+
help: remove the borrow on the left and add one on the right
7881
|
79-
LL | let _ = a + &b;
80-
| ~ ~~
82+
LL - let _ = &a + b;
83+
LL + let _ = a + &b;
84+
|
8185

8286
error[E0308]: mismatched types
8387
--> $DIR/issue-39018.rs:29:17
@@ -97,10 +101,10 @@ LL | let _ = e + b;
97101
| | `+` cannot be used to concatenate a `&str` with a `String`
98102
| &String
99103
|
100-
help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left
104+
help: create an owned `String` on the left and add a borrow on the right
101105
|
102106
LL | let _ = e.to_owned() + &b;
103-
| ~~~~~~~~~~~~ ~~
107+
| +++++++++++ +
104108

105109
error[E0369]: cannot add `&String` to `&String`
106110
--> $DIR/issue-39018.rs:31:15
@@ -111,10 +115,11 @@ LL | let _ = e + &b;
111115
| | `+` cannot be used to concatenate two `&str` strings
112116
| &String
113117
|
114-
help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left
118+
= note: string concatenation requires an owned `String` on the left
119+
help: create an owned `String` from a string reference
115120
|
116121
LL | let _ = e.to_owned() + &b;
117-
| ~~~~~~~~~~~~
122+
| +++++++++++
118123

119124
error[E0369]: cannot add `&str` to `&String`
120125
--> $DIR/issue-39018.rs:32:15
@@ -125,10 +130,11 @@ LL | let _ = e + d;
125130
| | `+` cannot be used to concatenate two `&str` strings
126131
| &String
127132
|
128-
help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left
133+
= note: string concatenation requires an owned `String` on the left
134+
help: create an owned `String` from a string reference
129135
|
130136
LL | let _ = e.to_owned() + d;
131-
| ~~~~~~~~~~~~
137+
| +++++++++++
132138

133139
error[E0369]: cannot add `&&str` to `&String`
134140
--> $DIR/issue-39018.rs:33:15
@@ -139,10 +145,11 @@ LL | let _ = e + &d;
139145
| | `+` cannot be used to concatenate two `&str` strings
140146
| &String
141147
|
142-
help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left
148+
= note: string concatenation requires an owned `String` on the left
149+
help: create an owned `String` from a string reference
143150
|
144151
LL | let _ = e.to_owned() + &d;
145-
| ~~~~~~~~~~~~
152+
| +++++++++++
146153

147154
error[E0369]: cannot add `&&str` to `&&str`
148155
--> $DIR/issue-39018.rs:34:16
@@ -169,10 +176,11 @@ LL | let _ = c + &d;
169176
| | `+` cannot be used to concatenate two `&str` strings
170177
| &str
171178
|
172-
help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left
179+
= note: string concatenation requires an owned `String` on the left
180+
help: create an owned `String` from a string reference
173181
|
174182
LL | let _ = c.to_owned() + &d;
175-
| ~~~~~~~~~~~~
183+
| +++++++++++
176184

177185
error[E0369]: cannot add `&str` to `&str`
178186
--> $DIR/issue-39018.rs:37:15
@@ -183,10 +191,11 @@ LL | let _ = c + d;
183191
| | `+` cannot be used to concatenate two `&str` strings
184192
| &str
185193
|
186-
help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left
194+
= note: string concatenation requires an owned `String` on the left
195+
help: create an owned `String` from a string reference
187196
|
188197
LL | let _ = c.to_owned() + d;
189-
| ~~~~~~~~~~~~
198+
| +++++++++++
190199

191200
error: aborting due to 14 previous errors
192201

src/test/ui/str/str-concat-on-double-ref.stderr

+3-2
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,11 @@ LL | let c = a + b;
77
| | `+` cannot be used to concatenate two `&str` strings
88
| &String
99
|
10-
help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left
10+
= note: string concatenation requires an owned `String` on the left
11+
help: create an owned `String` from a string reference
1112
|
1213
LL | let c = a.to_owned() + b;
13-
| ~~~~~~~~~~~~
14+
| +++++++++++
1415

1516
error: aborting due to previous error
1617

src/test/ui/terminal-width/non-1-width-unicode-multiline-label.stderr

+3-2
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,11 @@ LL | ...ཽཾཿ྄ཱྀྀྂྃ྅྆྇ྈྉྊྋྌྍྎྏྐྑྒྒྷྔ
77
| | `+` cannot be used to concatenate two `&str` strings
88
| &str
99
|
10-
help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left
10+
= note: string concatenation requires an owned `String` on the left
11+
help: create an owned `String` from a string reference
1112
|
1213
LL | let _ = "ༀ༁༂༃༄༅༆༇༈༉༊་༌།༎༏༐༑༒༓༔༕༖༗༘༙༚༛༜༝༞༟༠༡༢༣༤༥༦༧༨༩༪༫༬༭༮༯༰༱༲༳༴༵༶༷༸༹༺༻༼༽༾༿ཀཁགགྷངཅཆཇ཈ཉཊཋཌཌྷཎཏཐདདྷནཔཕབབྷམཙཚཛཛྷཝཞཟའཡརལཤཥསཧཨཀྵཪཫཬ཭཮཯཰ཱཱཱིིུུྲྀཷླྀཹེཻོཽཾཿ྄ཱྀྀྂྃ྅྆྇ྈྉྊྋྌྍྎྏྐྑྒྒྷྔྕྖྗ྘ྙྚྛྜྜྷྞྟྠྡྡྷྣྤྥྦྦྷྨྩྪྫྫྷྭྮྯྰྱྲླྴྵྶྷྸྐྵྺྻྼ྽྾྿࿀࿁࿂࿃࿄࿅࿆࿇࿈࿉࿊࿋࿌࿍࿎࿏࿐࿑࿒࿓࿔࿕࿖࿗࿘࿙࿚"; let _a = unicode_is_fun.to_owned() + " really fun!";
13-
| ~~~~~~~~~~~~~~~~~~~~~~~~~
14+
| +++++++++++
1415

1516
error: aborting due to previous error
1617

0 commit comments

Comments
 (0)