Skip to content

Commit 7264b68

Browse files
author
Yiming Lei
committed
visit enum init when the enum variable doesn't have any parameters
this fix #101208
1 parent 758f196 commit 7264b68

File tree

6 files changed

+106
-5
lines changed

6 files changed

+106
-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
}
@@ -1425,6 +1427,7 @@ pub(crate) fn raw_compare_const_impl<'tcx>(
14251427
terr,
14261428
false,
14271429
false,
1430+
false,
14281431
);
14291432
return Err(diag.emit());
14301433
};

compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs

+1
Original file line numberDiff line numberDiff line change
@@ -846,6 +846,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
846846
e,
847847
false,
848848
true,
849+
false,
849850
);
850851
}
851852
}

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

+73-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,12 +625,55 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
620625
}
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+
}
669+
623670
fn note_error_origin(
624671
&self,
625672
err: &mut Diagnostic,
626673
cause: &ObligationCause<'tcx>,
627674
exp_found: Option<ty::error::ExpectedFound<Ty<'tcx>>>,
628675
terr: TypeError<'tcx>,
676+
detect_enum_noparm: bool,
629677
) {
630678
match *cause.code() {
631679
ObligationCauseCode::Pattern { origin_expr: true, span: Some(span), root_ty } => {
@@ -639,8 +687,14 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
639687
{
640688
err.span_label(span, format!("this is an iterator with items of type `{}`", substs.type_at(0)));
641689
} else {
642-
err.span_label(span, format!("this expression has type `{}`", ty));
643-
}
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+
}
644698
}
645699
if let Some(ty::error::ExpectedFound { found, .. }) = exp_found
646700
&& ty.is_box() && ty.boxed_ty() == found
@@ -1489,6 +1543,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
14891543
terr: TypeError<'tcx>,
14901544
swap_secondary_and_primary: bool,
14911545
prefer_label: bool,
1546+
detect_enum_noparm: bool,
14921547
) {
14931548
let span = cause.span();
14941549

@@ -1939,7 +1994,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
19391994

19401995
// It reads better to have the error origin as the final
19411996
// thing.
1942-
self.note_error_origin(diag, cause, exp_found, terr);
1997+
self.note_error_origin(diag, cause, exp_found, terr, detect_enum_noparm);
19431998

19441999
debug!(?diag);
19452000
}
@@ -2259,6 +2314,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
22592314

22602315
let span = trace.cause.span();
22612316
let failure_code = trace.cause.as_failure_code(terr);
2317+
let mut detect_enum_noparm = false;
22622318
let mut diag = match failure_code {
22632319
FailureCode::Error0038(did) => {
22642320
let violations = self.tcx.object_safety_violations(did);
@@ -2332,6 +2388,9 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
23322388
}
23332389
}
23342390
}
2391+
(ty::FnDef(_, _), ty::Adt(adt_id, _)) if adt_id.is_enum() => {
2392+
detect_enum_noparm = true;
2393+
}
23352394
_ => {}
23362395
}
23372396
}
@@ -2352,7 +2411,16 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
23522411
struct_span_err!(self.tcx.sess, span, E0644, "{}", failure_str)
23532412
}
23542413
};
2355-
self.note_type_err(&mut diag, &trace.cause, None, Some(trace.values), terr, false, false);
2414+
self.note_type_err(
2415+
&mut diag,
2416+
&trace.cause,
2417+
None,
2418+
Some(trace.values),
2419+
terr,
2420+
false,
2421+
false,
2422+
detect_enum_noparm,
2423+
);
23562424
diag
23572425
}
23582426

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

+1
Original file line numberDiff line numberDiff line change
@@ -1687,6 +1687,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
16871687
err,
16881688
true,
16891689
false,
1690+
false,
16901691
);
16911692
self.note_obligation_cause(&mut diag, obligation);
16921693
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)