diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index fb762d2deba7c..e3a79fe265330 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -64,6 +64,7 @@ use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::lang_items::LangItem; use rustc_hir::{Item, ItemKind, Node}; +use rustc_middle::dep_graph::DepContext; use rustc_middle::ty::error::TypeError; use rustc_middle::ty::{ self, @@ -1965,7 +1966,33 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { struct_span_err!(self.tcx.sess, span, E0580, "{}", failure_str) } FailureCode::Error0308(failure_str) => { - struct_span_err!(self.tcx.sess, span, E0308, "{}", failure_str) + let mut err = struct_span_err!(self.tcx.sess, span, E0308, "{}", failure_str); + 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(_)) => {} + (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) = + code.strip_prefix('(').and_then(|s| s.strip_suffix(')')) + { + err.span_suggestion( + span, + "use a trailing comma to create a tuple with one element", + format!("({},)", code), + Applicability::MaybeIncorrect, + ); + } + } + } + _ => {} + } + } + err } FailureCode::Error0644(failure_str) => { struct_span_err!(self.tcx.sess, span, E0644, "{}", failure_str) diff --git a/src/test/ui/suggestions/issue-86100-tuple-paren-comma.rs b/src/test/ui/suggestions/issue-86100-tuple-paren-comma.rs new file mode 100644 index 0000000000000..fa9d1a88928cd --- /dev/null +++ b/src/test/ui/suggestions/issue-86100-tuple-paren-comma.rs @@ -0,0 +1,25 @@ +// Tests that a suggestion is issued for type mismatch errors when a +// 1-tuple is expected and a parenthesized expression of non-tuple +// type is supplied. + +fn foo(_t: (T,)) {} +struct S { _s: (String,) } + +fn main() { + let _x: (i32,) = (5); + //~^ ERROR: mismatched types [E0308] + //~| HELP: use a trailing comma to create a tuple with one element + + foo((Some(3))); + //~^ ERROR: mismatched types [E0308] + //~| HELP: use a trailing comma to create a tuple with one element + + let _s = S { _s: ("abc".to_string()) }; + //~^ ERROR: mismatched types [E0308] + //~| HELP: use a trailing comma to create a tuple with one element + + // Do not issue the suggestion if the found type is already a tuple. + let t = (1, 2); + let _x: (i32,) = (t); + //~^ ERROR: mismatched types [E0308] +} diff --git a/src/test/ui/suggestions/issue-86100-tuple-paren-comma.stderr b/src/test/ui/suggestions/issue-86100-tuple-paren-comma.stderr new file mode 100644 index 0000000000000..575379690b46f --- /dev/null +++ b/src/test/ui/suggestions/issue-86100-tuple-paren-comma.stderr @@ -0,0 +1,55 @@ +error[E0308]: mismatched types + --> $DIR/issue-86100-tuple-paren-comma.rs:9:22 + | +LL | let _x: (i32,) = (5); + | ------ ^^^ expected tuple, found integer + | | + | expected due to this + | + = note: expected tuple `(i32,)` + found type `{integer}` +help: use a trailing comma to create a tuple with one element + | +LL | let _x: (i32,) = (5,); + | ^^^^ + +error[E0308]: mismatched types + --> $DIR/issue-86100-tuple-paren-comma.rs:13:9 + | +LL | foo((Some(3))); + | ^^^^^^^^^ expected tuple, found enum `Option` + | + = note: expected tuple `(_,)` + found enum `Option<{integer}>` +help: use a trailing comma to create a tuple with one element + | +LL | foo((Some(3),)); + | ^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/issue-86100-tuple-paren-comma.rs:17:22 + | +LL | let _s = S { _s: ("abc".to_string()) }; + | ^^^^^^^^^^^^^^^^^^^ expected tuple, found struct `String` + | + = note: expected tuple `(String,)` + found struct `String` +help: use a trailing comma to create a tuple with one element + | +LL | let _s = S { _s: ("abc".to_string(),) }; + | ^^^^^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/issue-86100-tuple-paren-comma.rs:23:22 + | +LL | let _x: (i32,) = (t); + | ------ ^^^ expected a tuple with 1 element, found one with 2 elements + | | + | expected due to this + | + = note: expected tuple `(i32,)` + found tuple `({integer}, {integer})` + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0308`.