diff options
Diffstat (limited to 'compiler')
17 files changed, 100 insertions, 38 deletions
diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index b23cee14f75..7408b4fb0af 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -1648,7 +1648,7 @@ impl<'hir> LoweringContext<'_, '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 6340f1dcca1..0bfd62d68b2 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 `<expr>.await`. AwaitDesugar, /// A desugared `format_args!()`. @@ -2162,7 +2162,7 @@ impl MatchSource { 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 6d926cd8aa1..7ad9f51ba70 100644 --- a/compiler/rustc_hir_typeck/src/_match.rs +++ b/compiler/rustc_hir_typeck/src/_match.rs @@ -107,7 +107,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { 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 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { 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 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { 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 b4424f36744..726914a995b 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -1603,7 +1603,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { ); 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 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { ) && !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 40f9a954034..817115012a4 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 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { 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 15ed7fab65b..ac5468f3dfd 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 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { 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 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { 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 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { trace: &TypeTrace<'tcx>, terr: TypeError<'tcx>, ) -> Vec<TypeErrorAdditionalDiags> { - 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 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { // 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 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { && 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 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { 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 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { (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 @@ impl<'tcx> ObligationCauseExt<'tcx> for ObligationCause<'tcx> { 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 d08b6ba5e47..3cfda0cc5c0 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 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { 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 8e2e71fd879..ebc1c11902b 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 55ec17423ec..681400dbb94 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 2d655041c32..3465759b913 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<Span>, - pub scrut_hir_id: hir::HirId, pub opt_suggest_box_span: Option<Span>, } 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 295cddb1e15..fe5190900e9 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 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> { 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 c750727903f..a5c86e31a29 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 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { 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 a96d837b3ad..6c1f7d7a606 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 @@ impl<'tcx> Cx<'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 a786e659664..383e80851f0 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 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for MatchVisitor<'a, '_, '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 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> { | 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 903dbeeadfa..3b6276cfeb0 100644 --- a/compiler/rustc_mir_build/src/thir/print.rs +++ b/compiler/rustc_mir_build/src/thir/print.rs @@ -321,7 +321,7 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> { 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 495eb615ed8..8437e9a40e2 100644 --- a/compiler/rustc_passes/src/check_const.rs +++ b/compiler/rustc_passes/src/check_const.rs @@ -45,7 +45,7 @@ impl NonConstExpr { 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 d071cf76fd3..5e075984238 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 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { | ObligationCauseCode::MatchImpl(..) | ObligationCauseCode::ReturnType | ObligationCauseCode::ReturnValue(_) - | ObligationCauseCode::BlockTailExpression(_) + | ObligationCauseCode::BlockTailExpression(..) | ObligationCauseCode::AwaitableExpr(_) | ObligationCauseCode::ForLoopIterator | ObligationCauseCode::QuestionMark |
