Skip to content

Commit 25fcc0e

Browse files
authored
Rollup merge of #92507 - chordtoll:suggest-single-quotes, r=petrochenkov
Suggest single quotes when char expected, str provided If a type mismatch occurs where a char is expected and a string literal is provided, suggest changing the double quotes to single quotes. We already provide this suggestion in the other direction ( ' -> " ). Especially useful for new rust devs used to a language in which single/double quotes are interchangeable. Fixes #92479.
2 parents 4e4e1ec + 3087c4d commit 25fcc0e

File tree

10 files changed

+143
-3
lines changed

10 files changed

+143
-3
lines changed

compiler/rustc_infer/src/infer/error_reporting/mod.rs

+38-3
Original file line numberDiff line numberDiff line change
@@ -2041,11 +2041,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
20412041
if let ValuePairs::Types(ty::error::ExpectedFound { expected, found }) =
20422042
trace.values
20432043
{
2044-
// If a tuple of length one was expected and the found expression has
2045-
// parentheses around it, perhaps the user meant to write `(expr,)` to
2046-
// build a tuple (issue #86100)
20472044
match (expected.kind(), found.kind()) {
20482045
(ty::Tuple(_), ty::Tuple(_)) => {}
2046+
// If a tuple of length one was expected and the found expression has
2047+
// parentheses around it, perhaps the user meant to write `(expr,)` to
2048+
// build a tuple (issue #86100)
20492049
(ty::Tuple(_), _) if expected.tuple_fields().count() == 1 => {
20502050
if let Ok(code) = self.tcx.sess().source_map().span_to_snippet(span) {
20512051
if let Some(code) =
@@ -2060,6 +2060,41 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
20602060
}
20612061
}
20622062
}
2063+
// If a character was expected and the found expression is a string literal
2064+
// containing a single character, perhaps the user meant to write `'c'` to
2065+
// specify a character literal (issue #92479)
2066+
(ty::Char, ty::Ref(_, r, _)) if r.is_str() => {
2067+
if let Ok(code) = self.tcx.sess().source_map().span_to_snippet(span) {
2068+
if let Some(code) =
2069+
code.strip_prefix('"').and_then(|s| s.strip_suffix('"'))
2070+
{
2071+
if code.chars().nth(1).is_none() {
2072+
err.span_suggestion(
2073+
span,
2074+
"if you meant to write a `char` literal, use single quotes",
2075+
format!("'{}'", code),
2076+
Applicability::MachineApplicable,
2077+
);
2078+
}
2079+
}
2080+
}
2081+
}
2082+
// If a string was expected and the found expression is a character literal,
2083+
// perhaps the user meant to write `"s"` to specify a string literal.
2084+
(ty::Ref(_, r, _), ty::Char) if r.is_str() => {
2085+
if let Ok(code) = self.tcx.sess().source_map().span_to_snippet(span) {
2086+
if let Some(code) =
2087+
code.strip_prefix('\'').and_then(|s| s.strip_suffix('\''))
2088+
{
2089+
err.span_suggestion(
2090+
span,
2091+
"if you meant to write a `str` literal, use double quotes",
2092+
format!("\"{}\"", code),
2093+
Applicability::MachineApplicable,
2094+
);
2095+
}
2096+
}
2097+
}
20632098
_ => {}
20642099
}
20652100
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// When a MULTI-character string literal is used where a char should be,
2+
// DO NOT suggest changing to single quotes.
3+
4+
fn main() {
5+
let _: char = "foo"; //~ ERROR mismatched types
6+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
error[E0308]: mismatched types
2+
--> $DIR/char-as-str-multi.rs:5:19
3+
|
4+
LL | let _: char = "foo";
5+
| ---- ^^^^^ expected `char`, found `&str`
6+
| |
7+
| expected due to this
8+
9+
error: aborting due to previous error
10+
11+
For more information about this error, try `rustc --explain E0308`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// When a SINGLE-character string literal is used where a char should be,
2+
// suggest changing to single quotes.
3+
4+
// Testing both single-byte and multi-byte characters, as we should handle both.
5+
6+
// run-rustfix
7+
8+
fn main() {
9+
let _: char = 'a'; //~ ERROR mismatched types
10+
let _: char = '人'; //~ ERROR mismatched types
11+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// When a SINGLE-character string literal is used where a char should be,
2+
// suggest changing to single quotes.
3+
4+
// Testing both single-byte and multi-byte characters, as we should handle both.
5+
6+
// run-rustfix
7+
8+
fn main() {
9+
let _: char = "a"; //~ ERROR mismatched types
10+
let _: char = "人"; //~ ERROR mismatched types
11+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
error[E0308]: mismatched types
2+
--> $DIR/char-as-str-single.rs:9:19
3+
|
4+
LL | let _: char = "a";
5+
| ---- ^^^ expected `char`, found `&str`
6+
| |
7+
| expected due to this
8+
|
9+
help: if you meant to write a `char` literal, use single quotes
10+
|
11+
LL | let _: char = 'a';
12+
| ~~~
13+
14+
error[E0308]: mismatched types
15+
--> $DIR/char-as-str-single.rs:10:19
16+
|
17+
LL | let _: char = "人";
18+
| ---- ^^^^ expected `char`, found `&str`
19+
| |
20+
| expected due to this
21+
|
22+
help: if you meant to write a `char` literal, use single quotes
23+
|
24+
LL | let _: char = '人';
25+
| ~~~~
26+
27+
error: aborting due to 2 previous errors
28+
29+
For more information about this error, try `rustc --explain E0308`.
+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// When a char literal is used where a str should be,
2+
// suggest changing to double quotes.
3+
4+
// run-rustfix
5+
6+
fn main() {
7+
let _: &str = "a"; //~ ERROR mismatched types
8+
}

src/test/ui/inference/str-as-char.rs

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// When a char literal is used where a str should be,
2+
// suggest changing to double quotes.
3+
4+
// run-rustfix
5+
6+
fn main() {
7+
let _: &str = 'a'; //~ ERROR mismatched types
8+
}
+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
error[E0308]: mismatched types
2+
--> $DIR/str-as-char.rs:7:19
3+
|
4+
LL | let _: &str = 'a';
5+
| ---- ^^^ expected `&str`, found `char`
6+
| |
7+
| expected due to this
8+
|
9+
help: if you meant to write a `str` literal, use double quotes
10+
|
11+
LL | let _: &str = "a";
12+
| ~~~
13+
14+
error: aborting due to previous error
15+
16+
For more information about this error, try `rustc --explain E0308`.

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

+5
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,11 @@ error[E0308]: mismatched types
1212
|
1313
LL | let v: Vec(&str) = vec!['1', '2'];
1414
| ^^^ expected `&str`, found `char`
15+
|
16+
help: if you meant to write a `str` literal, use double quotes
17+
|
18+
LL | let v: Vec(&str) = vec!["1", '2'];
19+
| ~~~
1520

1621
error: aborting due to 2 previous errors
1722

0 commit comments

Comments
 (0)