Skip to content

Commit c1a685b

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 a8cd964 commit c1a685b

File tree

1 file changed

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

1 file changed

+87
-83
lines changed

compiler/rustc_hir_typeck/src/method/probe.rs

+87-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,20 @@ impl AutorefOrPtrAdjustment {
162156
}
163157
}
164158

159+
/// Extra information required only for error reporting.
160+
struct PickDiagHints<'a, 'tcx> {
161+
/// Unstable candidates alongside the stable ones.
162+
unstable_candidates: Option<Vec<(Candidate<'tcx>, Symbol)>>,
163+
164+
/// Collects near misses when trait bounds for type parameters are unsatisfied and is only used
165+
/// for error reporting
166+
unsatisfied_predicates: &'a mut Vec<(
167+
ty::Predicate<'tcx>,
168+
Option<ty::Predicate<'tcx>>,
169+
Option<ObligationCause<'tcx>>,
170+
)>,
171+
}
172+
165173
#[derive(Debug, Clone)]
166174
pub(crate) struct Pick<'tcx> {
167175
pub item: ty::AssocItem,
@@ -665,7 +673,6 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
665673
private_candidates: Vec::new(),
666674
private_candidate: Cell::new(None),
667675
static_candidates: RefCell::new(Vec::new()),
668-
unsatisfied_predicates: RefCell::new(Vec::new()),
669676
scope_expr_id,
670677
is_suggestion,
671678
}
@@ -678,7 +685,6 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
678685
self.private_candidates.clear();
679686
self.private_candidate.set(None);
680687
self.static_candidates.borrow_mut().clear();
681-
self.unsatisfied_predicates.borrow_mut().clear();
682688
}
683689

684690
/// When we're looking up a method by path (UFCS), we relate the receiver
@@ -1054,7 +1060,9 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
10541060
fn pick(mut self) -> PickResult<'tcx> {
10551061
assert!(self.method_name.is_some());
10561062

1057-
if let Some(r) = self.pick_core() {
1063+
let mut unsatisfied_predicates = Vec::new();
1064+
1065+
if let Some(r) = self.pick_core(&mut unsatisfied_predicates) {
10581066
return r;
10591067
}
10601068

@@ -1074,7 +1082,6 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
10741082

10751083
let static_candidates = std::mem::take(self.static_candidates.get_mut());
10761084
let private_candidate = self.private_candidate.take();
1077-
let unsatisfied_predicates = std::mem::take(self.unsatisfied_predicates.get_mut());
10781085

10791086
// things failed, so lets look at all traits, for diagnostic purposes now:
10801087
self.reset();
@@ -1084,7 +1091,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
10841091

10851092
self.assemble_extension_candidates_for_all_traits();
10861093

1087-
let out_of_scope_traits = match self.pick_core() {
1094+
let out_of_scope_traits = match self.pick_core(&mut Vec::new()) {
10881095
Some(Ok(p)) => vec![p.item.container_id(self.tcx)],
10891096
Some(Err(MethodError::Ambiguity(v))) => v
10901097
.into_iter()
@@ -1119,14 +1126,40 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
11191126
}))
11201127
}
11211128

1122-
fn pick_core(&self) -> Option<PickResult<'tcx>> {
1129+
fn pick_core(
1130+
&self,
1131+
unsatisfied_predicates: &mut Vec<(
1132+
ty::Predicate<'tcx>,
1133+
Option<ty::Predicate<'tcx>>,
1134+
Option<ObligationCause<'tcx>>,
1135+
)>,
1136+
) -> Option<PickResult<'tcx>> {
11231137
// Pick stable methods only first, and consider unstable candidates if not found.
1124-
self.pick_all_method(Some(&mut vec![])).or_else(|| self.pick_all_method(None))
1138+
self.pick_all_method(&mut PickDiagHints {
1139+
// This first cycle, maintain a list of unstable candidates which
1140+
// we encounter. This will end up in the Pick for diagnostics.
1141+
unstable_candidates: Some(Vec::new()),
1142+
// Contribute to the list of unsatisfied predicates which may
1143+
// also be used for diagnostics.
1144+
unsatisfied_predicates,
1145+
})
1146+
.or_else(|| {
1147+
self.pick_all_method(&mut PickDiagHints {
1148+
// On the second search, don't provide a special list of unstable
1149+
// candidates. This indicates to the picking code that it should
1150+
// in fact include such unstable candidates in the actual
1151+
// search.
1152+
unstable_candidates: None,
1153+
// And there's no need to duplicate ourselves in the
1154+
// unsatisifed predicates list. Provide a throwaway list.
1155+
unsatisfied_predicates: &mut Vec::new(),
1156+
})
1157+
})
11251158
}
11261159

1127-
fn pick_all_method(
1160+
fn pick_all_method<'b>(
11281161
&self,
1129-
mut unstable_candidates: Option<&mut Vec<(Candidate<'tcx>, Symbol)>>,
1162+
pick_diag_hints: &mut PickDiagHints<'b, 'tcx>,
11301163
) -> Option<PickResult<'tcx>> {
11311164
self.steps
11321165
.iter()
@@ -1151,37 +1184,19 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
11511184
.unwrap_or_else(|_| {
11521185
span_bug!(self.span, "{:?} was applicable but now isn't?", step.self_ty)
11531186
});
1154-
self.pick_by_value_method(step, self_ty, unstable_candidates.as_deref_mut())
1155-
.or_else(|| {
1156-
self.pick_autorefd_method(
1157-
step,
1158-
self_ty,
1159-
hir::Mutability::Not,
1160-
unstable_candidates.as_deref_mut(),
1161-
)
1187+
self.pick_by_value_method(step, self_ty, pick_diag_hints).or_else(|| {
1188+
self.pick_autorefd_method(step, self_ty, hir::Mutability::Not, pick_diag_hints)
11621189
.or_else(|| {
11631190
self.pick_autorefd_method(
11641191
step,
11651192
self_ty,
11661193
hir::Mutability::Mut,
1167-
unstable_candidates.as_deref_mut(),
1168-
)
1169-
})
1170-
.or_else(|| {
1171-
self.pick_const_ptr_method(
1172-
step,
1173-
self_ty,
1174-
unstable_candidates.as_deref_mut(),
1175-
)
1176-
})
1177-
.or_else(|| {
1178-
self.pick_reborrow_pin_method(
1179-
step,
1180-
self_ty,
1181-
unstable_candidates.as_deref_mut(),
1194+
pick_diag_hints,
11821195
)
11831196
})
1184-
})
1197+
.or_else(|| self.pick_const_ptr_method(step, self_ty, pick_diag_hints))
1198+
.or_else(|| self.pick_reborrow_pin_method(step, self_ty, pick_diag_hints))
1199+
})
11851200
})
11861201
}
11871202

@@ -1191,17 +1206,17 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
11911206
/// we will potentially *reborrow* it to a shorter lifetime. This allows us
11921207
/// to transparently pass `&mut` pointers, in particular, without consuming
11931208
/// them for their entire lifetime.
1194-
fn pick_by_value_method(
1209+
fn pick_by_value_method<'b>(
11951210
&self,
11961211
step: &CandidateStep<'tcx>,
11971212
self_ty: Ty<'tcx>,
1198-
unstable_candidates: Option<&mut Vec<(Candidate<'tcx>, Symbol)>>,
1213+
pick_diag_hints: &mut PickDiagHints<'b, 'tcx>,
11991214
) -> Option<PickResult<'tcx>> {
12001215
if step.unsize {
12011216
return None;
12021217
}
12031218

1204-
self.pick_method(self_ty, unstable_candidates).map(|r| {
1219+
self.pick_method(self_ty, pick_diag_hints).map(|r| {
12051220
r.map(|mut pick| {
12061221
pick.autoderefs = step.autoderefs;
12071222

@@ -1234,20 +1249,20 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
12341249
})
12351250
}
12361251

1237-
fn pick_autorefd_method(
1252+
fn pick_autorefd_method<'b>(
12381253
&self,
12391254
step: &CandidateStep<'tcx>,
12401255
self_ty: Ty<'tcx>,
12411256
mutbl: hir::Mutability,
1242-
unstable_candidates: Option<&mut Vec<(Candidate<'tcx>, Symbol)>>,
1257+
pick_diag_hints: &mut PickDiagHints<'b, 'tcx>,
12431258
) -> Option<PickResult<'tcx>> {
12441259
let tcx = self.tcx;
12451260

12461261
// In general, during probing we erase regions.
12471262
let region = tcx.lifetimes.re_erased;
12481263

12491264
let autoref_ty = Ty::new_ref(tcx, region, self_ty, mutbl);
1250-
self.pick_method(autoref_ty, unstable_candidates).map(|r| {
1265+
self.pick_method(autoref_ty, pick_diag_hints).map(|r| {
12511266
r.map(|mut pick| {
12521267
pick.autoderefs = step.autoderefs;
12531268
pick.autoref_or_ptr_adjustment =
@@ -1258,12 +1273,12 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
12581273
}
12591274

12601275
/// Looks for applicable methods if we reborrow a `Pin<&mut T>` as a `Pin<&T>`.
1261-
#[instrument(level = "debug", skip(self, step, unstable_candidates))]
1262-
fn pick_reborrow_pin_method(
1276+
#[instrument(level = "debug", skip(self, step, pick_diag_hints))]
1277+
fn pick_reborrow_pin_method<'b>(
12631278
&self,
12641279
step: &CandidateStep<'tcx>,
12651280
self_ty: Ty<'tcx>,
1266-
unstable_candidates: Option<&mut Vec<(Candidate<'tcx>, Symbol)>>,
1281+
pick_diag_hints: &mut PickDiagHints<'b, 'tcx>,
12671282
) -> Option<PickResult<'tcx>> {
12681283
if !self.tcx.features().pin_ergonomics() {
12691284
return None;
@@ -1284,7 +1299,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
12841299

12851300
let region = self.tcx.lifetimes.re_erased;
12861301
let autopin_ty = Ty::new_pinned_ref(self.tcx, region, inner_ty, hir::Mutability::Not);
1287-
self.pick_method(autopin_ty, unstable_candidates).map(|r| {
1302+
self.pick_method(autopin_ty, pick_diag_hints).map(|r| {
12881303
r.map(|mut pick| {
12891304
pick.autoderefs = step.autoderefs;
12901305
pick.autoref_or_ptr_adjustment =
@@ -1297,11 +1312,11 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
12971312
/// If `self_ty` is `*mut T` then this picks `*const T` methods. The reason why we have a
12981313
/// special case for this is because going from `*mut T` to `*const T` with autoderefs and
12991314
/// autorefs would require dereferencing the pointer, which is not safe.
1300-
fn pick_const_ptr_method(
1315+
fn pick_const_ptr_method<'b>(
13011316
&self,
13021317
step: &CandidateStep<'tcx>,
13031318
self_ty: Ty<'tcx>,
1304-
unstable_candidates: Option<&mut Vec<(Candidate<'tcx>, Symbol)>>,
1319+
pick_diag_hints: &mut PickDiagHints<'b, 'tcx>,
13051320
) -> Option<PickResult<'tcx>> {
13061321
// Don't convert an unsized reference to ptr
13071322
if step.unsize {
@@ -1313,7 +1328,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
13131328
};
13141329

13151330
let const_ptr_ty = Ty::new_imm_ptr(self.tcx, ty);
1316-
self.pick_method(const_ptr_ty, unstable_candidates).map(|r| {
1331+
self.pick_method(const_ptr_ty, pick_diag_hints).map(|r| {
13171332
r.map(|mut pick| {
13181333
pick.autoderefs = step.autoderefs;
13191334
pick.autoref_or_ptr_adjustment = Some(AutorefOrPtrAdjustment::ToConstPtr);
@@ -1322,61 +1337,50 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
13221337
})
13231338
}
13241339

1325-
fn pick_method(
1340+
fn pick_method<'b>(
13261341
&self,
13271342
self_ty: Ty<'tcx>,
1328-
mut unstable_candidates: Option<&mut Vec<(Candidate<'tcx>, Symbol)>>,
1343+
pick_diag_hints: &mut PickDiagHints<'b, 'tcx>,
13291344
) -> Option<PickResult<'tcx>> {
13301345
debug!("pick_method(self_ty={})", self.ty_to_string(self_ty));
13311346

1332-
let mut possibly_unsatisfied_predicates = Vec::new();
1333-
13341347
for (kind, candidates) in
13351348
[("inherent", &self.inherent_candidates), ("extension", &self.extension_candidates)]
13361349
{
13371350
debug!("searching {} candidates", kind);
1338-
let res = self.consider_candidates(
1339-
self_ty,
1340-
candidates,
1341-
&mut possibly_unsatisfied_predicates,
1342-
unstable_candidates.as_deref_mut(),
1343-
);
1351+
let res = self.consider_candidates(self_ty, candidates, pick_diag_hints);
13441352
if let Some(pick) = res {
13451353
return Some(pick);
13461354
}
13471355
}
13481356

13491357
if self.private_candidate.get().is_none() {
13501358
if let Some(Ok(pick)) =
1351-
self.consider_candidates(self_ty, &self.private_candidates, &mut vec![], None)
1359+
self.consider_candidates(self_ty, &self.private_candidates, pick_diag_hints)
13521360
{
13531361
self.private_candidate.set(Some((pick.item.kind.as_def_kind(), pick.item.def_id)));
13541362
}
13551363
}
1356-
1357-
// `pick_method` may be called twice for the same self_ty if no stable methods
1358-
// match. Only extend once.
1359-
if unstable_candidates.is_some() {
1360-
self.unsatisfied_predicates.borrow_mut().extend(possibly_unsatisfied_predicates);
1361-
}
13621364
None
13631365
}
13641366

1365-
fn consider_candidates(
1367+
fn consider_candidates<'b>(
13661368
&self,
13671369
self_ty: Ty<'tcx>,
13681370
candidates: &[Candidate<'tcx>],
1369-
possibly_unsatisfied_predicates: &mut Vec<(
1370-
ty::Predicate<'tcx>,
1371-
Option<ty::Predicate<'tcx>>,
1372-
Option<ObligationCause<'tcx>>,
1373-
)>,
1374-
mut unstable_candidates: Option<&mut Vec<(Candidate<'tcx>, Symbol)>>,
1371+
pick_diag_hints: &mut PickDiagHints<'b, 'tcx>,
13751372
) -> Option<PickResult<'tcx>> {
13761373
let mut applicable_candidates: Vec<_> = candidates
13771374
.iter()
13781375
.map(|probe| {
1379-
(probe, self.consider_probe(self_ty, probe, possibly_unsatisfied_predicates))
1376+
(
1377+
probe,
1378+
self.consider_probe(
1379+
self_ty,
1380+
probe,
1381+
&mut pick_diag_hints.unsatisfied_predicates,
1382+
),
1383+
)
13801384
})
13811385
.filter(|&(_, status)| status != ProbeResult::NoMatch)
13821386
.collect();
@@ -1391,7 +1395,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
13911395
}
13921396
}
13931397

1394-
if let Some(uc) = &mut unstable_candidates {
1398+
if let Some(uc) = &mut pick_diag_hints.unstable_candidates {
13951399
applicable_candidates.retain(|&(candidate, _)| {
13961400
if let stability::EvalResult::Deny { feature, .. } =
13971401
self.tcx.eval_stability(candidate.item.def_id, None, self.span, None)
@@ -1409,10 +1413,10 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
14091413
}
14101414

14111415
applicable_candidates.pop().map(|(probe, status)| match status {
1412-
ProbeResult::Match => {
1413-
Ok(probe
1414-
.to_unadjusted_pick(self_ty, unstable_candidates.cloned().unwrap_or_default()))
1415-
}
1416+
ProbeResult::Match => Ok(probe.to_unadjusted_pick(
1417+
self_ty,
1418+
pick_diag_hints.unstable_candidates.clone().unwrap_or_default(),
1419+
)),
14161420
ProbeResult::NoMatch | ProbeResult::BadReturnType => Err(MethodError::BadReturnType),
14171421
})
14181422
}
@@ -1854,7 +1858,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
18541858
pcx.method_name = Some(method_name);
18551859
pcx.assemble_inherent_candidates();
18561860
pcx.assemble_extension_candidates_for_all_traits();
1857-
pcx.pick_core().and_then(|pick| pick.ok()).map(|pick| pick.item)
1861+
pcx.pick_core(&mut Vec::new()).and_then(|pick| pick.ok()).map(|pick| pick.item)
18581862
})
18591863
.collect();
18601864

0 commit comments

Comments
 (0)