diff --git a/compiler/rustc_hir_analysis/src/check/compare_method.rs b/compiler/rustc_hir_analysis/src/check/compare_method.rs index 3469ec4767b7c..b844ecfdf1877 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_method.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_method.rs @@ -403,6 +403,7 @@ fn compare_predicate_entailment<'tcx>( terr, false, false, + false, ); return Err(diag.emit()); @@ -516,6 +517,7 @@ pub fn collect_trait_impl_trait_tys<'tcx>( terr, false, false, + false, ); return Err(diag.emit()); } @@ -1425,6 +1427,7 @@ pub(crate) fn raw_compare_const_impl<'tcx>( terr, false, false, + false, ); return Err(diag.emit()); }; diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 08a3cbccfb05e..7a47e8be74a2e 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -846,6 +846,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { e, false, true, + false, ); } } diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 9ff703e521ff6..fd7a06fccbfb0 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -1,3 +1,4 @@ +// ignore-tidy-filelength //! Error Reporting Code for the inference engine //! //! Because of the way inference, and in particular region inference, @@ -64,8 +65,12 @@ use rustc_errors::{Applicability, DiagnosticBuilder, DiagnosticStyledString, Mul use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_hir::intravisit::walk_block; +use rustc_hir::intravisit::walk_expr; +use rustc_hir::intravisit::Visitor; use rustc_hir::lang_items::LangItem; -use rustc_hir::Node; +use rustc_hir::HirId; +use rustc_hir::{Expr, Node}; use rustc_middle::dep_graph::DepContext; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::relate::{self, RelateResult, TypeRelation}; @@ -620,12 +625,55 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { } } + fn note_enum_suggestion( + &self, + err: &mut Diagnostic, + span: Span, + body_id: HirId, + arg_size: usize, + ) { + let body_node = self.tcx.hir().get(body_id); + let hir::Node::Expr(&hir::Expr{kind:hir::ExprKind::Block(body_expr, ..), ..}) = body_node else {return ()}; + struct FindExprVisitor<'tcx> { + target_span: Span, + size: usize, + terr: &'tcx mut Diagnostic, + } + impl<'tcx> Visitor<'tcx> for FindExprVisitor<'tcx> { + fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) { + if expr.span == self.target_span { + let mut suggest_vec = vec![]; + let mut i = 0; + suggest_vec.push((expr.span.shrink_to_hi(), "(".to_string())); + while i < self.size { + suggest_vec.push((expr.span.shrink_to_hi(), "_".to_string())); + if i != self.size - 1 { + suggest_vec.push((expr.span.shrink_to_hi(), ",".to_string())); + } + i = i + 1; + } + suggest_vec.push((expr.span.shrink_to_hi(), ")".to_string())); + + self.terr.multipart_suggestion( + "use parentheses to instantiate this tuple variant", + suggest_vec, + Applicability::MachineApplicable, + ); + } + walk_expr(self, expr); + } + } + let mut visitor = FindExprVisitor { target_span: span, size: arg_size, terr: err }; + walk_block(&mut visitor, body_expr); + } + fn note_error_origin( &self, err: &mut Diagnostic, cause: &ObligationCause<'tcx>, exp_found: Option<ty::error::ExpectedFound<Ty<'tcx>>>, terr: TypeError<'tcx>, + detect_enum_noparm: bool, ) { match *cause.code() { ObligationCauseCode::Pattern { origin_expr: true, span: Some(span), root_ty } => { @@ -639,8 +687,14 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { { err.span_label(span, format!("this is an iterator with items of type `{}`", substs.type_at(0))); } else { - err.span_label(span, format!("this expression has type `{}`", ty)); - } + err.span_label(span, format!("this expression has type `{}`", ty)); + if detect_enum_noparm && + let ty::FnDef(def_id, substs) = ty.kind(){ + let sig = self.tcx.bound_fn_sig(*def_id).subst(self.tcx, substs); + let sig = self.tcx.erase_late_bound_regions(sig); + self.note_enum_suggestion(err, span, cause.body_id, sig.inputs().len()); + } + } } if let Some(ty::error::ExpectedFound { found, .. }) = exp_found && ty.is_box() && ty.boxed_ty() == found @@ -1489,6 +1543,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { terr: TypeError<'tcx>, swap_secondary_and_primary: bool, prefer_label: bool, + detect_enum_noparm: bool, ) { let span = cause.span(); @@ -1939,7 +1994,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { // It reads better to have the error origin as the final // thing. - self.note_error_origin(diag, cause, exp_found, terr); + self.note_error_origin(diag, cause, exp_found, terr, detect_enum_noparm); debug!(?diag); } @@ -2259,6 +2314,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { let span = trace.cause.span(); let failure_code = trace.cause.as_failure_code(terr); + let mut detect_enum_noparm = false; let mut diag = match failure_code { FailureCode::Error0038(did) => { let violations = self.tcx.object_safety_violations(did); @@ -2332,6 +2388,9 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { } } } + (ty::FnDef(_, _), ty::Adt(adt_id, _)) if adt_id.is_enum() => { + detect_enum_noparm = true; + } _ => {} } } @@ -2352,7 +2411,16 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { struct_span_err!(self.tcx.sess, span, E0644, "{}", failure_str) } }; - self.note_type_err(&mut diag, &trace.cause, None, Some(trace.values), terr, false, false); + self.note_type_err( + &mut diag, + &trace.cause, + None, + Some(trace.values), + terr, + false, + false, + detect_enum_noparm, + ); diag } diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index 1217d264a9c1a..d99beb895f37b 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -1687,6 +1687,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { err, true, false, + false, ); self.note_obligation_cause(&mut diag, obligation); diag.emit(); diff --git a/src/test/ui/type/issue-101208.rs b/src/test/ui/type/issue-101208.rs new file mode 100644 index 0000000000000..49654a9e32734 --- /dev/null +++ b/src/test/ui/type/issue-101208.rs @@ -0,0 +1,10 @@ +enum E { + One(i32, i32) +} +fn main() { + let var = E::One; + if let E::One(var1, var2) = var { + //~^ ERROR 0308 + println!("{var1} {var2}"); + } +} diff --git a/src/test/ui/type/issue-101208.stderr b/src/test/ui/type/issue-101208.stderr new file mode 100644 index 0000000000000..ae6065df2f29e --- /dev/null +++ b/src/test/ui/type/issue-101208.stderr @@ -0,0 +1,18 @@ +error[E0308]: mismatched types + --> $DIR/issue-101208.rs:6:12 + | +LL | if let E::One(var1, var2) = var { + | ^^^^^^^^^^^^^^^^^^ --- this expression has type `fn(i32, i32) -> E {E::One}` + | | + | expected fn item, found enum `E` + | + = note: expected fn item `fn(i32, i32) -> E {E::One}` + found enum `E` +help: use parentheses to instantiate this tuple variant + | +LL | if let E::One(var1, var2) = var(_,_) { + | + + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`.