Skip to content

Commit 6a207f2

Browse files
committed
Try all stable candidates first before trying unstable ones
1 parent 9740050 commit 6a207f2

File tree

3 files changed

+105
-19
lines changed

3 files changed

+105
-19
lines changed

compiler/rustc_interface/src/tests.rs

+1
Original file line numberDiff line numberDiff line change
@@ -751,6 +751,7 @@ fn test_debugging_options_tracking_hash() {
751751
tracked!(panic_abort_tests, true);
752752
tracked!(panic_in_drop, PanicStrategy::Abort);
753753
tracked!(partially_uninit_const_threshold, Some(123));
754+
tracked!(pick_stable_methods_before_any_unstable, false);
754755
tracked!(plt, Some(true));
755756
tracked!(polonius, true);
756757
tracked!(precise_enum_drop_elaboration, false);

compiler/rustc_session/src/options.rs

+2
Original file line numberDiff line numberDiff line change
@@ -1233,6 +1233,8 @@ options! {
12331233
and set the maximum total size of a const allocation for which this is allowed (default: never)"),
12341234
perf_stats: bool = (false, parse_bool, [UNTRACKED],
12351235
"print some performance-related statistics (default: no)"),
1236+
pick_stable_methods_before_any_unstable: bool = (true, parse_bool, [TRACKED],
1237+
"try to pick stable methods first before picking any unstable methods (default: yes)"),
12361238
plt: Option<bool> = (None, parse_opt_bool, [TRACKED],
12371239
"whether to use the PLT when calling into shared libraries;
12381240
only has effect for PIC code on systems with ELF binaries

compiler/rustc_typeck/src/check/method/probe.rs

+102-19
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ impl<'a, 'tcx> Deref for ProbeContext<'a, 'tcx> {
9292
}
9393
}
9494

95-
#[derive(Debug)]
95+
#[derive(Debug, Clone)]
9696
struct Candidate<'tcx> {
9797
// Candidates are (I'm not quite sure, but they are mostly) basically
9898
// some metadata on top of a `ty::AssocItem` (without substs).
@@ -132,7 +132,7 @@ struct Candidate<'tcx> {
132132
import_ids: SmallVec<[LocalDefId; 1]>,
133133
}
134134

135-
#[derive(Debug)]
135+
#[derive(Debug, Clone)]
136136
enum CandidateKind<'tcx> {
137137
InherentImplCandidate(
138138
SubstsRef<'tcx>,
@@ -1102,13 +1102,37 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
11021102
}
11031103

11041104
fn pick_core(&mut self) -> Option<PickResult<'tcx>> {
1105-
let steps = self.steps.clone();
1105+
let mut unstable_candidates = Vec::new();
1106+
let pick = self.pick_all_method(Some(&mut unstable_candidates));
1107+
1108+
// In this case unstable picking is done by `pick_method`.
1109+
if !self.tcx.sess.opts.debugging_opts.pick_stable_methods_before_any_unstable {
1110+
return pick;
1111+
}
11061112

1107-
// find the first step that works
1113+
match pick {
1114+
// Emit a lint if there are unstable candidates alongside the stable ones.
1115+
//
1116+
// We suppress warning if we're picking the method only because it is a
1117+
// suggestion.
1118+
Some(Ok(ref p)) if !self.is_suggestion.0 && !unstable_candidates.is_empty() => {
1119+
self.emit_unstable_name_collision_hint(p, &unstable_candidates);
1120+
pick
1121+
}
1122+
Some(_) => pick,
1123+
None => self.pick_all_method(None),
1124+
}
1125+
}
1126+
1127+
fn pick_all_method(
1128+
&mut self,
1129+
mut unstable_candidates: Option<&mut Vec<(Candidate<'tcx>, Symbol)>>,
1130+
) -> Option<PickResult<'tcx>> {
1131+
let steps = self.steps.clone();
11081132
steps
11091133
.iter()
11101134
.filter(|step| {
1111-
debug!("pick_core: step={:?}", step);
1135+
debug!("pick_all_method: step={:?}", step);
11121136
// skip types that are from a type error or that would require dereferencing
11131137
// a raw pointer
11141138
!step.self_ty.references_error() && !step.from_unsafe_deref
@@ -1124,11 +1148,30 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
11241148
.unwrap_or_else(|_| {
11251149
span_bug!(self.span, "{:?} was applicable but now isn't?", step.self_ty)
11261150
});
1127-
self.pick_by_value_method(step, self_ty).or_else(|| {
1128-
self.pick_autorefd_method(step, self_ty, hir::Mutability::Not)
1129-
.or_else(|| self.pick_autorefd_method(step, self_ty, hir::Mutability::Mut))
1130-
.or_else(|| self.pick_const_ptr_method(step, self_ty))
1131-
})
1151+
self.pick_by_value_method(step, self_ty, unstable_candidates.as_deref_mut())
1152+
.or_else(|| {
1153+
self.pick_autorefd_method(
1154+
step,
1155+
self_ty,
1156+
hir::Mutability::Not,
1157+
unstable_candidates.as_deref_mut(),
1158+
)
1159+
.or_else(|| {
1160+
self.pick_autorefd_method(
1161+
step,
1162+
self_ty,
1163+
hir::Mutability::Mut,
1164+
unstable_candidates.as_deref_mut(),
1165+
)
1166+
})
1167+
.or_else(|| {
1168+
self.pick_const_ptr_method(
1169+
step,
1170+
self_ty,
1171+
unstable_candidates.as_deref_mut(),
1172+
)
1173+
})
1174+
})
11321175
})
11331176
.next()
11341177
}
@@ -1143,12 +1186,13 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
11431186
&mut self,
11441187
step: &CandidateStep<'tcx>,
11451188
self_ty: Ty<'tcx>,
1189+
unstable_candidates: Option<&mut Vec<(Candidate<'tcx>, Symbol)>>,
11461190
) -> Option<PickResult<'tcx>> {
11471191
if step.unsize {
11481192
return None;
11491193
}
11501194

1151-
self.pick_method(self_ty).map(|r| {
1195+
self.pick_method(self_ty, unstable_candidates).map(|r| {
11521196
r.map(|mut pick| {
11531197
pick.autoderefs = step.autoderefs;
11541198

@@ -1171,14 +1215,15 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
11711215
step: &CandidateStep<'tcx>,
11721216
self_ty: Ty<'tcx>,
11731217
mutbl: hir::Mutability,
1218+
unstable_candidates: Option<&mut Vec<(Candidate<'tcx>, Symbol)>>,
11741219
) -> Option<PickResult<'tcx>> {
11751220
let tcx = self.tcx;
11761221

11771222
// In general, during probing we erase regions.
11781223
let region = tcx.lifetimes.re_erased;
11791224

11801225
let autoref_ty = tcx.mk_ref(region, ty::TypeAndMut { ty: self_ty, mutbl });
1181-
self.pick_method(autoref_ty).map(|r| {
1226+
self.pick_method(autoref_ty, unstable_candidates).map(|r| {
11821227
r.map(|mut pick| {
11831228
pick.autoderefs = step.autoderefs;
11841229
pick.autoref_or_ptr_adjustment = Some(AutorefOrPtrAdjustment::Autoref {
@@ -1197,6 +1242,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
11971242
&mut self,
11981243
step: &CandidateStep<'tcx>,
11991244
self_ty: Ty<'tcx>,
1245+
unstable_candidates: Option<&mut Vec<(Candidate<'tcx>, Symbol)>>,
12001246
) -> Option<PickResult<'tcx>> {
12011247
// Don't convert an unsized reference to ptr
12021248
if step.unsize {
@@ -1210,7 +1256,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
12101256

12111257
let const_self_ty = ty::TypeAndMut { ty, mutbl: hir::Mutability::Not };
12121258
let const_ptr_ty = self.tcx.mk_ptr(const_self_ty);
1213-
self.pick_method(const_ptr_ty).map(|r| {
1259+
self.pick_method(const_ptr_ty, unstable_candidates).map(|r| {
12141260
r.map(|mut pick| {
12151261
pick.autoderefs = step.autoderefs;
12161262
pick.autoref_or_ptr_adjustment = Some(AutorefOrPtrAdjustment::ToConstPtr);
@@ -1219,8 +1265,8 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
12191265
})
12201266
}
12211267

1222-
fn pick_method(&mut self, self_ty: Ty<'tcx>) -> Option<PickResult<'tcx>> {
1223-
debug!("pick_method(self_ty={})", self.ty_to_string(self_ty));
1268+
fn pick_method_with_unstable(&mut self, self_ty: Ty<'tcx>) -> Option<PickResult<'tcx>> {
1269+
debug!("pick_method_with_unstable(self_ty={})", self.ty_to_string(self_ty));
12241270

12251271
let mut possibly_unsatisfied_predicates = Vec::new();
12261272
let mut unstable_candidates = Vec::new();
@@ -1252,7 +1298,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
12521298
debug!("searching unstable candidates");
12531299
let res = self.consider_candidates(
12541300
self_ty,
1255-
unstable_candidates.into_iter().map(|(c, _)| c),
1301+
unstable_candidates.iter().map(|(c, _)| c),
12561302
&mut possibly_unsatisfied_predicates,
12571303
None,
12581304
);
@@ -1262,6 +1308,42 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
12621308
res
12631309
}
12641310

1311+
fn pick_method(
1312+
&mut self,
1313+
self_ty: Ty<'tcx>,
1314+
mut unstable_candidates: Option<&mut Vec<(Candidate<'tcx>, Symbol)>>,
1315+
) -> Option<PickResult<'tcx>> {
1316+
if !self.tcx.sess.opts.debugging_opts.pick_stable_methods_before_any_unstable {
1317+
return self.pick_method_with_unstable(self_ty);
1318+
}
1319+
1320+
debug!("pick_method(self_ty={})", self.ty_to_string(self_ty));
1321+
1322+
let mut possibly_unsatisfied_predicates = Vec::new();
1323+
1324+
for (kind, candidates) in
1325+
&[("inherent", &self.inherent_candidates), ("extension", &self.extension_candidates)]
1326+
{
1327+
debug!("searching {} candidates", kind);
1328+
let res = self.consider_candidates(
1329+
self_ty,
1330+
candidates.iter(),
1331+
&mut possibly_unsatisfied_predicates,
1332+
unstable_candidates.as_deref_mut(),
1333+
);
1334+
if let Some(pick) = res {
1335+
return Some(pick);
1336+
}
1337+
}
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.extend(possibly_unsatisfied_predicates);
1343+
}
1344+
None
1345+
}
1346+
12651347
fn consider_candidates<'b, ProbesIter>(
12661348
&self,
12671349
self_ty: Ty<'tcx>,
@@ -1270,10 +1352,11 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
12701352
ty::Predicate<'tcx>,
12711353
Option<ty::Predicate<'tcx>>,
12721354
)>,
1273-
unstable_candidates: Option<&mut Vec<(&'b Candidate<'tcx>, Symbol)>>,
1355+
unstable_candidates: Option<&mut Vec<(Candidate<'tcx>, Symbol)>>,
12741356
) -> Option<PickResult<'tcx>>
12751357
where
12761358
ProbesIter: Iterator<Item = &'b Candidate<'tcx>> + Clone,
1359+
'tcx: 'b,
12771360
{
12781361
let mut applicable_candidates: Vec<_> = probes
12791362
.clone()
@@ -1298,7 +1381,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
12981381
if let stability::EvalResult::Deny { feature, .. } =
12991382
self.tcx.eval_stability(p.item.def_id, None, self.span, None)
13001383
{
1301-
uc.push((p, feature));
1384+
uc.push((p.clone(), feature));
13021385
return false;
13031386
}
13041387
true
@@ -1322,7 +1405,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
13221405
fn emit_unstable_name_collision_hint(
13231406
&self,
13241407
stable_pick: &Pick<'_>,
1325-
unstable_candidates: &[(&Candidate<'tcx>, Symbol)],
1408+
unstable_candidates: &[(Candidate<'tcx>, Symbol)],
13261409
) {
13271410
self.tcx.struct_span_lint_hir(
13281411
lint::builtin::UNSTABLE_NAME_COLLISIONS,

0 commit comments

Comments
 (0)