diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 9a76c05e4f620..f0c73d0c2f369 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -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) = @@ -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, + ); + } + } + } _ => {} } } diff --git a/src/test/ui/inference/char-as-str-multi.rs b/src/test/ui/inference/char-as-str-multi.rs new file mode 100644 index 0000000000000..21bbc6f20b294 --- /dev/null +++ b/src/test/ui/inference/char-as-str-multi.rs @@ -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 +} diff --git a/src/test/ui/inference/char-as-str-multi.stderr b/src/test/ui/inference/char-as-str-multi.stderr new file mode 100644 index 0000000000000..c3ba17a5579ad --- /dev/null +++ b/src/test/ui/inference/char-as-str-multi.stderr @@ -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`. diff --git a/src/test/ui/inference/char-as-str-single.fixed b/src/test/ui/inference/char-as-str-single.fixed new file mode 100644 index 0000000000000..e401492a830b4 --- /dev/null +++ b/src/test/ui/inference/char-as-str-single.fixed @@ -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 +} diff --git a/src/test/ui/inference/char-as-str-single.rs b/src/test/ui/inference/char-as-str-single.rs new file mode 100644 index 0000000000000..4f23cea5354c3 --- /dev/null +++ b/src/test/ui/inference/char-as-str-single.rs @@ -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 +} diff --git a/src/test/ui/inference/char-as-str-single.stderr b/src/test/ui/inference/char-as-str-single.stderr new file mode 100644 index 0000000000000..29075c15414b2 --- /dev/null +++ b/src/test/ui/inference/char-as-str-single.stderr @@ -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`. diff --git a/src/test/ui/inference/str-as-char.fixed b/src/test/ui/inference/str-as-char.fixed new file mode 100644 index 0000000000000..09f3dec5a1755 --- /dev/null +++ b/src/test/ui/inference/str-as-char.fixed @@ -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 +} diff --git a/src/test/ui/inference/str-as-char.rs b/src/test/ui/inference/str-as-char.rs new file mode 100644 index 0000000000000..7092a61244255 --- /dev/null +++ b/src/test/ui/inference/str-as-char.rs @@ -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 +} diff --git a/src/test/ui/inference/str-as-char.stderr b/src/test/ui/inference/str-as-char.stderr new file mode 100644 index 0000000000000..ebbe7c80f7719 --- /dev/null +++ b/src/test/ui/inference/str-as-char.stderr @@ -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`. diff --git a/src/test/ui/issues/issue-23589.stderr b/src/test/ui/issues/issue-23589.stderr index d126e1bf0b534..e065e17c280f9 100644 --- a/src/test/ui/issues/issue-23589.stderr +++ b/src/test/ui/issues/issue-23589.stderr @@ -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