From 2507e83d7bb0dd9e7217b10b13afc61763dc1eca Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 27 Oct 2024 22:35:17 +0000 Subject: [PATCH 1/2] Stop using the whole match expr span for an arm's obligation span --- compiler/rustc_hir_typeck/src/_match.rs | 16 +++++++--------- compiler/rustc_middle/src/traits/mod.rs | 2 ++ .../src/error_reporting/infer/mod.rs | 7 ++++--- tests/ui/wf/wf-dyn-incompat-trait-obj-match.rs | 4 ++-- .../ui/wf/wf-dyn-incompat-trait-obj-match.stderr | 10 +++------- 5 files changed, 18 insertions(+), 21 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/_match.rs b/compiler/rustc_hir_typeck/src/_match.rs index e68caa3e2e35e..3372cae7a5107 100644 --- a/compiler/rustc_hir_typeck/src/_match.rs +++ b/compiler/rustc_hir_typeck/src/_match.rs @@ -94,14 +94,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { (None, arm.body.span) }; - let (span, code) = match prior_arm { + let 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, match_src)) - } - Some((prior_arm_block_id, prior_arm_ty, prior_arm_span)) => ( - expr.span, + None => ObligationCauseCode::BlockTailExpression(arm.body.hir_id, match_src), + Some((prior_arm_block_id, prior_arm_ty, prior_arm_span)) => { ObligationCauseCode::MatchExpressionArm(Box::new(MatchExpressionArmCause { arm_block_id, arm_span, @@ -110,13 +107,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { prior_arm_ty, prior_arm_span, scrut_span: scrut.span, + expr_span: expr.span, source: match_src, prior_non_diverging_arms: prior_non_diverging_arms.clone(), tail_defines_return_position_impl_trait, - })), - ), + })) + } }; - let cause = self.cause(span, code); + let cause = self.cause(arm_span, code); // This is the moral equivalent of `coercion.coerce(self, cause, arm.body, arm_ty)`. // We use it this way to be able to expand on the potential error and detect when a diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index 8ee8b4c4823a8..7237a7014e874 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -519,6 +519,8 @@ pub struct MatchExpressionArmCause<'tcx> { pub prior_arm_span: Span, pub scrut_span: Span, pub source: hir::MatchSource, + // Span of the *whole* match expr + pub expr_span: Span, pub prior_non_diverging_arms: Vec, // Is the expectation of this match expression an RPIT? pub tail_defines_return_position_impl_trait: Option, diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs index b9a569d25e324..0cbb43b876387 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs @@ -412,6 +412,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { source, ref prior_non_diverging_arms, scrut_span, + expr_span, .. }) => match source { hir::MatchSource::TryDesugar(scrut_hir_id) => { @@ -460,12 +461,12 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { format!("this and all prior arms are found to be of type `{t}`"), ); } - let outer = if any_multiline_arm || !source_map.is_multiline(cause.span) { + let outer = if any_multiline_arm || !source_map.is_multiline(expr_span) { // Cover just `match` and the scrutinee expression, not // the entire match body, to reduce diagram noise. - cause.span.shrink_to_lo().to(scrut_span) + expr_span.shrink_to_lo().to(scrut_span) } else { - cause.span + expr_span }; let msg = "`match` arms have incompatible types"; err.span_label(outer, msg); diff --git a/tests/ui/wf/wf-dyn-incompat-trait-obj-match.rs b/tests/ui/wf/wf-dyn-incompat-trait-obj-match.rs index 07e90538b85dd..6eba6b7abecd4 100644 --- a/tests/ui/wf/wf-dyn-incompat-trait-obj-match.rs +++ b/tests/ui/wf/wf-dyn-incompat-trait-obj-match.rs @@ -22,8 +22,8 @@ fn main() { Some(()) => &S, None => &R, //~ ERROR E0308 } - let t: &dyn Trait = match opt() { //~ ERROR E0038 + let t: &dyn Trait = match opt() { Some(()) => &S, //~ ERROR E0038 - None => &R, + None => &R, //~ ERROR E0038 }; } diff --git a/tests/ui/wf/wf-dyn-incompat-trait-obj-match.stderr b/tests/ui/wf/wf-dyn-incompat-trait-obj-match.stderr index d7366e12256a2..6cd4ebf8412b6 100644 --- a/tests/ui/wf/wf-dyn-incompat-trait-obj-match.stderr +++ b/tests/ui/wf/wf-dyn-incompat-trait-obj-match.stderr @@ -31,14 +31,10 @@ LL | trait Trait: Sized {} = note: required for the cast from `&S` to `&dyn Trait` error[E0038]: the trait `Trait` cannot be made into an object - --> $DIR/wf-dyn-incompat-trait-obj-match.rs:25:25 + --> $DIR/wf-dyn-incompat-trait-obj-match.rs:27:17 | -LL | let t: &dyn Trait = match opt() { - | _________________________^ -LL | | Some(()) => &S, -LL | | None => &R, -LL | | }; - | |_____^ `Trait` cannot be made into an object +LL | None => &R, + | ^^ `Trait` cannot be made into an object | note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit --> $DIR/wf-dyn-incompat-trait-obj-match.rs:6:14 From 7f54b9ecefc38a8a3fde9a98b253eeb6f775b25a Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 27 Oct 2024 22:53:14 +0000 Subject: [PATCH 2/2] Remove ObligationCause::span() method --- .../src/check/compare_impl_item.rs | 4 ++-- compiler/rustc_hir_analysis/src/check/mod.rs | 2 +- compiler/rustc_hir_typeck/src/expr.rs | 2 +- .../rustc_hir_typeck/src/method/confirm.rs | 2 +- compiler/rustc_middle/src/traits/mod.rs | 19 +++++++------------ .../src/error_reporting/infer/mod.rs | 10 +++++----- .../nice_region_error/placeholder_error.rs | 2 +- .../src/traits/project.rs | 4 ++-- .../src/traits/query/evaluate_obligation.rs | 2 +- 9 files changed, 21 insertions(+), 26 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index 02cf1a502f16e..9de96b7ba7760 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -611,7 +611,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( Err(terr) => { let mut diag = struct_span_code_err!( tcx.dcx(), - cause.span(), + cause.span, E0053, "method `{}` has an incompatible return type for trait", trait_m.name @@ -1169,7 +1169,7 @@ fn extract_spans_for_error_reporting<'tcx>( TypeError::ArgumentMutability(i) | TypeError::ArgumentSorts(ExpectedFound { .. }, i) => { (impl_args.nth(i).unwrap(), trait_args.and_then(|mut args| args.nth(i))) } - _ => (cause.span(), tcx.hir().span_if_local(trait_m.def_id)), + _ => (cause.span, tcx.hir().span_if_local(trait_m.def_id)), } } diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index f2f9c69e49f70..58210aaa0668e 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -612,7 +612,7 @@ pub fn check_function_signature<'tcx>( match err { TypeError::ArgumentMutability(i) | TypeError::ArgumentSorts(ExpectedFound { .. }, i) => args.nth(i).unwrap(), - _ => cause.span(), + _ => cause.span, } } diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 92c2a90605584..d6e5fab610ed6 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -2027,7 +2027,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } Err(_) => { span_bug!( - cause.span(), + cause.span, "subtyping remaining fields of type changing FRU failed: {target_ty} != {fru_ty}: {}::{}", variant.name, ident.name, diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs index 96784fcb61b2c..f2b55d3aa4e1b 100644 --- a/compiler/rustc_hir_typeck/src/method/confirm.rs +++ b/compiler/rustc_hir_typeck/src/method/confirm.rs @@ -550,7 +550,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { // This has/will have errored in wfcheck, which we cannot depend on from here, as typeck on functions // may run before wfcheck if the function is used in const eval. self.dcx().span_delayed_bug( - cause.span(), + cause.span, format!("{self_ty} was a subtype of {method_self_ty} but now is not?"), ); } diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index 7237a7014e874..40e5ec4595982 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -92,16 +92,6 @@ impl<'tcx> ObligationCause<'tcx> { ObligationCause { span, body_id: CRATE_DEF_ID, code: Default::default() } } - pub fn span(&self) -> Span { - match *self.code() { - ObligationCauseCode::MatchExpressionArm(box MatchExpressionArmCause { - arm_span, - .. - }) => arm_span, - _ => self.span, - } - } - #[inline] pub fn code(&self) -> &ObligationCauseCode<'tcx> { &self.code @@ -517,12 +507,17 @@ pub struct MatchExpressionArmCause<'tcx> { pub prior_arm_block_id: Option, pub prior_arm_ty: Ty<'tcx>, pub prior_arm_span: Span, + /// Span of the scrutinee of the match (the matched value). pub scrut_span: Span, + /// Source of the match, i.e. `match` or a desugaring. pub source: hir::MatchSource, - // Span of the *whole* match expr + /// Span of the *whole* match expr. pub expr_span: Span, + /// Spans of the previous arms except for those that diverge (i.e. evaluate to `!`). + /// + /// These are used for pointing out errors that may affect several arms. pub prior_non_diverging_arms: Vec, - // Is the expectation of this match expression an RPIT? + /// Is the expectation of this match expression an RPIT? pub tail_defines_return_position_impl_trait: Option, } diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs index 0cbb43b876387..574cf1e88b16b 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs @@ -392,7 +392,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { Some(ty) if expected == ty => { let source_map = self.tcx.sess.source_map(); err.span_suggestion( - source_map.end_point(cause.span()), + source_map.end_point(cause.span), "try removing this `?`", "", Applicability::MachineApplicable, @@ -431,7 +431,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { Some(ty) if expected == ty => { let source_map = self.tcx.sess.source_map(); err.span_suggestion( - source_map.end_point(cause.span()), + source_map.end_point(cause.span), "try removing this `?`", "", Applicability::MachineApplicable, @@ -1149,7 +1149,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { terr: TypeError<'tcx>, prefer_label: bool, ) { - let span = cause.span(); + let span = cause.span; // For some types of errors, expected-found does not make // sense, so just ignore the values we were given. @@ -1643,7 +1643,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { terr: TypeError<'tcx>, ) -> Vec { let mut suggestions = Vec::new(); - let span = trace.cause.span(); + let span = trace.cause.span; let values = self.resolve_vars_if_possible(trace.values); if let Some((expected, found)) = values.ty() { match (expected.kind(), found.kind()) { @@ -1793,7 +1793,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ) -> Diag<'a> { debug!("report_and_explain_type_error(trace={:?}, terr={:?})", trace, terr); - let span = trace.cause.span(); + let span = trace.cause.span; let failure_code = trace.cause.as_failure_code_diag( terr, span, diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_error.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_error.rs index 14c2bf19a9cf7..4398af76ab2c7 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_error.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_error.rs @@ -237,7 +237,7 @@ impl<'tcx> NiceRegionError<'_, 'tcx> { expected_args: GenericArgsRef<'tcx>, actual_args: GenericArgsRef<'tcx>, ) -> Diag<'tcx> { - let span = cause.span(); + let span = cause.span; let (leading_ellipsis, satisfy_span, where_span, dup_span, def_id) = if let ObligationCauseCode::WhereClause(def_id, span) diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 38722c0ff7c5c..0803dd74b89bb 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -1180,7 +1180,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( selcx.tcx(), selcx.tcx().require_lang_item( LangItem::Sized, - Some(obligation.cause.span()), + Some(obligation.cause.span), ), [self_ty], ), @@ -1600,7 +1600,7 @@ fn confirm_builtin_candidate<'cx, 'tcx>( // exist. Instead, `Pointee` should be a supertrait of `Sized`. let sized_predicate = ty::TraitRef::new( tcx, - tcx.require_lang_item(LangItem::Sized, Some(obligation.cause.span())), + tcx.require_lang_item(LangItem::Sized, Some(obligation.cause.span)), [self_ty], ); obligations.push(obligation.with(tcx, sized_predicate)); diff --git a/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs index 76017299f2c08..bb44645a4ce1c 100644 --- a/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs +++ b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs @@ -90,7 +90,7 @@ impl<'tcx> InferCtxt<'tcx> { assert!(!self.intercrate); let c_pred = self.canonicalize_query(param_env.and(obligation.predicate), &mut _orig_values); - self.tcx.at(obligation.cause.span()).evaluate_obligation(c_pred) + self.tcx.at(obligation.cause.span).evaluate_obligation(c_pred) } }