Skip to content

Commit b31086a

Browse files
author
Yiming Lei
committed
visit enum init when the enum variable doesn't have any parameters
this will fix #101208
1 parent 538f118 commit b31086a

File tree

6 files changed

+105
-5
lines changed

6 files changed

+105
-5
lines changed

compiler/rustc_hir_analysis/src/check/compare_method.rs

+3
Original file line numberDiff line numberDiff line change
@@ -403,6 +403,7 @@ fn compare_predicate_entailment<'tcx>(
403403
terr,
404404
false,
405405
false,
406+
false,
406407
);
407408

408409
return Err(diag.emit());
@@ -516,6 +517,7 @@ pub fn collect_trait_impl_trait_tys<'tcx>(
516517
terr,
517518
false,
518519
false,
520+
false,
519521
);
520522
return Err(diag.emit());
521523
}
@@ -1383,6 +1385,7 @@ pub(crate) fn raw_compare_const_impl<'tcx>(
13831385
terr,
13841386
false,
13851387
false,
1388+
false,
13861389
);
13871390
return Err(diag.emit());
13881391
};

compiler/rustc_hir_analysis/src/check/fn_ctxt/checks.rs

+1
Original file line numberDiff line numberDiff line change
@@ -848,6 +848,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
848848
e,
849849
false,
850850
true,
851+
false,
851852
);
852853
}
853854
}

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

+72-5
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
// ignore-tidy-filelength
12
//! Error Reporting Code for the inference engine
23
//!
34
//! Because of the way inference, and in particular region inference,
@@ -64,8 +65,12 @@ use rustc_errors::{Applicability, DiagnosticBuilder, DiagnosticStyledString, Mul
6465
use rustc_hir as hir;
6566
use rustc_hir::def::DefKind;
6667
use rustc_hir::def_id::{DefId, LocalDefId};
68+
use rustc_hir::intravisit::walk_block;
69+
use rustc_hir::intravisit::walk_expr;
70+
use rustc_hir::intravisit::Visitor;
6771
use rustc_hir::lang_items::LangItem;
68-
use rustc_hir::Node;
72+
use rustc_hir::HirId;
73+
use rustc_hir::{Expr, Node};
6974
use rustc_middle::dep_graph::DepContext;
7075
use rustc_middle::ty::print::with_no_trimmed_paths;
7176
use rustc_middle::ty::relate::{self, RelateResult, TypeRelation};
@@ -620,13 +625,55 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
620625
_ => (), // FIXME(#22750) handle traits and stuff
621626
}
622627
}
628+
fn note_enum_suggestion(
629+
&self,
630+
err: &mut Diagnostic,
631+
span: Span,
632+
body_id: HirId,
633+
arg_size: usize,
634+
) {
635+
let body_node = self.tcx.hir().get(body_id);
636+
let hir::Node::Expr(&hir::Expr{kind:hir::ExprKind::Block(body_expr, ..), ..}) = body_node else {return ()};
637+
struct FindExprVisitor<'tcx> {
638+
target_span: Span,
639+
size: usize,
640+
terr: &'tcx mut Diagnostic,
641+
}
642+
impl<'tcx> Visitor<'tcx> for FindExprVisitor<'tcx> {
643+
fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
644+
if expr.span == self.target_span {
645+
let mut suggest_vec = vec![];
646+
let mut i = 0;
647+
suggest_vec.push((expr.span.shrink_to_hi(), "(".to_string()));
648+
while i < self.size {
649+
suggest_vec.push((expr.span.shrink_to_hi(), "_".to_string()));
650+
if i != self.size - 1 {
651+
suggest_vec.push((expr.span.shrink_to_hi(), ",".to_string()));
652+
}
653+
i = i + 1;
654+
}
655+
suggest_vec.push((expr.span.shrink_to_hi(), ")".to_string()));
656+
657+
self.terr.multipart_suggestion(
658+
"use parentheses to instantiate this tuple variant",
659+
suggest_vec,
660+
Applicability::MachineApplicable,
661+
);
662+
}
663+
walk_expr(self, expr);
664+
}
665+
}
666+
let mut visitor = FindExprVisitor { target_span: span, size: arg_size, terr: err };
667+
walk_block(&mut visitor, body_expr);
668+
}
623669

624670
fn note_error_origin(
625671
&self,
626672
err: &mut Diagnostic,
627673
cause: &ObligationCause<'tcx>,
628674
exp_found: Option<ty::error::ExpectedFound<Ty<'tcx>>>,
629675
terr: TypeError<'tcx>,
676+
detect_enum_noparm: bool,
630677
) {
631678
match *cause.code() {
632679
ObligationCauseCode::Pattern { origin_expr: true, span: Some(span), root_ty } => {
@@ -640,8 +687,14 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
640687
{
641688
err.span_label(span, format!("this is an iterator with items of type `{}`", substs.type_at(0)));
642689
} else {
643-
err.span_label(span, format!("this expression has type `{}`", ty));
644-
}
690+
err.span_label(span, format!("this expression has type `{}`", ty));
691+
if detect_enum_noparm &&
692+
let ty::FnDef(def_id, substs) = ty.kind(){
693+
let sig = self.tcx.bound_fn_sig(*def_id).subst(self.tcx, substs);
694+
let sig = self.tcx.erase_late_bound_regions(sig);
695+
self.note_enum_suggestion(err, span, cause.body_id, sig.inputs().len());
696+
}
697+
}
645698
}
646699
if let Some(ty::error::ExpectedFound { found, .. }) = exp_found
647700
&& ty.is_box() && ty.boxed_ty() == found
@@ -1490,6 +1543,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
14901543
terr: TypeError<'tcx>,
14911544
swap_secondary_and_primary: bool,
14921545
prefer_label: bool,
1546+
detect_enum_noparm: bool,
14931547
) {
14941548
let span = cause.span();
14951549

@@ -1940,7 +1994,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
19401994

19411995
// It reads better to have the error origin as the final
19421996
// thing.
1943-
self.note_error_origin(diag, cause, exp_found, terr);
1997+
self.note_error_origin(diag, cause, exp_found, terr, detect_enum_noparm);
19441998

19451999
debug!(?diag);
19462000
}
@@ -2260,6 +2314,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
22602314

22612315
let span = trace.cause.span();
22622316
let failure_code = trace.cause.as_failure_code(terr);
2317+
let mut detect_enum_noparm = false;
22632318
let mut diag = match failure_code {
22642319
FailureCode::Error0038(did) => {
22652320
let violations = self.tcx.object_safety_violations(did);
@@ -2314,6 +2369,9 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
23142369
}
23152370
}
23162371
}
2372+
(ty::FnDef(_, _), ty::Adt(adt_id, _)) if adt_id.is_enum() => {
2373+
detect_enum_noparm = true;
2374+
}
23172375
_ => {}
23182376
}
23192377
}
@@ -2334,7 +2392,16 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
23342392
struct_span_err!(self.tcx.sess, span, E0644, "{}", failure_str)
23352393
}
23362394
};
2337-
self.note_type_err(&mut diag, &trace.cause, None, Some(trace.values), terr, false, false);
2395+
self.note_type_err(
2396+
&mut diag,
2397+
&trace.cause,
2398+
None,
2399+
Some(trace.values),
2400+
terr,
2401+
false,
2402+
false,
2403+
detect_enum_noparm,
2404+
);
23382405
diag
23392406
}
23402407

compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1682,6 +1682,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
16821682
err,
16831683
true,
16841684
false,
1685+
false,
16851686
);
16861687
self.note_obligation_cause(&mut diag, obligation);
16871688
diag.emit();

src/test/ui/type/issue-101208.rs

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
enum E {
2+
One(i32, i32)
3+
}
4+
fn main() {
5+
let var = E::One;
6+
if let E::One(var1, var2) = var {
7+
//~^ ERROR 0308
8+
println!("{var1} {var2}");
9+
}
10+
}

src/test/ui/type/issue-101208.stderr

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
error[E0308]: mismatched types
2+
--> $DIR/issue-101208.rs:6:12
3+
|
4+
LL | if let E::One(var1, var2) = var {
5+
| ^^^^^^^^^^^^^^^^^^ --- this expression has type `fn(i32, i32) -> E {E::One}`
6+
| |
7+
| expected fn item, found enum `E`
8+
|
9+
= note: expected fn item `fn(i32, i32) -> E {E::One}`
10+
found enum `E`
11+
help: use parentheses to instantiate this tuple variant
12+
|
13+
LL | if let E::One(var1, var2) = var(_,_) {
14+
| +
15+
16+
error: aborting due to previous error
17+
18+
For more information about this error, try `rustc --explain E0308`.

0 commit comments

Comments
 (0)