diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index b23cee14f758642a12d5218e03a83f3bb4c722f3..7408b4fb0af48be3deda8d5b7669136627ec82f0 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -1648,7 +1648,7 @@ fn lower_expr_try(&mut self, span: Span, sub_expr: &Expr) -> hir::ExprKind<'hir> hir::ExprKind::Match( scrutinee, arena_vec![self; break_arm, continue_arm], - hir::MatchSource::TryDesugar, + hir::MatchSource::TryDesugar(scrutinee.hir_id), ) } diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 6340f1dcca1c2f87472ba15cb9e142205b0c2dd4..0bfd62d68b295fe59f897cafab11a7a586b264a8 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -2148,7 +2148,7 @@ pub enum MatchSource { /// A desugared `for _ in _ { .. }` loop. ForLoopDesugar, /// A desugared `?` operator. - TryDesugar, + TryDesugar(HirId), /// A desugared `.await`. AwaitDesugar, /// A desugared `format_args!()`. @@ -2162,7 +2162,7 @@ pub const fn name(self) -> &'static str { match self { Normal => "match", ForLoopDesugar => "for", - TryDesugar => "?", + TryDesugar(_) => "?", AwaitDesugar => ".await", FormatArgs => "format_args!()", } diff --git a/compiler/rustc_hir_typeck/src/_match.rs b/compiler/rustc_hir_typeck/src/_match.rs index 6d926cd8aa1325eec00f2b43400c1818f47783a7..7ad9f51ba705de01ea2415d47450b063cc773d19 100644 --- a/compiler/rustc_hir_typeck/src/_match.rs +++ b/compiler/rustc_hir_typeck/src/_match.rs @@ -107,7 +107,9 @@ pub fn check_match( let (span, code) = match prior_arm { // The reason for the first arm to fail is not that the match arms diverge, // but rather that there's a prior obligation that doesn't hold. - None => (arm_span, ObligationCauseCode::BlockTailExpression(arm.body.hir_id)), + None => { + (arm_span, ObligationCauseCode::BlockTailExpression(arm.body.hir_id, match_src)) + } Some((prior_arm_block_id, prior_arm_ty, prior_arm_span)) => ( expr.span, ObligationCauseCode::MatchExpressionArm(Box::new(MatchExpressionArmCause { @@ -120,7 +122,6 @@ pub fn check_match( scrut_span: scrut.span, source: match_src, prior_arms: other_arms.clone(), - scrut_hir_id: scrut.hir_id, opt_suggest_box_span, })), ), @@ -145,7 +146,12 @@ pub fn check_match( other_arms.remove(0); } - prior_arm = Some((arm_block_id, arm_ty, arm_span)); + if !arm_ty.is_never() { + // When a match arm has type `!`, then it doesn't influence the expected type for + // the following arm. If all of the prior arms are `!`, then the influence comes + // from elsewhere and we shouldn't point to any previous arm. + prior_arm = Some((arm_block_id, arm_ty, arm_span)); + } } // If all of the arms in the `match` diverge, diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index b4424f367449d07853950ce205fc5cd8b26384b3..726914a995b136e749a5cc740b0454706ce4270e 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -1603,7 +1603,7 @@ pub(crate) fn coerce_inner<'a>( ); err.span_label(cause.span, "return type is not `()`"); } - ObligationCauseCode::BlockTailExpression(blk_id) => { + ObligationCauseCode::BlockTailExpression(blk_id, ..) => { let parent_id = fcx.tcx.hir().parent_id(blk_id); err = self.report_return_mismatched_types( cause, @@ -1748,7 +1748,7 @@ fn report_return_mismatched_types<'a>( ) && !in_external_macro(fcx.tcx.sess, cond_expr.span) && !matches!( cond_expr.kind, - hir::ExprKind::Match(.., hir::MatchSource::TryDesugar) + hir::ExprKind::Match(.., hir::MatchSource::TryDesugar(_)) ) { err.span_label(cond_expr.span, "expected this to be `()`"); diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 40f9a954034971eb87b8a5e832c49639b220255f..817115012a4674a2993f4e39194169378c8880cf 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -1580,7 +1580,10 @@ pub(in super::super) fn check_block_with_expected( let coerce = ctxt.coerce.as_mut().unwrap(); if let Some((tail_expr, tail_expr_ty)) = tail_expr_ty { let span = self.get_expr_coercion_span(tail_expr); - let cause = self.cause(span, ObligationCauseCode::BlockTailExpression(blk.hir_id)); + let cause = self.cause( + span, + ObligationCauseCode::BlockTailExpression(blk.hir_id, hir::MatchSource::Normal), + ); let ty_for_diagnostic = coerce.merged_ty(); // We use coerce_inner here because we want to augment the error // suggesting to wrap the block in square brackets if it might've diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 15ed7fab65be2336e051b346ae6bf55119f5e06c..ac5468f3dfd0f66fc291449fec8c39f5277c9d0e 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -743,6 +743,35 @@ fn note_error_origin( ObligationCauseCode::Pattern { origin_expr: false, span: Some(span), .. } => { err.span_label(span, "expected due to this"); } + ObligationCauseCode::BlockTailExpression( + _, + hir::MatchSource::TryDesugar(scrut_hir_id), + ) => { + if let Some(ty::error::ExpectedFound { expected, .. }) = exp_found { + let scrut_expr = self.tcx.hir().expect_expr(scrut_hir_id); + let scrut_ty = if let hir::ExprKind::Call(_, args) = &scrut_expr.kind { + let arg_expr = args.first().expect("try desugaring call w/out arg"); + self.typeck_results.as_ref().and_then(|typeck_results| { + typeck_results.expr_ty_opt(arg_expr) + }) + } else { + bug!("try desugaring w/out call expr as scrutinee"); + }; + + match scrut_ty { + Some(ty) if expected == ty => { + let source_map = self.tcx.sess.source_map(); + err.span_suggestion( + source_map.end_point(cause.span()), + "try removing this `?`", + "", + Applicability::MachineApplicable, + ); + } + _ => {} + } + } + }, ObligationCauseCode::MatchExpressionArm(box MatchExpressionArmCause { arm_block_id, arm_span, @@ -752,12 +781,11 @@ fn note_error_origin( prior_arm_ty, source, ref prior_arms, - scrut_hir_id, opt_suggest_box_span, scrut_span, .. }) => match source { - hir::MatchSource::TryDesugar => { + hir::MatchSource::TryDesugar(scrut_hir_id) => { if let Some(ty::error::ExpectedFound { expected, .. }) = exp_found { let scrut_expr = self.tcx.hir().expect_expr(scrut_hir_id); let scrut_ty = if let hir::ExprKind::Call(_, args) = &scrut_expr.kind { @@ -1978,7 +2006,7 @@ pub fn type_error_additional_suggestions( trace: &TypeTrace<'tcx>, terr: TypeError<'tcx>, ) -> Vec { - use crate::traits::ObligationCauseCode::MatchExpressionArm; + use crate::traits::ObligationCauseCode::{BlockTailExpression, MatchExpressionArm}; let mut suggestions = Vec::new(); let span = trace.cause.span(); let values = self.resolve_vars_if_possible(trace.values); @@ -1996,11 +2024,17 @@ pub fn type_error_additional_suggestions( // specify a byte literal (ty::Uint(ty::UintTy::U8), ty::Char) => { if let Ok(code) = self.tcx.sess().source_map().span_to_snippet(span) - && let Some(code) = code.strip_prefix('\'').and_then(|s| s.strip_suffix('\'')) - && !code.starts_with("\\u") // forbid all Unicode escapes - && code.chars().next().is_some_and(|c| c.is_ascii()) // forbids literal Unicode characters beyond ASCII + && let Some(code) = + code.strip_prefix('\'').and_then(|s| s.strip_suffix('\'')) + // forbid all Unicode escapes + && !code.starts_with("\\u") + // forbids literal Unicode characters beyond ASCII + && code.chars().next().is_some_and(|c| c.is_ascii()) { - suggestions.push(TypeErrorAdditionalDiags::MeantByteLiteral { span, code: escape_literal(code) }) + suggestions.push(TypeErrorAdditionalDiags::MeantByteLiteral { + span, + code: escape_literal(code), + }) } } // If a character was expected and the found expression is a string literal @@ -2011,7 +2045,10 @@ pub fn type_error_additional_suggestions( && let Some(code) = code.strip_prefix('"').and_then(|s| s.strip_suffix('"')) && code.chars().count() == 1 { - suggestions.push(TypeErrorAdditionalDiags::MeantCharLiteral { span, code: escape_literal(code) }) + suggestions.push(TypeErrorAdditionalDiags::MeantCharLiteral { + span, + code: escape_literal(code), + }) } } // If a string was expected and the found expression is a character literal, @@ -2021,7 +2058,10 @@ pub fn type_error_additional_suggestions( if let Some(code) = code.strip_prefix('\'').and_then(|s| s.strip_suffix('\'')) { - suggestions.push(TypeErrorAdditionalDiags::MeantStrLiteral { span, code: escape_literal(code) }) + suggestions.push(TypeErrorAdditionalDiags::MeantStrLiteral { + span, + code: escape_literal(code), + }) } } } @@ -2030,17 +2070,24 @@ pub fn type_error_additional_suggestions( (ty::Bool, ty::Tuple(list)) => if list.len() == 0 { suggestions.extend(self.suggest_let_for_letchains(&trace.cause, span)); } - (ty::Array(_, _), ty::Array(_, _)) => suggestions.extend(self.suggest_specify_actual_length(terr, trace, span)), + (ty::Array(_, _), ty::Array(_, _)) => { + suggestions.extend(self.suggest_specify_actual_length(terr, trace, span)) + } _ => {} } } let code = trace.cause.code(); - if let &MatchExpressionArm(box MatchExpressionArmCause { source, .. }) = code - && let hir::MatchSource::TryDesugar = source - && let Some((expected_ty, found_ty, _, _)) = self.values_str(trace.values) - { - suggestions.push(TypeErrorAdditionalDiags::TryCannotConvert { found: found_ty.content(), expected: expected_ty.content() }); - } + if let &(MatchExpressionArm(box MatchExpressionArmCause { source, .. }) + | BlockTailExpression(.., source) + ) = code + && let hir::MatchSource::TryDesugar(_) = source + && let Some((expected_ty, found_ty, _, _)) = self.values_str(trace.values) + { + suggestions.push(TypeErrorAdditionalDiags::TryCannotConvert { + found: found_ty.content(), + expected: expected_ty.content(), + }); + } suggestions } @@ -2910,8 +2957,11 @@ fn as_failure_code_diag( CompareImplItemObligation { kind: ty::AssocKind::Const, .. } => { ObligationCauseFailureCode::ConstCompat { span, subdiags } } + BlockTailExpression(.., hir::MatchSource::TryDesugar(_)) => { + ObligationCauseFailureCode::TryCompat { span, subdiags } + } MatchExpressionArm(box MatchExpressionArmCause { source, .. }) => match source { - hir::MatchSource::TryDesugar => { + hir::MatchSource::TryDesugar(_) => { ObligationCauseFailureCode::TryCompat { span, subdiags } } _ => ObligationCauseFailureCode::MatchCompat { span, subdiags }, diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs index d08b6ba5e47d93ea9ad85a7f6ae4badb68c5bf8c..3cfda0cc5c05c7fcd7b682b90c72118d8ddea309 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs @@ -146,7 +146,7 @@ pub(super) fn try_report_static_impl_trait(&self) -> Option { if let SubregionOrigin::Subtype(box TypeTrace { cause, .. }) = sub_origin { if let ObligationCauseCode::ReturnValue(hir_id) - | ObligationCauseCode::BlockTailExpression(hir_id) = cause.code() + | ObligationCauseCode::BlockTailExpression(hir_id, ..) = cause.code() { let parent_id = tcx.hir().get_parent_item(*hir_id); if let Some(fn_decl) = tcx.hir().fn_decl_by_hir_id(parent_id.into()) { diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index 8e2e71fd87984aa397bf5ff8be3007715cd89d28..ebc1c11902bcb17d7c2e2b04f69c388cb215b40b 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -346,6 +346,7 @@ pub enum ExprKind<'tcx> { /// A `match` expression. Match { scrutinee: ExprId, + scrutinee_hir_id: hir::HirId, arms: Box<[ArmId]>, }, /// A block. diff --git a/compiler/rustc_middle/src/thir/visit.rs b/compiler/rustc_middle/src/thir/visit.rs index 55ec17423ec93780a0051272d76801160fb7dfe2..681400dbb9481f08dc13a9bc5a44bc1edb0f3796 100644 --- a/compiler/rustc_middle/src/thir/visit.rs +++ b/compiler/rustc_middle/src/thir/visit.rs @@ -70,7 +70,7 @@ pub fn walk_expr<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, expr: &Exp visitor.visit_expr(&visitor.thir()[expr]); } Loop { body } => visitor.visit_expr(&visitor.thir()[body]), - Match { scrutinee, ref arms } => { + Match { scrutinee, ref arms, .. } => { visitor.visit_expr(&visitor.thir()[scrutinee]); for &arm in &**arms { visitor.visit_arm(&visitor.thir()[arm]); diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index 2d655041c32e8b1cdc1c14561ce3c749e4c8f08c..3465759b91340b6160be255d70c0b53727d2513b 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -402,7 +402,7 @@ pub enum ObligationCauseCode<'tcx> { OpaqueReturnType(Option<(Ty<'tcx>, Span)>), /// Block implicit return - BlockTailExpression(hir::HirId), + BlockTailExpression(hir::HirId, hir::MatchSource), /// #[feature(trivial_bounds)] is not enabled TrivialBound, @@ -543,7 +543,6 @@ pub struct MatchExpressionArmCause<'tcx> { pub scrut_span: Span, pub source: hir::MatchSource, pub prior_arms: Vec, - pub scrut_hir_id: hir::HirId, pub opt_suggest_box_span: Option, } diff --git a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs index 295cddb1e15b46cd050935fc5a11a9a4d1dcd809..fe5190900e9408392008c11fa6fa41e4a76a252e 100644 --- a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs +++ b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs @@ -65,7 +65,7 @@ pub fn parse_terminator(&self, expr_id: ExprId) -> PResult> let target = self.parse_block(args[1])?; self.parse_call(args[2], destination, target) }, - ExprKind::Match { scrutinee, arms } => { + ExprKind::Match { scrutinee, arms, .. } => { let discr = self.parse_operand(*scrutinee)?; self.parse_match(arms, expr.span).map(|t| TerminatorKind::SwitchInt { discr, targets: t }) }, diff --git a/compiler/rustc_mir_build/src/build/expr/into.rs b/compiler/rustc_mir_build/src/build/expr/into.rs index c750727903fdcc4d39d8847bcf30b8f9c127e2fa..a5c86e31a29219b07030a10c0fc8cfdd5891d0a7 100644 --- a/compiler/rustc_mir_build/src/build/expr/into.rs +++ b/compiler/rustc_mir_build/src/build/expr/into.rs @@ -47,7 +47,7 @@ pub(crate) fn expr_into_dest( ExprKind::Block { block: ast_block } => { this.ast_block(destination, block, ast_block, source_info) } - ExprKind::Match { scrutinee, ref arms } => { + ExprKind::Match { scrutinee, ref arms, .. } => { this.match_expr(destination, expr_span, block, &this.thir[scrutinee], arms) } ExprKind::If { cond, then, else_opt, if_then_scope } => { diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index a96d837b3adab2c40f72e733c3af11f572e77830..6c1f7d7a606675a1201188fed55ddd47e8624f28 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -732,6 +732,7 @@ fn make_mirror_unadjusted(&mut self, expr: &'tcx hir::Expr<'tcx>) -> Expr<'tcx> }, hir::ExprKind::Match(ref discr, ref arms, _) => ExprKind::Match { scrutinee: self.mirror_expr(discr), + scrutinee_hir_id: discr.hir_id, arms: arms.iter().map(|a| self.convert_arm(a)).collect(), }, hir::ExprKind::Loop(ref body, ..) => { diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index a786e65966423688e5073419b81b3cab5bfe3261..383e80851f0d7861295cf724ac96b4d7bb86b3bc 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -135,10 +135,12 @@ fn visit_expr(&mut self, ex: &Expr<'tcx>) { }); return; } - ExprKind::Match { scrutinee, box ref arms } => { + ExprKind::Match { scrutinee, scrutinee_hir_id, box ref arms } => { let source = match ex.span.desugaring_kind() { Some(DesugaringKind::ForLoop) => hir::MatchSource::ForLoopDesugar, - Some(DesugaringKind::QuestionMark) => hir::MatchSource::TryDesugar, + Some(DesugaringKind::QuestionMark) => { + hir::MatchSource::TryDesugar(scrutinee_hir_id) + } Some(DesugaringKind::Await) => hir::MatchSource::AwaitDesugar, _ => hir::MatchSource::Normal, }; @@ -277,7 +279,7 @@ fn check_match( | hir::MatchSource::FormatArgs => report_arm_reachability(&cx, &report), // Unreachable patterns in try and await expressions occur when one of // the arms are an uninhabited type. Which is OK. - hir::MatchSource::AwaitDesugar | hir::MatchSource::TryDesugar => {} + hir::MatchSource::AwaitDesugar | hir::MatchSource::TryDesugar(_) => {} } // Check if the match is exhaustive. diff --git a/compiler/rustc_mir_build/src/thir/print.rs b/compiler/rustc_mir_build/src/thir/print.rs index 903dbeeadfa26db56d4b91efda8a0347813881a8..3b6276cfeb0e6e6410fd1d0ff2f0c17621b99217 100644 --- a/compiler/rustc_mir_build/src/thir/print.rs +++ b/compiler/rustc_mir_build/src/thir/print.rs @@ -321,7 +321,7 @@ fn print_expr_kind(&mut self, expr_kind: &ExprKind<'tcx>, depth_lvl: usize) { print_indented!(self, format!("pat: {:?}", pat), depth_lvl + 1); print_indented!(self, "}", depth_lvl); } - Match { scrutinee, arms } => { + Match { scrutinee, arms, .. } => { print_indented!(self, "Match {", depth_lvl); print_indented!(self, "scrutinee:", depth_lvl + 1); self.print_expr(*scrutinee, depth_lvl + 2); diff --git a/compiler/rustc_passes/src/check_const.rs b/compiler/rustc_passes/src/check_const.rs index 495eb615ed889b4a21103aeab2b1522d3127df16..8437e9a40e2a21b57c4827782be1dc82f2ba5a17 100644 --- a/compiler/rustc_passes/src/check_const.rs +++ b/compiler/rustc_passes/src/check_const.rs @@ -45,7 +45,7 @@ fn required_feature_gates(self) -> Option<&'static [Symbol]> { Self::Loop(ForLoop) | Self::Match(ForLoopDesugar) => &[sym::const_for], - Self::Match(TryDesugar) => &[sym::const_try], + Self::Match(TryDesugar(_)) => &[sym::const_try], // All other expressions are allowed. Self::Loop(Loop | While) | Self::Match(Normal | FormatArgs) => &[], diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index d071cf76fd3ac4dcd05246fbc122563191c66af6..5e075984238ee1c6cc8e863ba23ee3ba3e03ff01 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -2700,7 +2700,7 @@ fn note_obligation_cause_code( | ObligationCauseCode::MatchImpl(..) | ObligationCauseCode::ReturnType | ObligationCauseCode::ReturnValue(_) - | ObligationCauseCode::BlockTailExpression(_) + | ObligationCauseCode::BlockTailExpression(..) | ObligationCauseCode::AwaitableExpr(_) | ObligationCauseCode::ForLoopIterator | ObligationCauseCode::QuestionMark diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs index bc011a6c354cbf95669d6828fc02d580320ec10a..58c27855000133b7cd5dcf2c27fe46c8f925f65f 100644 --- a/src/tools/clippy/clippy_lints/src/dereference.rs +++ b/src/tools/clippy/clippy_lints/src/dereference.rs @@ -802,7 +802,8 @@ fn in_postfix_position<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'tcx>) -> boo match parent.kind { ExprKind::Call(child, _) | ExprKind::MethodCall(_, child, _, _) | ExprKind::Index(child, _, _) if child.hir_id == e.hir_id => true, - ExprKind::Field(_, _) | ExprKind::Match(_, _, MatchSource::TryDesugar | MatchSource::AwaitDesugar) => true, + ExprKind::Match(.., MatchSource::TryDesugar(_) | MatchSource::AwaitDesugar) + | ExprKind::Field(_, _) => true, _ => false, } } else { diff --git a/src/tools/clippy/clippy_lints/src/matches/mod.rs b/src/tools/clippy/clippy_lints/src/matches/mod.rs index 6d16d188754081c9f042e6ef5e092977239b19ed..930386a60aa020a3cf60dafd91d82e89c9b35960 100644 --- a/src/tools/clippy/clippy_lints/src/matches/mod.rs +++ b/src/tools/clippy/clippy_lints/src/matches/mod.rs @@ -1038,7 +1038,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { wild_in_or_pats::check(cx, arms); } - if source == MatchSource::TryDesugar { + if let MatchSource::TryDesugar(_) = source { try_err::check(cx, expr, ex); } diff --git a/src/tools/clippy/clippy_lints/src/matches/try_err.rs b/src/tools/clippy/clippy_lints/src/matches/try_err.rs index 99a748489b4703c2471f98aff249a82ee6df9300..0fd6f533db0d5990d1e533a2162ec3303c6d7d3b 100644 --- a/src/tools/clippy/clippy_lints/src/matches/try_err.rs +++ b/src/tools/clippy/clippy_lints/src/matches/try_err.rs @@ -80,7 +80,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, scrutine /// Finds function return type by examining return expressions in match arms. fn find_return_type<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx ExprKind<'_>) -> Option> { - if let ExprKind::Match(_, arms, MatchSource::TryDesugar) = expr { + if let ExprKind::Match(_, arms, MatchSource::TryDesugar(_)) = expr { for arm in *arms { if let ExprKind::Ret(Some(ret)) = arm.body.kind { return Some(cx.typeck_results().expr_ty(ret)); diff --git a/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs b/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs index 7eb325ee7b5e7498a1859cd7503aad2d11c090f2..eb4f003d38ae503dfb446e7355ef800c5f9fa076 100644 --- a/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs +++ b/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs @@ -64,7 +64,7 @@ pub(super) fn check( ExprKind::Path(QPath::LangItem(rustc_hir::LangItem::TryTraitBranch, _, _)) ), ExprKind::MethodCall(_, self_arg, ..) if expr.hir_id == self_arg.hir_id => true, - ExprKind::Match(_, _, MatchSource::TryDesugar | MatchSource::AwaitDesugar) + ExprKind::Match(_, _, MatchSource::TryDesugar(_) | MatchSource::AwaitDesugar) | ExprKind::Field(..) | ExprKind::Index(..) => true, _ => false, diff --git a/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs b/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs index 41986551da4721f5606ccff3fa0040f08cd96bb5..7016ad0a80f1563176e94367f3022dc32b97672c 100644 --- a/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs +++ b/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs @@ -236,7 +236,7 @@ fn indirect_usage<'tcx>( !matches!( node, Node::Expr(Expr { - kind: ExprKind::Match(.., MatchSource::TryDesugar), + kind: ExprKind::Match(.., MatchSource::TryDesugar(_)), .. }) ) diff --git a/src/tools/clippy/clippy_lints/src/needless_question_mark.rs b/src/tools/clippy/clippy_lints/src/needless_question_mark.rs index e2a7ba02a043c553bde251d0d91dfa82b387509c..7b0f7eaf1f063762efe36da8b86125a77320c129 100644 --- a/src/tools/clippy/clippy_lints/src/needless_question_mark.rs +++ b/src/tools/clippy/clippy_lints/src/needless_question_mark.rs @@ -122,7 +122,7 @@ fn check(cx: &LateContext<'_>, expr: &Expr<'_>) { } else { return; }; - if let ExprKind::Match(inner_expr_with_q, _, MatchSource::TryDesugar) = &arg.kind; + if let ExprKind::Match(inner_expr_with_q, _, MatchSource::TryDesugar(_)) = &arg.kind; if let ExprKind::Call(called, [inner_expr]) = &inner_expr_with_q.kind; if let ExprKind::Path(QPath::LangItem(LangItem::TryTraitBranch, ..)) = &called.kind; if expr.span.ctxt() == inner_expr.span.ctxt(); diff --git a/src/tools/clippy/clippy_lints/src/question_mark_used.rs b/src/tools/clippy/clippy_lints/src/question_mark_used.rs index ff66b8a0095316c52bfbef26064bb98437f22526..d0de33e3c4f14dd313477632c256207c51a0282e 100644 --- a/src/tools/clippy/clippy_lints/src/question_mark_used.rs +++ b/src/tools/clippy/clippy_lints/src/question_mark_used.rs @@ -34,7 +34,7 @@ impl<'tcx> LateLintPass<'tcx> for QuestionMarkUsed { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if let ExprKind::Match(_, _, MatchSource::TryDesugar) = expr.kind { + if let ExprKind::Match(_, _, MatchSource::TryDesugar(_)) = expr.kind { if !span_is_local(expr.span) { return; } diff --git a/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs b/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs index 4e3efe97b8c61973a33c4b193ca177bf7c82ec45..fc49b58e0a7772832386d26495423a9991c948e7 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs @@ -52,7 +52,7 @@ fn new() -> Self { impl<'tcx> Visitor<'tcx> for ReturnVisitor { fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) { - if let hir::ExprKind::Ret(_) | hir::ExprKind::Match(.., hir::MatchSource::TryDesugar) = ex.kind { + if let hir::ExprKind::Ret(_) | hir::ExprKind::Match(.., hir::MatchSource::TryDesugar(_)) = ex.kind { self.found_return = true; } else { hir_visit::walk_expr(self, ex); diff --git a/src/tools/clippy/clippy_lints/src/returns.rs b/src/tools/clippy/clippy_lints/src/returns.rs index 351bacf5691f3886d4655d5ccb4d550c614f8ffc..d6b9a49d2fe05885c14835ce85b8356d0a8331cf 100644 --- a/src/tools/clippy/clippy_lints/src/returns.rs +++ b/src/tools/clippy/clippy_lints/src/returns.rs @@ -164,7 +164,7 @@ fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) { if !in_external_macro(cx.sess(), stmt.span) && let StmtKind::Semi(expr) = stmt.kind && let ExprKind::Ret(Some(ret)) = expr.kind - && let ExprKind::Match(.., MatchSource::TryDesugar) = ret.kind + && let ExprKind::Match(.., MatchSource::TryDesugar(_)) = ret.kind // Ensure this is not the final stmt, otherwise removing it would cause a compile error && let OwnerNode::Item(item) = cx.tcx.hir().owner(cx.tcx.hir().get_parent_item(expr.hir_id)) && let ItemKind::Fn(_, _, body) = item.kind diff --git a/src/tools/clippy/clippy_lints/src/unit_types/unit_arg.rs b/src/tools/clippy/clippy_lints/src/unit_types/unit_arg.rs index dd120599c04e1b9c6f0175a4644e4c14dd1b00c8..462b1aa8153e76ba3027f84ffa42ad5843d0203b 100644 --- a/src/tools/clippy/clippy_lints/src/unit_types/unit_arg.rs +++ b/src/tools/clippy/clippy_lints/src/unit_types/unit_arg.rs @@ -42,7 +42,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { if cx.typeck_results().expr_ty(arg).is_unit() && !utils::is_unit_literal(arg) { !matches!( &arg.kind, - ExprKind::Match(.., MatchSource::TryDesugar) | ExprKind::Path(..) + ExprKind::Match(.., MatchSource::TryDesugar(_)) | ExprKind::Path(..) ) } else { false diff --git a/src/tools/clippy/clippy_lints/src/useless_conversion.rs b/src/tools/clippy/clippy_lints/src/useless_conversion.rs index 92b694d30760024dd4161a2dfed7b675802c556f..bd4dc07a42bfa37561fa3a7f736dfd97bb1fac73 100644 --- a/src/tools/clippy/clippy_lints/src/useless_conversion.rs +++ b/src/tools/clippy/clippy_lints/src/useless_conversion.rs @@ -113,7 +113,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { } match e.kind { - ExprKind::Match(_, arms, MatchSource::TryDesugar) => { + ExprKind::Match(_, arms, MatchSource::TryDesugar(_)) => { let (ExprKind::Ret(Some(e)) | ExprKind::Break(_, Some(e))) = arms[0].body.kind else { return; }; diff --git a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs index 60fab1ec41aeb0f0fd425902bfab48cd047bb2ff..6be8b8bb9169661f6028108293b99e7f10800d76 100644 --- a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs +++ b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs @@ -149,7 +149,7 @@ fn expr_search_pat(tcx: TyCtxt<'_>, e: &Expr<'_>) -> (Pat, Pat) { (Pat::Str("for"), Pat::Str("}")) }, ExprKind::Match(_, _, MatchSource::Normal) => (Pat::Str("match"), Pat::Str("}")), - ExprKind::Match(e, _, MatchSource::TryDesugar) => (expr_search_pat(tcx, e).0, Pat::Str("?")), + ExprKind::Match(e, _, MatchSource::TryDesugar(_)) => (expr_search_pat(tcx, e).0, Pat::Str("?")), ExprKind::Match(e, _, MatchSource::AwaitDesugar) | ExprKind::Yield(e, YieldSource::Await { .. }) => { (expr_search_pat(tcx, e).0, Pat::Str("await")) }, diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index b77a2f1d0cd055107f867fea2918416e9e2a13d2..6c4cec595247160bead694bfa93eef37c5705b9d 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -1765,7 +1765,7 @@ fn is_err(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool { if let ExprKind::Match(_, arms, ref source) = expr.kind { // desugared from a `?` operator - if *source == MatchSource::TryDesugar { + if let MatchSource::TryDesugar(_) = *source { return Some(expr); } diff --git a/src/tools/clippy/clippy_utils/src/visitors.rs b/src/tools/clippy/clippy_utils/src/visitors.rs index f83988a6e325ab55cedb92d798affb9c22d1a84c..3b47a451345ebeeb9f32f5fe59ac3900e4af2d95 100644 --- a/src/tools/clippy/clippy_utils/src/visitors.rs +++ b/src/tools/clippy/clippy_utils/src/visitors.rs @@ -161,7 +161,7 @@ fn visit_nested_item(&mut self, _: ItemId) {} /// returns `true` if expr contains match expr desugared from try fn contains_try(expr: &hir::Expr<'_>) -> bool { for_each_expr(expr, |e| { - if matches!(e.kind, hir::ExprKind::Match(_, _, hir::MatchSource::TryDesugar)) { + if matches!(e.kind, hir::ExprKind::Match(_, _, hir::MatchSource::TryDesugar(_))) { ControlFlow::Break(()) } else { ControlFlow::Continue(()) diff --git a/src/tools/clippy/tests/ui/if_same_then_else2.rs b/src/tools/clippy/tests/ui/if_same_then_else2.rs index 0b171f21d0cc4c07e8d35fded0cf62eae47afd64..c545434efe5b515f61f1d66b5c90e0ecfb0ccb84 100644 --- a/src/tools/clippy/tests/ui/if_same_then_else2.rs +++ b/src/tools/clippy/tests/ui/if_same_then_else2.rs @@ -98,7 +98,7 @@ fn if_same_then_else2() -> Result<&'static str, ()> { }; if true { - //~^ ERROR: this `if` has identical blocks + // FIXME: should emit "this `if` has identical blocks" Ok("foo")?; } else { Ok("foo")?; diff --git a/src/tools/clippy/tests/ui/if_same_then_else2.stderr b/src/tools/clippy/tests/ui/if_same_then_else2.stderr index 56e5f3e45b22c42d8c6ed991275bd2182fc73660..37fe787d1de3a4d6f126e82a6f2fb893508f75ca 100644 --- a/src/tools/clippy/tests/ui/if_same_then_else2.stderr +++ b/src/tools/clippy/tests/ui/if_same_then_else2.stderr @@ -82,25 +82,6 @@ LL | | f32::NAN LL | | }; | |_____^ -error: this `if` has identical blocks - --> $DIR/if_same_then_else2.rs:100:13 - | -LL | if true { - | _____________^ -LL | | -LL | | Ok("foo")?; -LL | | } else { - | |_____^ - | -note: same as this - --> $DIR/if_same_then_else2.rs:103:12 - | -LL | } else { - | ____________^ -LL | | Ok("foo")?; -LL | | } - | |_____^ - error: this `if` has identical blocks --> $DIR/if_same_then_else2.rs:124:20 | @@ -122,5 +103,5 @@ LL | | return Ok(&foo[0..]); LL | | } | |_____^ -error: aborting due to 6 previous errors +error: aborting due to 5 previous errors diff --git a/tests/ui/did_you_mean/compatible-variants.stderr b/tests/ui/did_you_mean/compatible-variants.stderr index 7b88d93ead112bd21905a8c4de5660626d663f56..f2bbd8ced8f2449ee105b86a6542fa4e445997a2 100644 --- a/tests/ui/did_you_mean/compatible-variants.stderr +++ b/tests/ui/did_you_mean/compatible-variants.stderr @@ -61,6 +61,8 @@ LL + Some(()) error[E0308]: `?` operator has incompatible types --> $DIR/compatible-variants.rs:35:5 | +LL | fn d() -> Option<()> { + | ---------- expected `Option<()>` because of return type LL | c()? | ^^^^ expected `Option<()>`, found `()` | diff --git a/tests/ui/issues/issue-51632-try-desugar-incompatible-types.stderr b/tests/ui/issues/issue-51632-try-desugar-incompatible-types.stderr index 7180a3d2426d109bca8556dcb9272fdd68ba132b..c92da53dbc48b2a6fd30cc7020715e4e25ceb421 100644 --- a/tests/ui/issues/issue-51632-try-desugar-incompatible-types.stderr +++ b/tests/ui/issues/issue-51632-try-desugar-incompatible-types.stderr @@ -1,6 +1,8 @@ error[E0308]: `?` operator has incompatible types --> $DIR/issue-51632-try-desugar-incompatible-types.rs:8:5 | +LL | fn forbidden_narratives() -> Result { + | ----------------- expected `Result` because of return type LL | missing_discourses()? | ^^^^^^^^^^^^^^^^^^^^^ expected `Result`, found `isize` | diff --git a/tests/ui/match/non-first-arm-doesnt-match-expected-return-type.rs b/tests/ui/match/non-first-arm-doesnt-match-expected-return-type.rs new file mode 100644 index 0000000000000000000000000000000000000000..85b1ef7555edcbe31c96a84c917266b1c34ffe34 --- /dev/null +++ b/tests/ui/match/non-first-arm-doesnt-match-expected-return-type.rs @@ -0,0 +1,21 @@ +#![allow(unused)] + +fn test(shouldwe: Option, shouldwe2: Option) -> u32 { + //~^ NOTE expected `u32` because of return type + match shouldwe { + Some(val) => { + match shouldwe2 { + Some(val) => { + return val; + } + None => (), //~ ERROR mismatched types + //~^ NOTE expected `u32`, found `()` + } + } + None => return 12, + } +} + +fn main() { + println!("returned {}", test(None, Some(5))); +} diff --git a/tests/ui/match/non-first-arm-doesnt-match-expected-return-type.stderr b/tests/ui/match/non-first-arm-doesnt-match-expected-return-type.stderr new file mode 100644 index 0000000000000000000000000000000000000000..e6d93b8b5f57b8ff96bc2013f45e22e024f8e532 --- /dev/null +++ b/tests/ui/match/non-first-arm-doesnt-match-expected-return-type.stderr @@ -0,0 +1,12 @@ +error[E0308]: mismatched types + --> $DIR/non-first-arm-doesnt-match-expected-return-type.rs:11:25 + | +LL | fn test(shouldwe: Option, shouldwe2: Option) -> u32 { + | --- expected `u32` because of return type +... +LL | None => (), + | ^^ expected `u32`, found `()` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/suggestions/remove-question-symbol-with-paren.stderr b/tests/ui/suggestions/remove-question-symbol-with-paren.stderr index 39e35f733a1d276183bfb348df5172f247297e9b..40b9cf2dcd4d4cc24996913e4764a1a49091617b 100644 --- a/tests/ui/suggestions/remove-question-symbol-with-paren.stderr +++ b/tests/ui/suggestions/remove-question-symbol-with-paren.stderr @@ -1,6 +1,9 @@ error[E0308]: `?` operator has incompatible types --> $DIR/remove-question-symbol-with-paren.rs:5:6 | +LL | fn foo() -> Option<()> { + | ---------- expected `Option<()>` because of return type +LL | let x = Some(()); LL | (x?) | ^^ expected `Option<()>`, found `()` |