Skip to content

Commit 1060a51

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.
1 parent 611200f commit 1060a51

File tree

1 file changed

+88
-83
lines changed
  • compiler/rustc_hir_typeck/src/method

1 file changed

+88
-83
lines changed

compiler/rustc_hir_typeck/src/method/probe.rs

+88-83
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(),
1150-
)
1151-
})
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(),
1177+
pick_diag_hints,
11641178
)
11651179
})
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

@@ -1173,17 +1189,17 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
11731189
/// we will potentially *reborrow* it to a shorter lifetime. This allows us
11741190
/// to transparently pass `&mut` pointers, in particular, without consuming
11751191
/// them for their entire lifetime.
1176-
fn pick_by_value_method(
1192+
fn pick_by_value_method<'b>(
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<'b, '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

@@ -1216,20 +1232,20 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
12161232
})
12171233
}
12181234

1219-
fn pick_autorefd_method(
1235+
fn pick_autorefd_method<'b>(
12201236
&self,
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<'b, '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))]
1244-
fn pick_reborrow_pin_method(
1259+
#[instrument(level = "debug", skip(self, step, pick_diag_hints))]
1260+
fn pick_reborrow_pin_method<'b>(
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<'b, '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 =
@@ -1279,11 +1295,11 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
12791295
/// If `self_ty` is `*mut T` then this picks `*const T` methods. The reason why we have a
12801296
/// special case for this is because going from `*mut T` to `*const T` with autoderefs and
12811297
/// autorefs would require dereferencing the pointer, which is not safe.
1282-
fn pick_const_ptr_method(
1298+
fn pick_const_ptr_method<'b>(
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<'b, '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);
@@ -1304,61 +1320,50 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
13041320
})
13051321
}
13061322

1307-
fn pick_method(
1323+
fn pick_method<'b>(
13081324
&self,
13091325
self_ty: Ty<'tcx>,
1310-
mut unstable_candidates: Option<&mut Vec<(Candidate<'tcx>, Symbol)>>,
1326+
pick_diag_hints: &mut PickDiagHints<'b, '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, pick_diag_hints)
13341343
{
13351344
self.private_candidate.set(Some((pick.item.kind.as_def_kind(), pick.item.def_id)));
13361345
}
13371346
}
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-
}
13441347
None
13451348
}
13461349

1347-
fn consider_candidates(
1350+
fn consider_candidates<'b>(
13481351
&self,
13491352
self_ty: Ty<'tcx>,
13501353
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)>>,
1354+
pick_diag_hints: &mut PickDiagHints<'b, 'tcx>,
13571355
) -> Option<PickResult<'tcx>> {
13581356
let mut applicable_candidates: Vec<_> = candidates
13591357
.iter()
13601358
.map(|probe| {
1361-
(probe, self.consider_probe(self_ty, probe, possibly_unsatisfied_predicates))
1359+
(
1360+
probe,
1361+
self.consider_probe(
1362+
self_ty,
1363+
probe,
1364+
&mut pick_diag_hints.unsatisfied_predicates,
1365+
),
1366+
)
13621367
})
13631368
.filter(|&(_, status)| status != ProbeResult::NoMatch)
13641369
.collect();
@@ -1373,7 +1378,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
13731378
}
13741379
}
13751380

1376-
if let Some(uc) = &mut unstable_candidates {
1381+
if let Some(uc) = &mut pick_diag_hints.unstable_candidates {
13771382
applicable_candidates.retain(|&(candidate, _)| {
13781383
if let stability::EvalResult::Deny { feature, .. } =
13791384
self.tcx.eval_stability(candidate.item.def_id, None, self.span, None)
@@ -1391,10 +1396,10 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
13911396
}
13921397

13931398
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-
}
1399+
ProbeResult::Match => Ok(probe.to_unadjusted_pick(
1400+
self_ty,
1401+
pick_diag_hints.unstable_candidates.clone().unwrap_or_default(),
1402+
)),
13981403
ProbeResult::NoMatch | ProbeResult::BadReturnType => Err(MethodError::BadReturnType),
13991404
})
14001405
}
@@ -1836,7 +1841,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
18361841
pcx.method_name = Some(method_name);
18371842
pcx.assemble_inherent_candidates();
18381843
pcx.assemble_extension_candidates_for_all_traits();
1839-
pcx.pick_core().and_then(|pick| pick.ok()).map(|pick| pick.item)
1844+
pcx.pick_core(&mut Vec::new()).and_then(|pick| pick.ok()).map(|pick| pick.item)
18401845
})
18411846
.collect();
18421847

0 commit comments

Comments
 (0)