Skip to content

Commit f2465f8

Browse files
committed
Use trait solver to answer questions instead of manually writing a trait solver
1 parent 9de6b70 commit f2465f8

File tree

1 file changed

+22
-79
lines changed

1 file changed

+22
-79
lines changed

compiler/rustc_borrowck/src/diagnostics/region_errors.rs

+22-79
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ use rustc_infer::infer::{
2020
};
2121
use rustc_middle::hir::place::PlaceBase;
2222
use rustc_middle::mir::{ConstraintCategory, ReturnConstraint};
23-
use rustc_middle::traits::ObligationCause;
2423
use rustc_middle::ty::GenericArgs;
2524
use rustc_middle::ty::TypeVisitor;
2625
use rustc_middle::ty::{self, RegionVid, Ty};
@@ -29,8 +28,7 @@ use rustc_span::symbol::{kw, Ident};
2928
use rustc_span::Span;
3029
use rustc_trait_selection::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
3130
use rustc_trait_selection::infer::InferCtxtExt;
32-
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
33-
use rustc_trait_selection::traits::Obligation;
31+
use rustc_trait_selection::traits::{Obligation, ObligationCtxt};
3432

3533
use crate::borrowck_errors;
3634
use crate::session_diagnostics::{
@@ -1140,16 +1138,6 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
11401138
return;
11411139
};
11421140

1143-
// Get the arguments for the found method, only specifying that `Self` is the receiver type.
1144-
let args = GenericArgs::for_item(tcx, method, |param, _| {
1145-
if param.index == 0 {
1146-
possible_rcvr_ty.into()
1147-
} else {
1148-
self.infcx.var_for_def(expr.span, param)
1149-
}
1150-
});
1151-
1152-
let preds = tcx.predicates_of(method).instantiate(tcx, args);
11531141
// Get the type for the parameter corresponding to the argument the closure with the
11541142
// lifetime error we had.
11551143
let Some(input) = tcx
@@ -1163,75 +1151,30 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
11631151
return;
11641152
};
11651153

1166-
let cause = ObligationCause::misc(expr.span, self.mir_def_id());
1154+
trace!(?input);
11671155

1168-
enum CanSuggest {
1169-
Yes,
1170-
No,
1171-
Maybe,
1172-
}
1156+
let ty::Param(closure_param) = input.kind() else { return };
11731157

1174-
// Ok, the following is a HACK. We go over every predicate in the `fn` looking for the ones
1175-
// referencing the argument at hand, which is a closure with some bounds. In those, we
1176-
// re-verify that the closure we synthesized still matches the closure bound on the argument
1177-
// (this is likely unneeded) but *more importantly*, we look at the
1178-
// `<ClosureTy as FnOnce>::Output = ClosureRetTy` to confirm that the closure type we
1179-
// synthesized above *will* be accepted by the `where` bound corresponding to this
1180-
// argument. Put a different way, given `counts.iter().max_by_key(|(_, v)| v)`, we check
1181-
// that a new `ClosureTy` of `|(_, v)| { **v }` will be accepted by this method signature:
1182-
// ```
1183-
// fn max_by_key<B: Ord, F>(self, f: F) -> Option<Self::Item>
1184-
// where
1185-
// Self: Sized,
1186-
// F: FnMut(&Self::Item) -> B,
1187-
// ```
1188-
// Sadly, we can't use `ObligationCtxt` to do this, we need to modify things in place.
1189-
let mut can_suggest = CanSuggest::Maybe;
1190-
for pred in preds.predicates {
1191-
match tcx.liberate_late_bound_regions(self.mir_def_id().into(), pred.kind()) {
1192-
ty::ClauseKind::Trait(pred)
1193-
if self.infcx.can_eq(self.param_env, pred.self_ty(), *input)
1194-
&& [
1195-
tcx.lang_items().fn_trait(),
1196-
tcx.lang_items().fn_mut_trait(),
1197-
tcx.lang_items().fn_once_trait(),
1198-
]
1199-
.contains(&Some(pred.def_id())) =>
1200-
{
1201-
// This predicate is an `Fn*` trait and corresponds to the argument with the
1202-
// closure that failed the lifetime check. We verify that the arguments will
1203-
// continue to match (which didn't change, so they should, and this be a no-op).
1204-
let pred = pred.with_self_ty(tcx, closure_ty);
1205-
let o = Obligation::new(tcx, cause.clone(), self.param_env, pred);
1206-
if !self.infcx.predicate_may_hold(&o) {
1207-
// The closure we have doesn't have the right arguments for the trait bound
1208-
can_suggest = CanSuggest::No;
1209-
} else if let CanSuggest::Maybe = can_suggest {
1210-
// The closure has the right arguments
1211-
can_suggest = CanSuggest::Yes;
1212-
}
1213-
}
1214-
ty::ClauseKind::Projection(proj)
1215-
if self.infcx.can_eq(self.param_env, proj.projection_ty.self_ty(), *input)
1216-
&& tcx.lang_items().fn_once_output() == Some(proj.projection_ty.def_id) =>
1217-
{
1218-
// Verify that `<[closure@...] as FnOnce>::Output` matches the expected
1219-
// `Output` from the trait bound on the function called with the `[closure@...]`
1220-
// as argument.
1221-
let proj = proj.with_self_ty(tcx, closure_ty);
1222-
let o = Obligation::new(tcx, cause.clone(), self.param_env, proj);
1223-
if !self.infcx.predicate_may_hold(&o) {
1224-
// Return type doesn't match.
1225-
can_suggest = CanSuggest::No;
1226-
} else if let CanSuggest::Maybe = can_suggest {
1227-
// Return type matches, we can suggest dereferencing the closure's value.
1228-
can_suggest = CanSuggest::Yes;
1229-
}
1230-
}
1231-
_ => {}
1158+
// Get the arguments for the found method, only specifying that `Self` is the receiver type.
1159+
let args = GenericArgs::for_item(tcx, method, |param, _| {
1160+
if param.index == 0 {
1161+
possible_rcvr_ty.into()
1162+
} else if param.index == closure_param.index {
1163+
closure_ty.into()
1164+
} else {
1165+
self.infcx.var_for_def(expr.span, param)
12321166
}
1233-
}
1234-
if let CanSuggest::Yes = can_suggest {
1167+
});
1168+
1169+
let preds = tcx.predicates_of(method).instantiate(tcx, args);
1170+
1171+
let ocx = ObligationCtxt::new(&self.infcx);
1172+
ocx.register_obligations(preds.iter().map(|(pred, span)| {
1173+
trace!(?pred);
1174+
Obligation::misc(tcx, span, self.mir_def_id(), self.param_env, pred)
1175+
}));
1176+
1177+
if ocx.select_all_or_error().is_empty() {
12351178
diag.span_suggestion_verbose(
12361179
value.span.shrink_to_lo(),
12371180
"dereference the return value",

0 commit comments

Comments
 (0)