Skip to content

Commit 8a3f712

Browse files
committed
Refactor FulfillmentError to track less data
Move the information about pointing at the call argument expression in an unmet obligation span from the `FulfillmentError` to a new `ObligationCauseCode`.
1 parent 284a8a9 commit 8a3f712

File tree

11 files changed

+86
-57
lines changed

11 files changed

+86
-57
lines changed

compiler/rustc_borrowck/src/type_check/mod.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1998,7 +1998,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
19981998
&obligation,
19991999
&traits::SelectionError::Unimplemented,
20002000
false,
2001-
false,
20022001
);
20032002
}
20042003
}

compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,13 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
2929
SubregionOrigin::Subtype(box TypeTrace { ref cause, .. }) => cause,
3030
_ => return None,
3131
};
32-
let (parent, impl_def_id) = match &cause.code {
32+
// If we added a "points at argument expression" obligation, we remove it here, we care
33+
// about the original obligation only.
34+
let code = match &cause.code {
35+
ObligationCauseCode::FunctionArgumentObligation { parent_code, .. } => &*parent_code,
36+
_ => &cause.code,
37+
};
38+
let (parent, impl_def_id) = match code {
3339
ObligationCauseCode::MatchImpl(parent, impl_def_id) => (parent, impl_def_id),
3440
_ => return None,
3541
};

compiler/rustc_infer/src/traits/mod.rs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -66,10 +66,6 @@ pub type Selection<'tcx> = ImplSource<'tcx, PredicateObligation<'tcx>>;
6666
pub struct FulfillmentError<'tcx> {
6767
pub obligation: PredicateObligation<'tcx>,
6868
pub code: FulfillmentErrorCode<'tcx>,
69-
/// Diagnostics only: we opportunistically change the `code.span` when we encounter an
70-
/// obligation error caused by a call argument. When this is the case, we also signal that in
71-
/// this field to ensure accuracy of suggestions.
72-
pub points_at_arg_span: bool,
7369
/// Diagnostics only: the 'root' obligation which resulted in
7470
/// the failure to process `obligation`. This is the obligation
7571
/// that was initially passed to `register_predicate_obligation`
@@ -128,7 +124,7 @@ impl<'tcx> FulfillmentError<'tcx> {
128124
code: FulfillmentErrorCode<'tcx>,
129125
root_obligation: PredicateObligation<'tcx>,
130126
) -> FulfillmentError<'tcx> {
131-
FulfillmentError { obligation, code, points_at_arg_span: false, root_obligation }
127+
FulfillmentError { obligation, code, root_obligation }
132128
}
133129
}
134130

compiler/rustc_middle/src/traits/mod.rs

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,15 @@ pub enum ObligationCauseCode<'tcx> {
253253

254254
DerivedObligation(DerivedObligationCause<'tcx>),
255255

256+
FunctionArgumentObligation {
257+
/// The node of the relevant argument in the function call.
258+
arg_hir_id: hir::HirId,
259+
/// The node of the function call.
260+
call_hir_id: hir::HirId,
261+
/// The obligation introduced by this argument.
262+
parent_code: Lrc<ObligationCauseCode<'tcx>>,
263+
},
264+
256265
/// Error derived when matching traits/impls; see ObligationCause for more details
257266
CompareImplConstObligation,
258267

@@ -368,11 +377,12 @@ impl ObligationCauseCode<'_> {
368377
// Return the base obligation, ignoring derived obligations.
369378
pub fn peel_derives(&self) -> &Self {
370379
let mut base_cause = self;
371-
while let BuiltinDerivedObligation(cause)
372-
| ImplDerivedObligation(cause)
373-
| DerivedObligation(cause) = base_cause
380+
while let BuiltinDerivedObligation(DerivedObligationCause { parent_code, .. })
381+
| ImplDerivedObligation(DerivedObligationCause { parent_code, .. })
382+
| DerivedObligation(DerivedObligationCause { parent_code, .. })
383+
| FunctionArgumentObligation { parent_code, .. } = base_cause
374384
{
375-
base_cause = &cause.parent_code;
385+
base_cause = &parent_code;
376386
}
377387
base_cause
378388
}

compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,6 @@ impl TraitEngine<'tcx> for FulfillmentContext<'tcx> {
5757
.map(|obligation| FulfillmentError {
5858
obligation: obligation.clone(),
5959
code: FulfillmentErrorCode::CodeAmbiguity,
60-
points_at_arg_span: false,
6160
// FIXME - does Chalk have a notation of 'root obligation'?
6261
// This is just for diagnostics, so it's okay if this is wrong
6362
root_obligation: obligation.clone(),
@@ -112,7 +111,6 @@ impl TraitEngine<'tcx> for FulfillmentContext<'tcx> {
112111
code: FulfillmentErrorCode::CodeSelectionError(
113112
SelectionError::Unimplemented,
114113
),
115-
points_at_arg_span: false,
116114
// FIXME - does Chalk have a notation of 'root obligation'?
117115
// This is just for diagnostics, so it's okay if this is wrong
118116
root_obligation: obligation,
@@ -129,7 +127,6 @@ impl TraitEngine<'tcx> for FulfillmentContext<'tcx> {
129127
code: FulfillmentErrorCode::CodeSelectionError(
130128
SelectionError::Unimplemented,
131129
),
132-
points_at_arg_span: false,
133130
// FIXME - does Chalk have a notation of 'root obligation'?
134131
// This is just for diagnostics, so it's okay if this is wrong
135132
root_obligation: obligation,

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

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,6 @@ pub trait InferCtxtExt<'tcx> {
6666
root_obligation: &PredicateObligation<'tcx>,
6767
error: &SelectionError<'tcx>,
6868
fallback_has_occurred: bool,
69-
points_at_arg: bool,
7069
);
7170

7271
/// Given some node representing a fn-like thing in the HIR map,
@@ -237,7 +236,6 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
237236
root_obligation: &PredicateObligation<'tcx>,
238237
error: &SelectionError<'tcx>,
239238
fallback_has_occurred: bool,
240-
points_at_arg: bool,
241239
) {
242240
let tcx = self.tcx;
243241
let mut span = obligation.cause.span;
@@ -387,7 +385,6 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
387385
&obligation,
388386
&mut err,
389387
&trait_ref,
390-
points_at_arg,
391388
have_alt_message,
392389
) {
393390
self.note_obligation_cause(&mut err, &obligation);
@@ -430,8 +427,8 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
430427
err.span_label(enclosing_scope_span, s.as_str());
431428
}
432429

433-
self.suggest_dereferences(&obligation, &mut err, trait_ref, points_at_arg);
434-
self.suggest_fn_call(&obligation, &mut err, trait_ref, points_at_arg);
430+
self.suggest_dereferences(&obligation, &mut err, trait_ref);
431+
self.suggest_fn_call(&obligation, &mut err, trait_ref);
435432
self.suggest_remove_reference(&obligation, &mut err, trait_ref);
436433
self.suggest_semicolon_removal(&obligation, &mut err, span, trait_ref);
437434
self.note_version_mismatch(&mut err, &trait_ref);
@@ -500,12 +497,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
500497
// Changing mutability doesn't make a difference to whether we have
501498
// an `Unsize` impl (Fixes ICE in #71036)
502499
if !is_unsize {
503-
self.suggest_change_mut(
504-
&obligation,
505-
&mut err,
506-
trait_ref,
507-
points_at_arg,
508-
);
500+
self.suggest_change_mut(&obligation, &mut err, trait_ref);
509501
}
510502

511503
// If this error is due to `!: Trait` not implemented but `(): Trait` is
@@ -1214,7 +1206,6 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> {
12141206
&error.root_obligation,
12151207
selection_error,
12161208
fallback_has_occurred,
1217-
error.points_at_arg_span,
12181209
);
12191210
}
12201211
FulfillmentErrorCode::CodeProjectionError(ref e) => {

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

Lines changed: 40 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,6 @@ pub trait InferCtxtExt<'tcx> {
5454
obligation: &PredicateObligation<'tcx>,
5555
err: &mut DiagnosticBuilder<'tcx>,
5656
trait_ref: ty::PolyTraitRef<'tcx>,
57-
points_at_arg: bool,
5857
);
5958

6059
fn get_closure_name(
@@ -69,15 +68,13 @@ pub trait InferCtxtExt<'tcx> {
6968
obligation: &PredicateObligation<'tcx>,
7069
err: &mut DiagnosticBuilder<'_>,
7170
trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
72-
points_at_arg: bool,
7371
);
7472

7573
fn suggest_add_reference_to_arg(
7674
&self,
7775
obligation: &PredicateObligation<'tcx>,
7876
err: &mut DiagnosticBuilder<'_>,
7977
trait_ref: &ty::Binder<'tcx, ty::TraitRef<'tcx>>,
80-
points_at_arg: bool,
8178
has_custom_message: bool,
8279
) -> bool;
8380

@@ -93,7 +90,6 @@ pub trait InferCtxtExt<'tcx> {
9390
obligation: &PredicateObligation<'tcx>,
9491
err: &mut DiagnosticBuilder<'_>,
9592
trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
96-
points_at_arg: bool,
9793
);
9894

9995
fn suggest_semicolon_removal(
@@ -490,16 +486,19 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
490486
obligation: &PredicateObligation<'tcx>,
491487
err: &mut DiagnosticBuilder<'tcx>,
492488
trait_ref: ty::PolyTraitRef<'tcx>,
493-
points_at_arg: bool,
494489
) {
495490
// It only make sense when suggesting dereferences for arguments
496-
if !points_at_arg {
491+
let code = if let ObligationCauseCode::FunctionArgumentObligation { parent_code, .. } =
492+
&obligation.cause.code
493+
{
494+
std::rc::Rc::clone(parent_code)
495+
} else {
497496
return;
498-
}
497+
};
499498
let param_env = obligation.param_env;
500499
let body_id = obligation.cause.body_id;
501500
let span = obligation.cause.span;
502-
let real_trait_ref = match &obligation.cause.code {
501+
let real_trait_ref = match &*code {
503502
ObligationCauseCode::ImplDerivedObligation(cause)
504503
| ObligationCauseCode::DerivedObligation(cause)
505504
| ObligationCauseCode::BuiltinDerivedObligation(cause) => cause.parent_trait_ref,
@@ -584,7 +583,6 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
584583
obligation: &PredicateObligation<'tcx>,
585584
err: &mut DiagnosticBuilder<'_>,
586585
trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
587-
points_at_arg: bool,
588586
) {
589587
let self_ty = match trait_ref.self_ty().no_bound_vars() {
590588
None => return,
@@ -656,11 +654,11 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
656654
}
657655
_ => return,
658656
};
659-
if points_at_arg {
657+
if matches!(obligation.cause.code, ObligationCauseCode::FunctionArgumentObligation { .. }) {
660658
// When the obligation error has been ensured to have been caused by
661659
// an argument, the `obligation.cause.span` points at the expression
662-
// of the argument, so we can provide a suggestion. This is signaled
663-
// by `points_at_arg`. Otherwise, we give a more general note.
660+
// of the argument, so we can provide a suggestion. Otherwise, we give
661+
// a more general note.
664662
err.span_suggestion_verbose(
665663
obligation.cause.span.shrink_to_hi(),
666664
&msg,
@@ -677,7 +675,6 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
677675
obligation: &PredicateObligation<'tcx>,
678676
err: &mut DiagnosticBuilder<'_>,
679677
trait_ref: &ty::Binder<'tcx, ty::TraitRef<'tcx>>,
680-
points_at_arg: bool,
681678
has_custom_message: bool,
682679
) -> bool {
683680
let span = obligation.cause.span;
@@ -686,9 +683,14 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
686683
ExpnKind::Desugaring(DesugaringKind::ForLoop(ForLoopLoc::IntoIter))
687684
);
688685

689-
if !points_at_arg && !points_at_for_iter {
690-
return false;
691-
}
686+
let code =
687+
if let (ObligationCauseCode::FunctionArgumentObligation { parent_code, .. }, false) =
688+
(&obligation.cause.code, points_at_for_iter)
689+
{
690+
std::rc::Rc::clone(parent_code)
691+
} else {
692+
return false;
693+
};
692694

693695
// List of traits for which it would be nonsensical to suggest borrowing.
694696
// For instance, immutable references are always Copy, so suggesting to
@@ -787,7 +789,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
787789
return false;
788790
};
789791

790-
if let ObligationCauseCode::ImplDerivedObligation(obligation) = &obligation.cause.code {
792+
if let ObligationCauseCode::ImplDerivedObligation(obligation) = &*code {
791793
let expected_trait_ref = obligation.parent_trait_ref.skip_binder();
792794
let new_imm_trait_ref =
793795
ty::TraitRef::new(obligation.parent_trait_ref.def_id(), imm_substs);
@@ -799,7 +801,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
799801
return try_borrowing(new_mut_trait_ref, expected_trait_ref, true, &[]);
800802
}
801803
} else if let ObligationCauseCode::BindingObligation(_, _)
802-
| ObligationCauseCode::ItemObligation(_) = &obligation.cause.code
804+
| ObligationCauseCode::ItemObligation(_) = &*code
803805
{
804806
if try_borrowing(
805807
ty::TraitRef::new(trait_ref.def_id, imm_substs),
@@ -891,8 +893,12 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
891893
obligation: &PredicateObligation<'tcx>,
892894
err: &mut DiagnosticBuilder<'_>,
893895
trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
894-
points_at_arg: bool,
895896
) {
897+
let points_at_arg = matches!(
898+
obligation.cause.code,
899+
ObligationCauseCode::FunctionArgumentObligation { .. },
900+
);
901+
896902
let span = obligation.cause.span;
897903
if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
898904
let refs_number =
@@ -2289,6 +2295,21 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
22892295
)
22902296
});
22912297
}
2298+
ObligationCauseCode::FunctionArgumentObligation {
2299+
arg_hir_id: _,
2300+
call_hir_id: _,
2301+
ref parent_code,
2302+
} => {
2303+
ensure_sufficient_stack(|| {
2304+
self.note_obligation_cause_code(
2305+
err,
2306+
predicate,
2307+
&parent_code,
2308+
obligated_types,
2309+
seen_requirements,
2310+
)
2311+
});
2312+
}
22922313
ObligationCauseCode::CompareImplMethodObligation {
22932314
item_name,
22942315
trait_item_def_id,

compiler/rustc_typeck/src/check/coercion.rs

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -707,13 +707,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
707707

708708
// Object safety violations or miscellaneous.
709709
Err(err) => {
710-
self.report_selection_error(
711-
obligation.clone(),
712-
&obligation,
713-
&err,
714-
false,
715-
false,
716-
);
710+
self.report_selection_error(obligation.clone(), &obligation, &err, false);
717711
// Treat this like an obligation and follow through
718712
// with the unsizing - the lack of a coercion should
719713
// be silent, as it causes a type mismatch later.

compiler/rustc_typeck/src/check/fn_ctxt/checks.rs

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use crate::check::{
99
};
1010

1111
use rustc_ast as ast;
12+
use rustc_data_structures::sync::Lrc;
1213
use rustc_errors::{Applicability, DiagnosticBuilder, DiagnosticId};
1314
use rustc_hir as hir;
1415
use rustc_hir::def::{CtorOf, DefKind, Res};
@@ -324,6 +325,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
324325
self.point_at_arg_instead_of_call_if_possible(
325326
errors,
326327
&final_arg_types[..],
328+
expr,
327329
sp,
328330
&args,
329331
);
@@ -391,7 +393,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
391393
) {
392394
for error in errors {
393395
error.obligation.cause.make_mut().span = arg.span;
394-
error.points_at_arg_span = true;
396+
let code = error.obligation.cause.code.clone();
397+
error.obligation.cause.make_mut().code =
398+
ObligationCauseCode::FunctionArgumentObligation {
399+
arg_hir_id: arg.hir_id,
400+
call_hir_id: expr.hir_id,
401+
parent_code: Lrc::new(code),
402+
};
395403
}
396404
}
397405
},
@@ -937,6 +945,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
937945
&self,
938946
errors: &mut Vec<traits::FulfillmentError<'tcx>>,
939947
final_arg_types: &[(usize, Ty<'tcx>, Ty<'tcx>)],
948+
expr: &'tcx hir::Expr<'tcx>,
940949
call_sp: Span,
941950
args: &'tcx [hir::Expr<'tcx>],
942951
) {
@@ -986,7 +995,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
986995
// We make sure that only *one* argument matches the obligation failure
987996
// and we assign the obligation's span to its expression's.
988997
error.obligation.cause.make_mut().span = args[ref_in].span;
989-
error.points_at_arg_span = true;
998+
let code = error.obligation.cause.code.clone();
999+
error.obligation.cause.make_mut().code =
1000+
ObligationCauseCode::FunctionArgumentObligation {
1001+
arg_hir_id: args[ref_in].hir_id,
1002+
call_hir_id: expr.hir_id,
1003+
parent_code: Lrc::new(code),
1004+
};
9901005
}
9911006
}
9921007
}

0 commit comments

Comments
 (0)