Skip to content

Commit 4d7e014

Browse files
committed
Clean fix for rust-lang#96223
- Modified `InferCtxt::mk_trait_obligation_with_new_self_ty` to take as argument a `Binder<(TraitPredicate, Ty)>` instead of a `Binder<TraitPredicate>` and a separate `Ty` with no bound vars. - Modified all call places to avoid calling `Binder::no_bounds_var` or `Binder::skip_binder` when it is not safe.
1 parent 3655175 commit 4d7e014

File tree

2 files changed

+121
-115
lines changed

2 files changed

+121
-115
lines changed

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

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1384,8 +1384,7 @@ trait InferCtxtPrivExt<'hir, 'tcx> {
13841384
fn mk_trait_obligation_with_new_self_ty(
13851385
&self,
13861386
param_env: ty::ParamEnv<'tcx>,
1387-
trait_ref: ty::PolyTraitPredicate<'tcx>,
1388-
new_self_ty: Ty<'tcx>,
1387+
trait_ref_and_ty: ty::Binder<'tcx, (ty::TraitPredicate<'tcx>, Ty<'tcx>)>,
13891388
) -> PredicateObligation<'tcx>;
13901389

13911390
fn maybe_report_ambiguity(
@@ -1923,14 +1922,11 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
19231922
fn mk_trait_obligation_with_new_self_ty(
19241923
&self,
19251924
param_env: ty::ParamEnv<'tcx>,
1926-
trait_ref: ty::PolyTraitPredicate<'tcx>,
1927-
new_self_ty: Ty<'tcx>,
1925+
trait_ref_and_ty: ty::Binder<'tcx, (ty::TraitPredicate<'tcx>, Ty<'tcx>)>,
19281926
) -> PredicateObligation<'tcx> {
1929-
assert!(!new_self_ty.has_escaping_bound_vars());
1930-
1931-
let trait_pred = trait_ref.map_bound_ref(|tr| ty::TraitPredicate {
1927+
let trait_pred = trait_ref_and_ty.map_bound_ref(|(tr, new_self_ty)| ty::TraitPredicate {
19321928
trait_ref: ty::TraitRef {
1933-
substs: self.tcx.mk_substs_trait(new_self_ty, &tr.trait_ref.substs[1..]),
1929+
substs: self.tcx.mk_substs_trait(*new_self_ty, &tr.trait_ref.substs[1..]),
19341930
..tr.trait_ref
19351931
},
19361932
..*tr

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

Lines changed: 117 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -637,8 +637,10 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
637637
if let Some(steps) = autoderef.find_map(|(ty, steps)| {
638638
// Re-add the `&`
639639
let ty = self.tcx.mk_ref(region, TypeAndMut { ty, mutbl });
640-
let obligation =
641-
self.mk_trait_obligation_with_new_self_ty(param_env, real_trait_pred, ty);
640+
let real_trait_pred_and_ty =
641+
real_trait_pred.map_bound(|inner_trait_pred| (inner_trait_pred, ty));
642+
let obligation = self
643+
.mk_trait_obligation_with_new_self_ty(param_env, real_trait_pred_and_ty);
642644
Some(steps).filter(|_| self.predicate_may_hold(&obligation))
643645
}) {
644646
if steps > 0 {
@@ -659,10 +661,11 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
659661
}
660662
} else if real_trait_pred != trait_pred {
661663
// This branch addresses #87437.
664+
let real_trait_pred_and_base_ty =
665+
real_trait_pred.map_bound(|inner_trait_pred| (inner_trait_pred, base_ty));
662666
let obligation = self.mk_trait_obligation_with_new_self_ty(
663667
param_env,
664-
real_trait_pred,
665-
base_ty,
668+
real_trait_pred_and_base_ty,
666669
);
667670
if self.predicate_may_hold(&obligation) {
668671
err.span_suggestion_verbose(
@@ -720,9 +723,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
720723
err: &mut Diagnostic,
721724
trait_pred: ty::PolyTraitPredicate<'tcx>,
722725
) -> bool {
723-
let Some(self_ty) = trait_pred.self_ty().no_bound_vars() else {
724-
return false;
725-
};
726+
let self_ty = trait_pred.self_ty().skip_binder();
726727

727728
let (def_id, output_ty, callable) = match *self_ty.kind() {
728729
ty::Closure(def_id, substs) => (def_id, substs.as_closure().sig().output(), "closure"),
@@ -731,14 +732,12 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
731732
};
732733
let msg = format!("use parentheses to call the {}", callable);
733734

734-
// `mk_trait_obligation_with_new_self_ty` only works for types with no escaping bound
735-
// variables, so bail out if we have any.
736-
let Some(output_ty) = output_ty.no_bound_vars() else {
737-
return false;
738-
};
735+
let output_ty = self.tcx.liberate_late_bound_regions(def_id, output_ty);
736+
737+
let trait_pred_and_self = trait_pred.map_bound(|trait_pred| (trait_pred, output_ty));
739738

740739
let new_obligation =
741-
self.mk_trait_obligation_with_new_self_ty(obligation.param_env, trait_pred, output_ty);
740+
self.mk_trait_obligation_with_new_self_ty(obligation.param_env, trait_pred_and_self);
742741

743742
match self.evaluate_obligation(&new_obligation) {
744743
Ok(
@@ -842,96 +841,102 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
842841
let param_env = obligation.param_env;
843842

844843
// Try to apply the original trait binding obligation by borrowing.
845-
let mut try_borrowing = |old_pred: ty::PolyTraitPredicate<'tcx>,
846-
blacklist: &[DefId]|
847-
-> bool {
848-
if blacklist.contains(&old_pred.def_id()) {
849-
return false;
850-
}
844+
let mut try_borrowing =
845+
|old_pred: ty::PolyTraitPredicate<'tcx>, blacklist: &[DefId]| -> bool {
846+
if blacklist.contains(&old_pred.def_id()) {
847+
return false;
848+
}
849+
// We map bounds to `&T` and `&mut T`
850+
let trait_pred_and_imm_ref = old_pred.map_bound(|trait_pred| {
851+
(
852+
trait_pred,
853+
self.tcx.mk_imm_ref(self.tcx.lifetimes.re_static, trait_pred.self_ty()),
854+
)
855+
});
856+
let trait_pred_and_mut_ref = old_pred.map_bound(|trait_pred| {
857+
(
858+
trait_pred,
859+
self.tcx.mk_mut_ref(self.tcx.lifetimes.re_static, trait_pred.self_ty()),
860+
)
861+
});
851862

852-
// This is a quick fix to resolve an ICE (#96223).
853-
// This change should probably be deeper.
854-
// As suggested by @jackh726, `mk_trait_obligation_with_new_self_ty` could take a `Binder<(TraitRef, Ty)>
855-
// instead of `Binder<Ty>` leading to some changes to its call places.
856-
let Some(orig_ty) = old_pred.self_ty().no_bound_vars() else {
857-
return false;
858-
};
859-
let mk_result = |new_ty| {
860-
let obligation =
861-
self.mk_trait_obligation_with_new_self_ty(param_env, old_pred, new_ty);
862-
self.predicate_must_hold_modulo_regions(&obligation)
863-
};
864-
let imm_result = mk_result(self.tcx.mk_imm_ref(self.tcx.lifetimes.re_static, orig_ty));
865-
let mut_result = mk_result(self.tcx.mk_mut_ref(self.tcx.lifetimes.re_static, orig_ty));
866-
867-
if imm_result || mut_result {
868-
if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
869-
// We have a very specific type of error, where just borrowing this argument
870-
// might solve the problem. In cases like this, the important part is the
871-
// original type obligation, not the last one that failed, which is arbitrary.
872-
// Because of this, we modify the error to refer to the original obligation and
873-
// return early in the caller.
874-
875-
let msg = format!(
876-
"the trait bound `{}: {}` is not satisfied",
877-
orig_ty,
878-
old_pred.print_modifiers_and_trait_path(),
879-
);
880-
if has_custom_message {
881-
err.note(&msg);
882-
} else {
883-
err.message =
884-
vec![(rustc_errors::DiagnosticMessage::Str(msg), Style::NoStyle)];
885-
}
886-
if snippet.starts_with('&') {
887-
// This is already a literal borrow and the obligation is failing
888-
// somewhere else in the obligation chain. Do not suggest non-sense.
889-
return false;
890-
}
891-
err.span_label(
892-
span,
893-
&format!(
894-
"expected an implementor of trait `{}`",
863+
let mk_result = |trait_pred_and_new_ty| {
864+
let obligation =
865+
self.mk_trait_obligation_with_new_self_ty(param_env, trait_pred_and_new_ty);
866+
self.predicate_must_hold_modulo_regions(&obligation)
867+
};
868+
let imm_result = mk_result(trait_pred_and_imm_ref);
869+
let mut_result = mk_result(trait_pred_and_mut_ref);
870+
871+
if imm_result || mut_result {
872+
if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
873+
// We have a very specific type of error, where just borrowing this argument
874+
// might solve the problem. In cases like this, the important part is the
875+
// original type obligation, not the last one that failed, which is arbitrary.
876+
// Because of this, we modify the error to refer to the original obligation and
877+
// return early in the caller.
878+
879+
let msg = format!(
880+
"the trait bound `{}: {}` is not satisfied",
881+
// Safe to skip binder here
882+
old_pred.self_ty().skip_binder(),
895883
old_pred.print_modifiers_and_trait_path(),
896-
),
897-
);
898-
899-
// This if is to prevent a special edge-case
900-
if matches!(
901-
span.ctxt().outer_expn_data().kind,
902-
ExpnKind::Root | ExpnKind::Desugaring(DesugaringKind::ForLoop)
903-
) {
904-
// We don't want a borrowing suggestion on the fields in structs,
905-
// ```
906-
// struct Foo {
907-
// the_foos: Vec<Foo>
908-
// }
909-
// ```
910-
911-
if imm_result && mut_result {
912-
err.span_suggestions(
913-
span.shrink_to_lo(),
914-
"consider borrowing here",
915-
["&".to_string(), "&mut ".to_string()].into_iter(),
916-
Applicability::MaybeIncorrect,
917-
);
884+
);
885+
if has_custom_message {
886+
err.note(&msg);
918887
} else {
919-
err.span_suggestion_verbose(
920-
span.shrink_to_lo(),
921-
&format!(
922-
"consider{} borrowing here",
923-
if mut_result { " mutably" } else { "" }
924-
),
925-
format!("&{}", if mut_result { "mut " } else { "" }),
926-
Applicability::MaybeIncorrect,
927-
);
888+
err.message =
889+
vec![(rustc_errors::DiagnosticMessage::Str(msg), Style::NoStyle)];
928890
}
891+
if snippet.starts_with('&') {
892+
// This is already a literal borrow and the obligation is failing
893+
// somewhere else in the obligation chain. Do not suggest non-sense.
894+
return false;
895+
}
896+
err.span_label(
897+
span,
898+
&format!(
899+
"expected an implementor of trait `{}`",
900+
old_pred.print_modifiers_and_trait_path(),
901+
),
902+
);
903+
904+
// This if is to prevent a special edge-case
905+
if matches!(
906+
span.ctxt().outer_expn_data().kind,
907+
ExpnKind::Root | ExpnKind::Desugaring(DesugaringKind::ForLoop)
908+
) {
909+
// We don't want a borrowing suggestion on the fields in structs,
910+
// ```
911+
// struct Foo {
912+
// the_foos: Vec<Foo>
913+
// }
914+
// ```
915+
916+
if imm_result && mut_result {
917+
err.span_suggestions(
918+
span.shrink_to_lo(),
919+
"consider borrowing here",
920+
["&".to_string(), "&mut ".to_string()].into_iter(),
921+
Applicability::MaybeIncorrect,
922+
);
923+
} else {
924+
err.span_suggestion_verbose(
925+
span.shrink_to_lo(),
926+
&format!(
927+
"consider{} borrowing here",
928+
if mut_result { " mutably" } else { "" }
929+
),
930+
format!("&{}", if mut_result { "mut " } else { "" }),
931+
Applicability::MaybeIncorrect,
932+
);
933+
}
934+
}
935+
return true;
929936
}
930-
return true;
931937
}
932-
}
933-
return false;
934-
};
938+
return false;
939+
};
935940

936941
if let ObligationCauseCode::ImplDerivedObligation(cause) = &*code {
937942
try_borrowing(cause.derived.parent_trait_pred, &[])
@@ -992,20 +997,22 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
992997
return false;
993998
}
994999

995-
let Some(mut suggested_ty) = trait_pred.self_ty().no_bound_vars() else {
996-
return false;
997-
};
1000+
// We skip binder here
1001+
let mut suggested_ty = trait_pred.self_ty().skip_binder();
9981002

9991003
for refs_remaining in 0..refs_number {
10001004
let ty::Ref(_, inner_ty, _) = suggested_ty.kind() else {
10011005
break;
10021006
};
10031007
suggested_ty = *inner_ty;
10041008

1009+
// We remap bounds here
1010+
let trait_pred_and_suggested_ty =
1011+
trait_pred.map_bound(|trait_pred| (trait_pred, suggested_ty));
1012+
10051013
let new_obligation = self.mk_trait_obligation_with_new_self_ty(
10061014
obligation.param_env,
1007-
trait_pred,
1008-
suggested_ty,
1015+
trait_pred_and_suggested_ty,
10091016
);
10101017

10111018
if self.predicate_may_hold(&new_obligation) {
@@ -1141,10 +1148,12 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
11411148
hir::Mutability::Not => self.tcx.mk_mut_ref(region, t_type),
11421149
};
11431150

1151+
let trait_pred_and_suggested_ty =
1152+
trait_pred.map_bound(|trait_pred| (trait_pred, suggested_ty));
1153+
11441154
let new_obligation = self.mk_trait_obligation_with_new_self_ty(
11451155
obligation.param_env,
1146-
trait_pred,
1147-
suggested_ty,
1156+
trait_pred_and_suggested_ty,
11481157
);
11491158
let suggested_ty_would_satisfy_obligation = self
11501159
.evaluate_obligation_no_overflow(&new_obligation)
@@ -1195,7 +1204,9 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
11951204
// Only suggest this if the expression behind the semicolon implements the predicate
11961205
&& let Some(typeck_results) = self.in_progress_typeck_results
11971206
&& let Some(ty) = typeck_results.borrow().expr_ty_opt(expr)
1198-
&& self.predicate_may_hold(&self.mk_trait_obligation_with_new_self_ty(obligation.param_env, trait_pred, ty))
1207+
&& self.predicate_may_hold(&self.mk_trait_obligation_with_new_self_ty(
1208+
obligation.param_env, trait_pred.map_bound(|trait_pred| (trait_pred, ty))
1209+
))
11991210
{
12001211
err.span_label(
12011212
expr.span,
@@ -2727,8 +2738,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
27272738
);
27282739
let try_obligation = self.mk_trait_obligation_with_new_self_ty(
27292740
obligation.param_env,
2730-
trait_pred,
2731-
normalized_ty.ty().unwrap(),
2741+
trait_pred.map_bound(|trait_pred| (trait_pred, normalized_ty.ty().unwrap())),
27322742
);
27332743
debug!("suggest_await_before_try: try_trait_obligation {:?}", try_obligation);
27342744
if self.predicate_may_hold(&try_obligation)

0 commit comments

Comments
 (0)