Skip to content

Commit

Permalink
Rollup merge of rust-lang#92507 - chordtoll:suggest-single-quotes, r=…
Browse files Browse the repository at this point in the history
…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 rust-lang#92479.
  • Loading branch information
matthiaskrgr authored Jan 4, 2022
2 parents 4e4e1ec + 3087c4d commit 25fcc0e
Show file tree
Hide file tree
Showing 10 changed files with 143 additions and 3 deletions.
41 changes: 38 additions & 3 deletions compiler/rustc_infer/src/infer/error_reporting/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2041,11 +2041,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
if let ValuePairs::Types(ty::error::ExpectedFound { expected, found }) =
trace.values
{
// If a tuple of length one was expected and the found expression has
// parentheses around it, perhaps the user meant to write `(expr,)` to
// build a tuple (issue #86100)
match (expected.kind(), found.kind()) {
(ty::Tuple(_), ty::Tuple(_)) => {}
// If a tuple of length one was expected and the found expression has
// parentheses around it, perhaps the user meant to write `(expr,)` to
// build a tuple (issue #86100)
(ty::Tuple(_), _) if expected.tuple_fields().count() == 1 => {
if let Ok(code) = self.tcx.sess().source_map().span_to_snippet(span) {
if let Some(code) =
Expand All @@ -2060,6 +2060,41 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
}
}
}
// If a character was expected and the found expression is a string literal
// containing a single character, perhaps the user meant to write `'c'` to
// specify a character literal (issue #92479)
(ty::Char, ty::Ref(_, r, _)) if r.is_str() => {
if let Ok(code) = self.tcx.sess().source_map().span_to_snippet(span) {
if let Some(code) =
code.strip_prefix('"').and_then(|s| s.strip_suffix('"'))
{
if code.chars().nth(1).is_none() {
err.span_suggestion(
span,
"if you meant to write a `char` literal, use single quotes",
format!("'{}'", code),
Applicability::MachineApplicable,
);
}
}
}
}
// If a string was expected and the found expression is a character literal,
// perhaps the user meant to write `"s"` to specify a string literal.
(ty::Ref(_, r, _), ty::Char) if r.is_str() => {
if let Ok(code) = self.tcx.sess().source_map().span_to_snippet(span) {
if let Some(code) =
code.strip_prefix('\'').and_then(|s| s.strip_suffix('\''))
{
err.span_suggestion(
span,
"if you meant to write a `str` literal, use double quotes",
format!("\"{}\"", code),
Applicability::MachineApplicable,
);
}
}
}
_ => {}
}
}
Expand Down
6 changes: 6 additions & 0 deletions src/test/ui/inference/char-as-str-multi.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// When a MULTI-character string literal is used where a char should be,
// DO NOT suggest changing to single quotes.

fn main() {
let _: char = "foo"; //~ ERROR mismatched types
}
11 changes: 11 additions & 0 deletions src/test/ui/inference/char-as-str-multi.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
error[E0308]: mismatched types
--> $DIR/char-as-str-multi.rs:5:19
|
LL | let _: char = "foo";
| ---- ^^^^^ expected `char`, found `&str`
| |
| expected due to this

error: aborting due to previous error

For more information about this error, try `rustc --explain E0308`.
11 changes: 11 additions & 0 deletions src/test/ui/inference/char-as-str-single.fixed
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// When a SINGLE-character string literal is used where a char should be,
// suggest changing to single quotes.

// Testing both single-byte and multi-byte characters, as we should handle both.

// run-rustfix

fn main() {
let _: char = 'a'; //~ ERROR mismatched types
let _: char = '人'; //~ ERROR mismatched types
}
11 changes: 11 additions & 0 deletions src/test/ui/inference/char-as-str-single.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// When a SINGLE-character string literal is used where a char should be,
// suggest changing to single quotes.

// Testing both single-byte and multi-byte characters, as we should handle both.

// run-rustfix

fn main() {
let _: char = "a"; //~ ERROR mismatched types
let _: char = "人"; //~ ERROR mismatched types
}
29 changes: 29 additions & 0 deletions src/test/ui/inference/char-as-str-single.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
error[E0308]: mismatched types
--> $DIR/char-as-str-single.rs:9:19
|
LL | let _: char = "a";
| ---- ^^^ expected `char`, found `&str`
| |
| expected due to this
|
help: if you meant to write a `char` literal, use single quotes
|
LL | let _: char = 'a';
| ~~~

error[E0308]: mismatched types
--> $DIR/char-as-str-single.rs:10:19
|
LL | let _: char = "人";
| ---- ^^^^ expected `char`, found `&str`
| |
| expected due to this
|
help: if you meant to write a `char` literal, use single quotes
|
LL | let _: char = '人';
| ~~~~

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0308`.
8 changes: 8 additions & 0 deletions src/test/ui/inference/str-as-char.fixed
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// When a char literal is used where a str should be,
// suggest changing to double quotes.

// run-rustfix

fn main() {
let _: &str = "a"; //~ ERROR mismatched types
}
8 changes: 8 additions & 0 deletions src/test/ui/inference/str-as-char.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// When a char literal is used where a str should be,
// suggest changing to double quotes.

// run-rustfix

fn main() {
let _: &str = 'a'; //~ ERROR mismatched types
}
16 changes: 16 additions & 0 deletions src/test/ui/inference/str-as-char.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
error[E0308]: mismatched types
--> $DIR/str-as-char.rs:7:19
|
LL | let _: &str = 'a';
| ---- ^^^ expected `&str`, found `char`
| |
| expected due to this
|
help: if you meant to write a `str` literal, use double quotes
|
LL | let _: &str = "a";
| ~~~

error: aborting due to previous error

For more information about this error, try `rustc --explain E0308`.
5 changes: 5 additions & 0 deletions src/test/ui/issues/issue-23589.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@ error[E0308]: mismatched types
|
LL | let v: Vec(&str) = vec!['1', '2'];
| ^^^ expected `&str`, found `char`
|
help: if you meant to write a `str` literal, use double quotes
|
LL | let v: Vec(&str) = vec!["1", '2'];
| ~~~

error: aborting due to 2 previous errors

Expand Down

0 comments on commit 25fcc0e

Please sign in to comment.