Skip to content

Commit 7f7c964

Browse files
committed
Arbitrary self types v2: pick diags to stack.
This commit makes no (intentional) functional change. Previously, the picking process maintained two lists of extra information useful for diagnostics: * any unstable candidates which might have been picked * any unsatisfied predicates Previously, these were dealt with quite differently - the former list was passed around as a function parameter; the latter lived in a RefCell in the ProbeCtxt. With this change we increase consistency by keeping them together in a new PickDiagHints structure, passed as a parameter, with no need for interior mutability. The lifecycle of each of these lists remains fairly complex, so it's explained with new comments in pick_core. A further cleanup here would be to package the widely-used tuple (ty::Predicate<'tcx>, Option<ty::Predicate<'tcx>>, Option<ObligationCause<'tcx>>) into a named struct for UnsatisfiedPredicate. This seems worth doing but it turns out that this tuple is used in dozens of places, so if we're going to do this we should do it as a separate PR to avoid constant rebase trouble.
1 parent e75660d commit 7f7c964

File tree

1 file changed

+85
-77
lines changed
  • compiler/rustc_hir_typeck/src/method

1 file changed

+85
-77
lines changed

Diff for: compiler/rustc_hir_typeck/src/method/probe.rs

+85-77
Original file line numberDiff line numberDiff line change
@@ -79,12 +79,6 @@ pub(crate) struct ProbeContext<'a, 'tcx> {
7979
/// used for error reporting
8080
static_candidates: RefCell<Vec<CandidateSource>>,
8181

82-
/// Collects near misses when trait bounds for type parameters are unsatisfied and is only used
83-
/// for error reporting
84-
unsatisfied_predicates: RefCell<
85-
Vec<(ty::Predicate<'tcx>, Option<ty::Predicate<'tcx>>, Option<ObligationCause<'tcx>>)>,
86-
>,
87-
8882
scope_expr_id: HirId,
8983

9084
/// Is this probe being done for a diagnostic? This will skip some error reporting
@@ -162,6 +156,21 @@ impl AutorefOrPtrAdjustment {
162156
}
163157
}
164158

159+
/// Extra information required only for error reporting.
160+
#[derive(Debug)]
161+
struct PickDiagHints<'a, 'tcx> {
162+
/// Unstable candidates alongside the stable ones.
163+
unstable_candidates: Option<Vec<(Candidate<'tcx>, Symbol)>>,
164+
165+
/// Collects near misses when trait bounds for type parameters are unsatisfied and is only used
166+
/// for error reporting
167+
unsatisfied_predicates: &'a mut Vec<(
168+
ty::Predicate<'tcx>,
169+
Option<ty::Predicate<'tcx>>,
170+
Option<ObligationCause<'tcx>>,
171+
)>,
172+
}
173+
165174
#[derive(Debug, Clone)]
166175
pub(crate) struct Pick<'tcx> {
167176
pub item: ty::AssocItem,
@@ -647,7 +656,6 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
647656
private_candidates: Vec::new(),
648657
private_candidate: Cell::new(None),
649658
static_candidates: RefCell::new(Vec::new()),
650-
unsatisfied_predicates: RefCell::new(Vec::new()),
651659
scope_expr_id,
652660
is_suggestion,
653661
}
@@ -660,7 +668,6 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
660668
self.private_candidates.clear();
661669
self.private_candidate.set(None);
662670
self.static_candidates.borrow_mut().clear();
663-
self.unsatisfied_predicates.borrow_mut().clear();
664671
}
665672

666673
/// When we're looking up a method by path (UFCS), we relate the receiver
@@ -1036,7 +1043,9 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
10361043
fn pick(mut self) -> PickResult<'tcx> {
10371044
assert!(self.method_name.is_some());
10381045

1039-
if let Some(r) = self.pick_core() {
1046+
let mut unsatisfied_predicates = Vec::new();
1047+
1048+
if let Some(r) = self.pick_core(&mut unsatisfied_predicates) {
10401049
return r;
10411050
}
10421051

@@ -1056,7 +1065,6 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
10561065

10571066
let static_candidates = std::mem::take(self.static_candidates.get_mut());
10581067
let private_candidate = self.private_candidate.take();
1059-
let unsatisfied_predicates = std::mem::take(self.unsatisfied_predicates.get_mut());
10601068

10611069
// things failed, so lets look at all traits, for diagnostic purposes now:
10621070
self.reset();
@@ -1066,7 +1074,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
10661074

10671075
self.assemble_extension_candidates_for_all_traits();
10681076

1069-
let out_of_scope_traits = match self.pick_core() {
1077+
let out_of_scope_traits = match self.pick_core(&mut Vec::new()) {
10701078
Some(Ok(p)) => vec![p.item.container_id(self.tcx)],
10711079
Some(Err(MethodError::Ambiguity(v))) => v
10721080
.into_iter()
@@ -1101,14 +1109,40 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
11011109
}))
11021110
}
11031111

1104-
fn pick_core(&self) -> Option<PickResult<'tcx>> {
1112+
fn pick_core(
1113+
&self,
1114+
unsatisfied_predicates: &mut Vec<(
1115+
ty::Predicate<'tcx>,
1116+
Option<ty::Predicate<'tcx>>,
1117+
Option<ObligationCause<'tcx>>,
1118+
)>,
1119+
) -> Option<PickResult<'tcx>> {
11051120
// Pick stable methods only first, and consider unstable candidates if not found.
1106-
self.pick_all_method(Some(&mut vec![])).or_else(|| self.pick_all_method(None))
1121+
self.pick_all_method(&mut PickDiagHints {
1122+
// This first cycle, maintain a list of unstable candidates which
1123+
// we encounter. This will end up in the Pick for diagnostics.
1124+
unstable_candidates: Some(Vec::new()),
1125+
// Contribute to the list of unsatisfied predicates which may
1126+
// also be used for diagnostics.
1127+
unsatisfied_predicates,
1128+
})
1129+
.or_else(|| {
1130+
self.pick_all_method(&mut PickDiagHints {
1131+
// On the second search, don't provide a special list of unstable
1132+
// candidates. This indicates to the picking code that it should
1133+
// in fact include such unstable candidates in the actual
1134+
// search.
1135+
unstable_candidates: None,
1136+
// And there's no need to duplicate ourselves in the
1137+
// unsatisifed predicates list. Provide a throwaway list.
1138+
unsatisfied_predicates: &mut Vec::new(),
1139+
})
1140+
})
11071141
}
11081142

1109-
fn pick_all_method(
1143+
fn pick_all_method<'b>(
11101144
&self,
1111-
mut unstable_candidates: Option<&mut Vec<(Candidate<'tcx>, Symbol)>>,
1145+
pick_diag_hints: &mut PickDiagHints<'b, 'tcx>,
11121146
) -> Option<PickResult<'tcx>> {
11131147
self.steps
11141148
.iter()
@@ -1133,37 +1167,19 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
11331167
.unwrap_or_else(|_| {
11341168
span_bug!(self.span, "{:?} was applicable but now isn't?", step.self_ty)
11351169
});
1136-
self.pick_by_value_method(step, self_ty, unstable_candidates.as_deref_mut())
1137-
.or_else(|| {
1138-
self.pick_autorefd_method(
1139-
step,
1140-
self_ty,
1141-
hir::Mutability::Not,
1142-
unstable_candidates.as_deref_mut(),
1143-
)
1170+
self.pick_by_value_method(step, self_ty, pick_diag_hints).or_else(|| {
1171+
self.pick_autorefd_method(step, self_ty, hir::Mutability::Not, pick_diag_hints)
11441172
.or_else(|| {
11451173
self.pick_autorefd_method(
11461174
step,
11471175
self_ty,
11481176
hir::Mutability::Mut,
1149-
unstable_candidates.as_deref_mut(),
1177+
pick_diag_hints,
11501178
)
11511179
})
1152-
.or_else(|| {
1153-
self.pick_const_ptr_method(
1154-
step,
1155-
self_ty,
1156-
unstable_candidates.as_deref_mut(),
1157-
)
1158-
})
1159-
.or_else(|| {
1160-
self.pick_reborrow_pin_method(
1161-
step,
1162-
self_ty,
1163-
unstable_candidates.as_deref_mut(),
1164-
)
1165-
})
1166-
})
1180+
.or_else(|| self.pick_const_ptr_method(step, self_ty, pick_diag_hints))
1181+
.or_else(|| self.pick_reborrow_pin_method(step, self_ty, pick_diag_hints))
1182+
})
11671183
})
11681184
}
11691185

@@ -1177,13 +1193,13 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
11771193
&self,
11781194
step: &CandidateStep<'tcx>,
11791195
self_ty: Ty<'tcx>,
1180-
unstable_candidates: Option<&mut Vec<(Candidate<'tcx>, Symbol)>>,
1196+
pick_diag_hints: &mut PickDiagHints<'_, 'tcx>,
11811197
) -> Option<PickResult<'tcx>> {
11821198
if step.unsize {
11831199
return None;
11841200
}
11851201

1186-
self.pick_method(self_ty, unstable_candidates).map(|r| {
1202+
self.pick_method(self_ty, pick_diag_hints).map(|r| {
11871203
r.map(|mut pick| {
11881204
pick.autoderefs = step.autoderefs;
11891205

@@ -1221,15 +1237,15 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
12211237
step: &CandidateStep<'tcx>,
12221238
self_ty: Ty<'tcx>,
12231239
mutbl: hir::Mutability,
1224-
unstable_candidates: Option<&mut Vec<(Candidate<'tcx>, Symbol)>>,
1240+
pick_diag_hints: &mut PickDiagHints<'_, 'tcx>,
12251241
) -> Option<PickResult<'tcx>> {
12261242
let tcx = self.tcx;
12271243

12281244
// In general, during probing we erase regions.
12291245
let region = tcx.lifetimes.re_erased;
12301246

12311247
let autoref_ty = Ty::new_ref(tcx, region, self_ty, mutbl);
1232-
self.pick_method(autoref_ty, unstable_candidates).map(|r| {
1248+
self.pick_method(autoref_ty, pick_diag_hints).map(|r| {
12331249
r.map(|mut pick| {
12341250
pick.autoderefs = step.autoderefs;
12351251
pick.autoref_or_ptr_adjustment =
@@ -1240,12 +1256,12 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
12401256
}
12411257

12421258
/// Looks for applicable methods if we reborrow a `Pin<&mut T>` as a `Pin<&T>`.
1243-
#[instrument(level = "debug", skip(self, step, unstable_candidates))]
1259+
#[instrument(level = "debug", skip(self, step, pick_diag_hints))]
12441260
fn pick_reborrow_pin_method(
12451261
&self,
12461262
step: &CandidateStep<'tcx>,
12471263
self_ty: Ty<'tcx>,
1248-
unstable_candidates: Option<&mut Vec<(Candidate<'tcx>, Symbol)>>,
1264+
pick_diag_hints: &mut PickDiagHints<'_, 'tcx>,
12491265
) -> Option<PickResult<'tcx>> {
12501266
if !self.tcx.features().pin_ergonomics() {
12511267
return None;
@@ -1266,7 +1282,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
12661282

12671283
let region = self.tcx.lifetimes.re_erased;
12681284
let autopin_ty = Ty::new_pinned_ref(self.tcx, region, inner_ty, hir::Mutability::Not);
1269-
self.pick_method(autopin_ty, unstable_candidates).map(|r| {
1285+
self.pick_method(autopin_ty, pick_diag_hints).map(|r| {
12701286
r.map(|mut pick| {
12711287
pick.autoderefs = step.autoderefs;
12721288
pick.autoref_or_ptr_adjustment =
@@ -1283,7 +1299,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
12831299
&self,
12841300
step: &CandidateStep<'tcx>,
12851301
self_ty: Ty<'tcx>,
1286-
unstable_candidates: Option<&mut Vec<(Candidate<'tcx>, Symbol)>>,
1302+
pick_diag_hints: &mut PickDiagHints<'_, 'tcx>,
12871303
) -> Option<PickResult<'tcx>> {
12881304
// Don't convert an unsized reference to ptr
12891305
if step.unsize {
@@ -1295,7 +1311,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
12951311
};
12961312

12971313
let const_ptr_ty = Ty::new_imm_ptr(self.tcx, ty);
1298-
self.pick_method(const_ptr_ty, unstable_candidates).map(|r| {
1314+
self.pick_method(const_ptr_ty, pick_diag_hints).map(|r| {
12991315
r.map(|mut pick| {
13001316
pick.autoderefs = step.autoderefs;
13011317
pick.autoref_or_ptr_adjustment = Some(AutorefOrPtrAdjustment::ToConstPtr);
@@ -1307,58 +1323,50 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
13071323
fn pick_method(
13081324
&self,
13091325
self_ty: Ty<'tcx>,
1310-
mut unstable_candidates: Option<&mut Vec<(Candidate<'tcx>, Symbol)>>,
1326+
pick_diag_hints: &mut PickDiagHints<'_, 'tcx>,
13111327
) -> Option<PickResult<'tcx>> {
13121328
debug!("pick_method(self_ty={})", self.ty_to_string(self_ty));
13131329

1314-
let mut possibly_unsatisfied_predicates = Vec::new();
1315-
13161330
for (kind, candidates) in
13171331
[("inherent", &self.inherent_candidates), ("extension", &self.extension_candidates)]
13181332
{
13191333
debug!("searching {} candidates", kind);
1320-
let res = self.consider_candidates(
1321-
self_ty,
1322-
candidates,
1323-
&mut possibly_unsatisfied_predicates,
1324-
unstable_candidates.as_deref_mut(),
1325-
);
1334+
let res = self.consider_candidates(self_ty, candidates, pick_diag_hints);
13261335
if let Some(pick) = res {
13271336
return Some(pick);
13281337
}
13291338
}
13301339

13311340
if self.private_candidate.get().is_none() {
13321341
if let Some(Ok(pick)) =
1333-
self.consider_candidates(self_ty, &self.private_candidates, &mut vec![], None)
1342+
self.consider_candidates(self_ty, &self.private_candidates, &mut PickDiagHints {
1343+
unstable_candidates: None,
1344+
unsatisfied_predicates: &mut vec![],
1345+
})
13341346
{
13351347
self.private_candidate.set(Some((pick.item.kind.as_def_kind(), pick.item.def_id)));
13361348
}
13371349
}
1338-
1339-
// `pick_method` may be called twice for the same self_ty if no stable methods
1340-
// match. Only extend once.
1341-
if unstable_candidates.is_some() {
1342-
self.unsatisfied_predicates.borrow_mut().extend(possibly_unsatisfied_predicates);
1343-
}
13441350
None
13451351
}
13461352

13471353
fn consider_candidates(
13481354
&self,
13491355
self_ty: Ty<'tcx>,
13501356
candidates: &[Candidate<'tcx>],
1351-
possibly_unsatisfied_predicates: &mut Vec<(
1352-
ty::Predicate<'tcx>,
1353-
Option<ty::Predicate<'tcx>>,
1354-
Option<ObligationCause<'tcx>>,
1355-
)>,
1356-
mut unstable_candidates: Option<&mut Vec<(Candidate<'tcx>, Symbol)>>,
1357+
pick_diag_hints: &mut PickDiagHints<'_, 'tcx>,
13571358
) -> Option<PickResult<'tcx>> {
13581359
let mut applicable_candidates: Vec<_> = candidates
13591360
.iter()
13601361
.map(|probe| {
1361-
(probe, self.consider_probe(self_ty, probe, possibly_unsatisfied_predicates))
1362+
(
1363+
probe,
1364+
self.consider_probe(
1365+
self_ty,
1366+
probe,
1367+
&mut pick_diag_hints.unsatisfied_predicates,
1368+
),
1369+
)
13621370
})
13631371
.filter(|&(_, status)| status != ProbeResult::NoMatch)
13641372
.collect();
@@ -1373,7 +1381,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
13731381
}
13741382
}
13751383

1376-
if let Some(uc) = &mut unstable_candidates {
1384+
if let Some(uc) = &mut pick_diag_hints.unstable_candidates {
13771385
applicable_candidates.retain(|&(candidate, _)| {
13781386
if let stability::EvalResult::Deny { feature, .. } =
13791387
self.tcx.eval_stability(candidate.item.def_id, None, self.span, None)
@@ -1391,10 +1399,10 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
13911399
}
13921400

13931401
applicable_candidates.pop().map(|(probe, status)| match status {
1394-
ProbeResult::Match => {
1395-
Ok(probe
1396-
.to_unadjusted_pick(self_ty, unstable_candidates.cloned().unwrap_or_default()))
1397-
}
1402+
ProbeResult::Match => Ok(probe.to_unadjusted_pick(
1403+
self_ty,
1404+
pick_diag_hints.unstable_candidates.clone().unwrap_or_default(),
1405+
)),
13981406
ProbeResult::NoMatch | ProbeResult::BadReturnType => Err(MethodError::BadReturnType),
13991407
})
14001408
}
@@ -1859,7 +1867,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
18591867
pcx.method_name = Some(method_name);
18601868
pcx.assemble_inherent_candidates();
18611869
pcx.assemble_extension_candidates_for_all_traits();
1862-
pcx.pick_core().and_then(|pick| pick.ok()).map(|pick| pick.item)
1870+
pcx.pick_core(&mut Vec::new()).and_then(|pick| pick.ok()).map(|pick| pick.item)
18631871
})
18641872
.collect();
18651873

0 commit comments

Comments
 (0)