From 736ab66c62ad23b880299e1f997ff1e4d7a9ceef Mon Sep 17 00:00:00 2001 From: Wafarm Date: Mon, 19 Aug 2024 11:37:11 +0800 Subject: [PATCH 01/20] Don't suggest adding return type for closures with default return type --- compiler/rustc_hir_typeck/src/_match.rs | 2 +- compiler/rustc_hir_typeck/src/coercion.rs | 4 +- compiler/rustc_hir_typeck/src/expr.rs | 2 +- .../rustc_hir_typeck/src/fn_ctxt/_impl.rs | 39 +++++---------- .../rustc_hir_typeck/src/fn_ctxt/checks.rs | 2 +- .../src/fn_ctxt/suggestions.rs | 49 ++++++++++++++----- .../add_semicolon_non_block_closure.rs | 1 - .../add_semicolon_non_block_closure.stderr | 4 -- .../try-operator-dont-suggest-semicolon.rs | 1 - ...try-operator-dont-suggest-semicolon.stderr | 17 ++----- tests/ui/typeck/issue-81943.stderr | 26 +++++----- 11 files changed, 74 insertions(+), 73 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/_match.rs b/compiler/rustc_hir_typeck/src/_match.rs index 7427fb147166f..573c8d4d7119a 100644 --- a/compiler/rustc_hir_typeck/src/_match.rs +++ b/compiler/rustc_hir_typeck/src/_match.rs @@ -388,7 +388,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { { // check that the `if` expr without `else` is the fn body's expr if expr.span == sp { - return self.get_fn_decl(hir_id).map(|(_, fn_decl, _)| { + return self.get_fn_decl(hir_id).map(|(_, fn_decl)| { let (ty, span) = match fn_decl.output { hir::FnRetTy::DefaultReturn(span) => ("()".to_string(), span), hir::FnRetTy::Return(ty) => (ty_to_string(&self.tcx, ty), ty.span), diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index dabc5a8939783..8e5d8cba5bef0 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -1859,10 +1859,10 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { }; // If this is due to an explicit `return`, suggest adding a return type. - if let Some((fn_id, fn_decl, can_suggest)) = fcx.get_fn_decl(block_or_return_id) + if let Some((fn_id, fn_decl)) = fcx.get_fn_decl(block_or_return_id) && !due_to_block { - fcx.suggest_missing_return_type(&mut err, fn_decl, expected, found, can_suggest, fn_id); + fcx.suggest_missing_return_type(&mut err, fn_decl, expected, found, fn_id); } // If this is due to a block, then maybe we forgot a `return`/`break`. diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index dd33b947b0d06..d70c3f6a0d843 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -773,7 +773,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.ret_coercion_span.set(Some(expr.span)); } let cause = self.cause(expr.span, ObligationCauseCode::ReturnNoExpression); - if let Some((_, fn_decl, _)) = self.get_fn_decl(expr.hir_id) { + if let Some((_, fn_decl)) = self.get_fn_decl(expr.hir_id) { coercion.coerce_forced_unit( self, &cause, diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index 2d205d1ede9cd..1c4a6fc22f797 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -31,7 +31,7 @@ use rustc_middle::{bug, span_bug}; use rustc_session::lint; use rustc_span::def_id::LocalDefId; use rustc_span::hygiene::DesugaringKind; -use rustc_span::symbol::{kw, sym}; +use rustc_span::symbol::kw; use rustc_span::Span; use rustc_target::abi::FieldIdx; use rustc_trait_selection::error_reporting::infer::need_type_info::TypeAnnotationNeeded; @@ -895,38 +895,28 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) } - /// Given a `HirId`, return the `HirId` of the enclosing function, its `FnDecl`, and whether a - /// suggestion can be made, `None` otherwise. + /// Given a `HirId`, return the `HirId` of the enclosing function and its `FnDecl`. pub(crate) fn get_fn_decl( &self, blk_id: HirId, - ) -> Option<(LocalDefId, &'tcx hir::FnDecl<'tcx>, bool)> { + ) -> Option<(LocalDefId, &'tcx hir::FnDecl<'tcx>)> { // Get enclosing Fn, if it is a function or a trait method, unless there's a `loop` or // `while` before reaching it, as block tail returns are not available in them. self.tcx.hir().get_fn_id_for_return_block(blk_id).and_then(|item_id| { match self.tcx.hir_node(item_id) { Node::Item(&hir::Item { - ident, - kind: hir::ItemKind::Fn(ref sig, ..), - owner_id, - .. - }) => { - // This is less than ideal, it will not suggest a return type span on any - // method called `main`, regardless of whether it is actually the entry point, - // but it will still present it as the reason for the expected type. - Some((owner_id.def_id, sig.decl, ident.name != sym::main)) - } + kind: hir::ItemKind::Fn(ref sig, ..), owner_id, .. + }) => Some((owner_id.def_id, sig.decl)), Node::TraitItem(&hir::TraitItem { kind: hir::TraitItemKind::Fn(ref sig, ..), owner_id, .. - }) => Some((owner_id.def_id, sig.decl, true)), - // FIXME: Suggestable if this is not a trait implementation + }) => Some((owner_id.def_id, sig.decl)), Node::ImplItem(&hir::ImplItem { kind: hir::ImplItemKind::Fn(ref sig, ..), owner_id, .. - }) => Some((owner_id.def_id, sig.decl, false)), + }) => Some((owner_id.def_id, sig.decl)), Node::Expr(&hir::Expr { hir_id, kind: hir::ExprKind::Closure(&hir::Closure { def_id, kind, fn_decl, .. }), @@ -937,33 +927,30 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // FIXME(async_closures): Implement this. return None; } - hir::ClosureKind::Closure => Some((def_id, fn_decl, true)), + hir::ClosureKind::Closure => Some((def_id, fn_decl)), hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared( _, hir::CoroutineSource::Fn, )) => { - let (ident, sig, owner_id) = match self.tcx.parent_hir_node(hir_id) { + let (sig, owner_id) = match self.tcx.parent_hir_node(hir_id) { Node::Item(&hir::Item { - ident, kind: hir::ItemKind::Fn(ref sig, ..), owner_id, .. - }) => (ident, sig, owner_id), + }) => (sig, owner_id), Node::TraitItem(&hir::TraitItem { - ident, kind: hir::TraitItemKind::Fn(ref sig, ..), owner_id, .. - }) => (ident, sig, owner_id), + }) => (sig, owner_id), Node::ImplItem(&hir::ImplItem { - ident, kind: hir::ImplItemKind::Fn(ref sig, ..), owner_id, .. - }) => (ident, sig, owner_id), + }) => (sig, owner_id), _ => return None, }; - Some((owner_id.def_id, sig.decl, ident.name != sym::main)) + Some((owner_id.def_id, sig.decl)) } _ => None, } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 5333982c42029..2a1c3b0300482 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -1841,7 +1841,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // that highlight errors inline. let mut sp = blk.span; let mut fn_span = None; - if let Some((fn_def_id, decl, _)) = self.get_fn_decl(blk.hir_id) { + if let Some((fn_def_id, decl)) = self.get_fn_decl(blk.hir_id) { let ret_sp = decl.output.span(); if let Some(block_sp) = self.parent_item_span(blk.hir_id) { // HACK: on some cases (`ui/liveness/liveness-issue-2163.rs`) the diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 031aa6159d2bc..8b63a6df8af00 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -78,9 +78,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // `break` type mismatches provide better context for tail `loop` expressions. return false; } - if let Some((fn_id, fn_decl, can_suggest)) = self.get_fn_decl(blk_id) { + if let Some((fn_id, fn_decl)) = self.get_fn_decl(blk_id) { pointing_at_return_type = - self.suggest_missing_return_type(err, fn_decl, expected, found, can_suggest, fn_id); + self.suggest_missing_return_type(err, fn_decl, expected, found, fn_id); self.suggest_missing_break_or_return_expr( err, expr, fn_decl, expected, found, blk_id, fn_id, ); @@ -812,7 +812,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn_decl: &hir::FnDecl<'tcx>, expected: Ty<'tcx>, found: Ty<'tcx>, - can_suggest: bool, fn_id: LocalDefId, ) -> bool { // Can't suggest `->` on a block-like coroutine @@ -825,28 +824,26 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let found = self.resolve_numeric_literals_with_default(self.resolve_vars_if_possible(found)); // Only suggest changing the return type for methods that - // haven't set a return type at all (and aren't `fn main()` or an impl). + // haven't set a return type at all (and aren't `fn main()`, impl or closure). match &fn_decl.output { - &hir::FnRetTy::DefaultReturn(span) if expected.is_unit() && !can_suggest => { - // `fn main()` must return `()`, do not suggest changing return type - err.subdiagnostic(errors::ExpectedReturnTypeLabel::Unit { span }); - return true; - } + // For closure with default returns, don't suggest adding return type + &hir::FnRetTy::DefaultReturn(_) if self.tcx.is_closure_like(fn_id.to_def_id()) => {} &hir::FnRetTy::DefaultReturn(span) if expected.is_unit() => { - if let Some(found) = found.make_suggestable(self.tcx, false, None) { + if !self.can_add_return_type(fn_id) { + err.subdiagnostic(errors::ExpectedReturnTypeLabel::Unit { span }); + } else if let Some(found) = found.make_suggestable(self.tcx, false, None) { err.subdiagnostic(errors::AddReturnTypeSuggestion::Add { span, found: found.to_string(), }); - return true; } else if let Some(sugg) = suggest_impl_trait(self, self.param_env, found) { err.subdiagnostic(errors::AddReturnTypeSuggestion::Add { span, found: sugg }); - return true; } else { // FIXME: if `found` could be `impl Iterator` we should suggest that. err.subdiagnostic(errors::AddReturnTypeSuggestion::MissingHere { span }); - return true; } + + return true; } hir::FnRetTy::Return(hir_ty) => { if let hir::TyKind::OpaqueDef(item_id, ..) = hir_ty.kind @@ -904,6 +901,32 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { false } + /// Checks whether we can add a return type to a function. + /// Assumes given function doesn't have a explicit return type. + fn can_add_return_type(&self, fn_id: LocalDefId) -> bool { + match self.tcx.hir_node_by_def_id(fn_id) { + Node::Item(&hir::Item { ident, .. }) => { + // This is less than ideal, it will not suggest a return type span on any + // method called `main`, regardless of whether it is actually the entry point, + // but it will still present it as the reason for the expected type. + ident.name != sym::main + } + Node::ImplItem(item) => { + // If it doesn't impl a trait, we can add a return type + let Node::Item(&hir::Item { + kind: hir::ItemKind::Impl(&hir::Impl { of_trait, .. }), + .. + }) = self.tcx.parent_hir_node(item.hir_id()) + else { + unreachable!(); + }; + + of_trait.is_none() + } + _ => true, + } + } + fn try_note_caller_chooses_ty_for_ty_param( &self, diag: &mut Diag<'_>, diff --git a/tests/ui/closures/add_semicolon_non_block_closure.rs b/tests/ui/closures/add_semicolon_non_block_closure.rs index 62c5e343cd345..3ae91be60c5a0 100644 --- a/tests/ui/closures/add_semicolon_non_block_closure.rs +++ b/tests/ui/closures/add_semicolon_non_block_closure.rs @@ -8,5 +8,4 @@ fn main() { foo(|| bar()) //~^ ERROR mismatched types [E0308] //~| HELP consider using a semicolon here - //~| HELP try adding a return type } diff --git a/tests/ui/closures/add_semicolon_non_block_closure.stderr b/tests/ui/closures/add_semicolon_non_block_closure.stderr index 7883db8f98ec5..3dd8f12d55f32 100644 --- a/tests/ui/closures/add_semicolon_non_block_closure.stderr +++ b/tests/ui/closures/add_semicolon_non_block_closure.stderr @@ -8,10 +8,6 @@ help: consider using a semicolon here | LL | foo(|| { bar(); }) | + +++ -help: try adding a return type - | -LL | foo(|| -> i32 bar()) - | ++++++ error: aborting due to 1 previous error diff --git a/tests/ui/suggestions/try-operator-dont-suggest-semicolon.rs b/tests/ui/suggestions/try-operator-dont-suggest-semicolon.rs index 35a06d396f2bb..f882a159f9834 100644 --- a/tests/ui/suggestions/try-operator-dont-suggest-semicolon.rs +++ b/tests/ui/suggestions/try-operator-dont-suggest-semicolon.rs @@ -3,7 +3,6 @@ fn main() -> Result<(), ()> { a(|| { - //~^ HELP: try adding a return type b() //~^ ERROR: mismatched types [E0308] //~| NOTE: expected `()`, found `i32` diff --git a/tests/ui/suggestions/try-operator-dont-suggest-semicolon.stderr b/tests/ui/suggestions/try-operator-dont-suggest-semicolon.stderr index 5506456afe9ca..939285498fb69 100644 --- a/tests/ui/suggestions/try-operator-dont-suggest-semicolon.stderr +++ b/tests/ui/suggestions/try-operator-dont-suggest-semicolon.stderr @@ -1,20 +1,13 @@ error[E0308]: mismatched types - --> $DIR/try-operator-dont-suggest-semicolon.rs:7:9 + --> $DIR/try-operator-dont-suggest-semicolon.rs:6:9 | LL | b() - | ^^^ expected `()`, found `i32` - | -help: consider using a semicolon here - | -LL | b(); - | + -help: try adding a return type - | -LL | a(|| -> i32 { - | ++++++ + | ^^^- help: consider using a semicolon here: `;` + | | + | expected `()`, found `i32` error[E0308]: mismatched types - --> $DIR/try-operator-dont-suggest-semicolon.rs:17:9 + --> $DIR/try-operator-dont-suggest-semicolon.rs:16:9 | LL | / if true { LL | | diff --git a/tests/ui/typeck/issue-81943.stderr b/tests/ui/typeck/issue-81943.stderr index f8da9ef0d180f..041ff10752cf0 100644 --- a/tests/ui/typeck/issue-81943.stderr +++ b/tests/ui/typeck/issue-81943.stderr @@ -2,9 +2,7 @@ error[E0308]: mismatched types --> $DIR/issue-81943.rs:7:9 | LL | f(|x| lib::d!(x)); - | -^^^^^^^^^^ expected `()`, found `i32` - | | - | help: try adding a return type: `-> i32` + | ^^^^^^^^^^ expected `()`, found `i32` | = note: this error originates in the macro `lib::d` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -12,22 +10,28 @@ error[E0308]: mismatched types --> $DIR/issue-81943.rs:8:28 | LL | f(|x| match x { tmp => { g(tmp) } }); - | ^^^^^^ expected `()`, found `i32` + | -------------------^^^^^^---- + | | | + | | expected `()`, found `i32` + | expected this to be `()` | help: consider using a semicolon here | LL | f(|x| match x { tmp => { g(tmp); } }); | + -help: try adding a return type +help: consider using a semicolon here | -LL | f(|x| -> i32 match x { tmp => { g(tmp) } }); - | ++++++ +LL | f(|x| match x { tmp => { g(tmp) } };); + | + error[E0308]: mismatched types --> $DIR/issue-81943.rs:10:38 | LL | ($e:expr) => { match $e { x => { g(x) } } } - | ^^^^ expected `()`, found `i32` + | ------------------^^^^---- + | | | + | | expected `()`, found `i32` + | expected this to be `()` LL | } LL | f(|x| d!(x)); | ----- in this macro invocation @@ -37,10 +41,10 @@ help: consider using a semicolon here | LL | ($e:expr) => { match $e { x => { g(x); } } } | + -help: try adding a return type +help: consider using a semicolon here | -LL | f(|x| -> i32 d!(x)); - | ++++++ +LL | ($e:expr) => { match $e { x => { g(x) } }; } + | + error: aborting due to 3 previous errors From 2ddcbca0e626cc3856349deeed17814ba6c272d6 Mon Sep 17 00:00:00 2001 From: tunawasabi <77270077+tunawasabi@users.noreply.github.com> Date: Sun, 25 Aug 2024 04:24:27 +0900 Subject: [PATCH 02/20] Suggest the struct variant pattern syntax on usage of unit variant pattern for a struct variant --- compiler/rustc_hir_typeck/src/lib.rs | 32 ++++++++++++++++++- .../ui/empty/empty-struct-braces-pat-1.stderr | 10 ++++++ .../ui/empty/empty-struct-braces-pat-3.stderr | 20 ++++++++++++ tests/ui/issues/issue-63983.stderr | 5 +++ .../recover/recover-from-bad-variant.stderr | 5 +++ tests/ui/suggestions/issue-84700.stderr | 5 +++ ...t-variant-form-through-alias-caught.stderr | 10 ++++++ 7 files changed, 86 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index 9ec101196a43f..0a4df619c20f3 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -45,7 +45,7 @@ pub use coercion::can_coerce; use fn_ctxt::FnCtxt; use rustc_data_structures::unord::UnordSet; use rustc_errors::codes::*; -use rustc_errors::{struct_span_code_err, Applicability, ErrorGuaranteed}; +use rustc_errors::{pluralize, struct_span_code_err, Applicability, ErrorGuaranteed}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::intravisit::Visitor; @@ -421,6 +421,36 @@ fn report_unexpected_variant_res( err.multipart_suggestion_verbose(descr, suggestion, Applicability::MaybeIncorrect); err } + Res::Def(DefKind::Variant, _) if expr.is_none() => { + err.span_label(span, format!("not a {expected}")); + + let fields = &tcx.expect_variant_res(res).fields.raw; + let span = qpath.span().shrink_to_hi().to(span.shrink_to_hi()); + let (msg, sugg) = if fields.is_empty() { + ("use the struct variant pattern syntax".to_string(), " {}".to_string()) + } else { + let msg = format!( + "the struct variant's field{s} {are} being ignored", + s = pluralize!(fields.len()), + are = pluralize!("is", fields.len()) + ); + let fields = fields + .iter() + .map(|field| format!("{}: _", field.name.to_ident_string())) + .collect::>() + .join(", "); + let sugg = format!(" {{ {} }}", fields); + (msg, sugg) + }; + + err.span_suggestion_verbose( + qpath.span().shrink_to_hi().to(span.shrink_to_hi()), + msg, + sugg, + Applicability::HasPlaceholders, + ); + err + } _ => err.with_span_label(span, format!("not a {expected}")), } .emit() diff --git a/tests/ui/empty/empty-struct-braces-pat-1.stderr b/tests/ui/empty/empty-struct-braces-pat-1.stderr index 14e09fc27a06d..c16fbc7de2b29 100644 --- a/tests/ui/empty/empty-struct-braces-pat-1.stderr +++ b/tests/ui/empty/empty-struct-braces-pat-1.stderr @@ -3,12 +3,22 @@ error[E0533]: expected unit struct, unit variant or constant, found struct varia | LL | E::Empty3 => () | ^^^^^^^^^ not a unit struct, unit variant or constant + | +help: use the struct variant pattern syntax + | +LL | E::Empty3 {} => () + | ++ error[E0533]: expected unit struct, unit variant or constant, found struct variant `XE::XEmpty3` --> $DIR/empty-struct-braces-pat-1.rs:31:9 | LL | XE::XEmpty3 => () | ^^^^^^^^^^^ not a unit struct, unit variant or constant + | +help: use the struct variant pattern syntax + | +LL | XE::XEmpty3 {} => () + | ++ error: aborting due to 2 previous errors diff --git a/tests/ui/empty/empty-struct-braces-pat-3.stderr b/tests/ui/empty/empty-struct-braces-pat-3.stderr index 00c8b12e6f984..b2ab7113347ff 100644 --- a/tests/ui/empty/empty-struct-braces-pat-3.stderr +++ b/tests/ui/empty/empty-struct-braces-pat-3.stderr @@ -3,24 +3,44 @@ error[E0164]: expected tuple struct or tuple variant, found struct variant `E::E | LL | E::Empty3() => () | ^^^^^^^^^^^ not a tuple struct or tuple variant + | +help: use the struct variant pattern syntax + | +LL | E::Empty3 {} => () + | ~~ error[E0164]: expected tuple struct or tuple variant, found struct variant `XE::XEmpty3` --> $DIR/empty-struct-braces-pat-3.rs:21:9 | LL | XE::XEmpty3() => () | ^^^^^^^^^^^^^ not a tuple struct or tuple variant + | +help: use the struct variant pattern syntax + | +LL | XE::XEmpty3 {} => () + | ~~ error[E0164]: expected tuple struct or tuple variant, found struct variant `E::Empty3` --> $DIR/empty-struct-braces-pat-3.rs:25:9 | LL | E::Empty3(..) => () | ^^^^^^^^^^^^^ not a tuple struct or tuple variant + | +help: use the struct variant pattern syntax + | +LL | E::Empty3 {} => () + | ~~ error[E0164]: expected tuple struct or tuple variant, found struct variant `XE::XEmpty3` --> $DIR/empty-struct-braces-pat-3.rs:29:9 | LL | XE::XEmpty3(..) => () | ^^^^^^^^^^^^^^^ not a tuple struct or tuple variant + | +help: use the struct variant pattern syntax + | +LL | XE::XEmpty3 {} => () + | ~~ error: aborting due to 4 previous errors diff --git a/tests/ui/issues/issue-63983.stderr b/tests/ui/issues/issue-63983.stderr index f90c81116264a..3539732451ce2 100644 --- a/tests/ui/issues/issue-63983.stderr +++ b/tests/ui/issues/issue-63983.stderr @@ -12,6 +12,11 @@ error[E0533]: expected unit struct, unit variant or constant, found struct varia | LL | MyEnum::Struct => "", | ^^^^^^^^^^^^^^ not a unit struct, unit variant or constant + | +help: the struct variant's field is being ignored + | +LL | MyEnum::Struct { s: _ } => "", + | ++++++++ error: aborting due to 2 previous errors diff --git a/tests/ui/parser/recover/recover-from-bad-variant.stderr b/tests/ui/parser/recover/recover-from-bad-variant.stderr index 04968bbdf999d..0339f86951543 100644 --- a/tests/ui/parser/recover/recover-from-bad-variant.stderr +++ b/tests/ui/parser/recover/recover-from-bad-variant.stderr @@ -19,6 +19,11 @@ error[E0164]: expected tuple struct or tuple variant, found struct variant `Enum | LL | Enum::Foo(a, b) => {} | ^^^^^^^^^^^^^^^ not a tuple struct or tuple variant + | +help: the struct variant's fields are being ignored + | +LL | Enum::Foo { a: _, b: _ } => {} + | ~~~~~~~~~~~~~~ error[E0769]: tuple variant `Enum::Bar` written as struct variant --> $DIR/recover-from-bad-variant.rs:12:9 diff --git a/tests/ui/suggestions/issue-84700.stderr b/tests/ui/suggestions/issue-84700.stderr index ac9f5ab0b0cbb..d07055826606d 100644 --- a/tests/ui/suggestions/issue-84700.stderr +++ b/tests/ui/suggestions/issue-84700.stderr @@ -12,6 +12,11 @@ error[E0164]: expected tuple struct or tuple variant, found struct variant `Farm | LL | FarmAnimal::Chicken(_) => "cluck, cluck!".to_string(), | ^^^^^^^^^^^^^^^^^^^^^^ not a tuple struct or tuple variant + | +help: the struct variant's field is being ignored + | +LL | FarmAnimal::Chicken { num_eggs: _ } => "cluck, cluck!".to_string(), + | ~~~~~~~~~~~~~~~ error: aborting due to 2 previous errors diff --git a/tests/ui/type-alias-enum-variants/incorrect-variant-form-through-alias-caught.stderr b/tests/ui/type-alias-enum-variants/incorrect-variant-form-through-alias-caught.stderr index c21c59397c79e..714b4fd7d25f6 100644 --- a/tests/ui/type-alias-enum-variants/incorrect-variant-form-through-alias-caught.stderr +++ b/tests/ui/type-alias-enum-variants/incorrect-variant-form-through-alias-caught.stderr @@ -14,12 +14,22 @@ error[E0533]: expected unit struct, unit variant or constant, found struct varia | LL | let Alias::Braced = panic!(); | ^^^^^^^^^^^^^ not a unit struct, unit variant or constant + | +help: use the struct variant pattern syntax + | +LL | let Alias::Braced {} = panic!(); + | ++ error[E0164]: expected tuple struct or tuple variant, found struct variant `Alias::Braced` --> $DIR/incorrect-variant-form-through-alias-caught.rs:12:9 | LL | let Alias::Braced(..) = panic!(); | ^^^^^^^^^^^^^^^^^ not a tuple struct or tuple variant + | +help: use the struct variant pattern syntax + | +LL | let Alias::Braced {} = panic!(); + | ~~ error[E0618]: expected function, found enum variant `Alias::Unit` --> $DIR/incorrect-variant-form-through-alias-caught.rs:15:5 From 7ed9f945a22a6e9cfb75405698e0eaa163c12beb Mon Sep 17 00:00:00 2001 From: Kyle Huey Date: Fri, 6 Sep 2024 12:39:11 -0700 Subject: [PATCH 03/20] Don't leave debug locations for constants sitting on the builder indefinitely. Because constants are currently emitted *before* the prologue, leaving the debug location on the IRBuilder spills onto other instructions in the prologue and messes up both line numbers as well as the point LLVM chooses to be the prologue end. Example LLVM IR (irrelevant IR elided): Before: define internal { i64, i64 } @_ZN3tmp3Foo18var_return_opt_try17he02116165b0fc08cE(ptr align 8 %self) !dbg !347 { start: %self.dbg.spill = alloca [8 x i8], align 8 %_0 = alloca [16 x i8], align 8 %residual.dbg.spill = alloca [0 x i8], align 1 #dbg_declare(ptr %residual.dbg.spill, !353, !DIExpression(), !357) store ptr %self, ptr %self.dbg.spill, align 8, !dbg !357 #dbg_declare(ptr %self.dbg.spill, !350, !DIExpression(), !358) After: define internal { i64, i64 } @_ZN3tmp3Foo18var_return_opt_try17h00b17d08874ddd90E(ptr align 8 %self) !dbg !347 { start: %self.dbg.spill = alloca [8 x i8], align 8 %_0 = alloca [16 x i8], align 8 %residual.dbg.spill = alloca [0 x i8], align 1 #dbg_declare(ptr %residual.dbg.spill, !353, !DIExpression(), !357) store ptr %self, ptr %self.dbg.spill, align 8 #dbg_declare(ptr %self.dbg.spill, !350, !DIExpression(), !358) Note in particular how !357 from %residual.dbg.spill's dbg_declare no longer falls through onto the store to %self.dbg.spill. This fixes argument values at entry when the constant is a ZST (e.g.