Skip to content

Commit ce3f3a5

Browse files
committed
Auto merge of #90329 - nbdd0121:typeck, r=nagisa
Try all stable method candidates first before trying unstable ones Currently we try methods in this order in each step: * Stable by value * Unstable by value * Stable autoref * Unstable autoref * ... This PR changes it to first try pick methods without any unstable candidates, and if none is found, try again to pick unstable ones. Fix #90320 CC #88971, hopefully would allow us to rename the "unstable_*" methods for integer impls back. `@rustbot` label T-compiler T-libs-api
2 parents 548c108 + 6ad626f commit ce3f3a5

File tree

7 files changed

+191
-27
lines changed

7 files changed

+191
-27
lines changed

compiler/rustc_interface/src/tests.rs

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

compiler/rustc_session/src/options.rs

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

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

+113-25
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>,
@@ -204,6 +204,7 @@ pub struct Pick<'tcx> {
204204
/// Indicates that we want to add an autoref (and maybe also unsize it), or if the receiver is
205205
/// `*mut T`, convert it to `*const T`.
206206
pub autoref_or_ptr_adjustment: Option<AutorefOrPtrAdjustment<'tcx>>,
207+
pub self_ty: Ty<'tcx>,
207208
}
208209

209210
#[derive(Clone, Debug, PartialEq, Eq)]
@@ -1101,13 +1102,37 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
11011102
}
11021103

11031104
fn pick_core(&mut self) -> Option<PickResult<'tcx>> {
1104-
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+
}
11051112

1106-
// 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();
11071132
steps
11081133
.iter()
11091134
.filter(|step| {
1110-
debug!("pick_core: step={:?}", step);
1135+
debug!("pick_all_method: step={:?}", step);
11111136
// skip types that are from a type error or that would require dereferencing
11121137
// a raw pointer
11131138
!step.self_ty.references_error() && !step.from_unsafe_deref
@@ -1123,11 +1148,30 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
11231148
.unwrap_or_else(|_| {
11241149
span_bug!(self.span, "{:?} was applicable but now isn't?", step.self_ty)
11251150
});
1126-
self.pick_by_value_method(step, self_ty).or_else(|| {
1127-
self.pick_autorefd_method(step, self_ty, hir::Mutability::Not)
1128-
.or_else(|| self.pick_autorefd_method(step, self_ty, hir::Mutability::Mut))
1129-
.or_else(|| self.pick_const_ptr_method(step, self_ty))
1130-
})
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+
})
11311175
})
11321176
.next()
11331177
}
@@ -1142,12 +1186,13 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
11421186
&mut self,
11431187
step: &CandidateStep<'tcx>,
11441188
self_ty: Ty<'tcx>,
1189+
unstable_candidates: Option<&mut Vec<(Candidate<'tcx>, Symbol)>>,
11451190
) -> Option<PickResult<'tcx>> {
11461191
if step.unsize {
11471192
return None;
11481193
}
11491194

1150-
self.pick_method(self_ty).map(|r| {
1195+
self.pick_method(self_ty, unstable_candidates).map(|r| {
11511196
r.map(|mut pick| {
11521197
pick.autoderefs = step.autoderefs;
11531198

@@ -1170,14 +1215,15 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
11701215
step: &CandidateStep<'tcx>,
11711216
self_ty: Ty<'tcx>,
11721217
mutbl: hir::Mutability,
1218+
unstable_candidates: Option<&mut Vec<(Candidate<'tcx>, Symbol)>>,
11731219
) -> Option<PickResult<'tcx>> {
11741220
let tcx = self.tcx;
11751221

11761222
// In general, during probing we erase regions.
11771223
let region = tcx.lifetimes.re_erased;
11781224

11791225
let autoref_ty = tcx.mk_ref(region, ty::TypeAndMut { ty: self_ty, mutbl });
1180-
self.pick_method(autoref_ty).map(|r| {
1226+
self.pick_method(autoref_ty, unstable_candidates).map(|r| {
11811227
r.map(|mut pick| {
11821228
pick.autoderefs = step.autoderefs;
11831229
pick.autoref_or_ptr_adjustment = Some(AutorefOrPtrAdjustment::Autoref {
@@ -1196,6 +1242,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
11961242
&mut self,
11971243
step: &CandidateStep<'tcx>,
11981244
self_ty: Ty<'tcx>,
1245+
unstable_candidates: Option<&mut Vec<(Candidate<'tcx>, Symbol)>>,
11991246
) -> Option<PickResult<'tcx>> {
12001247
// Don't convert an unsized reference to ptr
12011248
if step.unsize {
@@ -1209,7 +1256,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
12091256

12101257
let const_self_ty = ty::TypeAndMut { ty, mutbl: hir::Mutability::Not };
12111258
let const_ptr_ty = self.tcx.mk_ptr(const_self_ty);
1212-
self.pick_method(const_ptr_ty).map(|r| {
1259+
self.pick_method(const_ptr_ty, unstable_candidates).map(|r| {
12131260
r.map(|mut pick| {
12141261
pick.autoderefs = step.autoderefs;
12151262
pick.autoref_or_ptr_adjustment = Some(AutorefOrPtrAdjustment::ToConstPtr);
@@ -1218,8 +1265,8 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
12181265
})
12191266
}
12201267

1221-
fn pick_method(&mut self, self_ty: Ty<'tcx>) -> Option<PickResult<'tcx>> {
1222-
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));
12231270

12241271
let mut possibly_unsatisfied_predicates = Vec::new();
12251272
let mut unstable_candidates = Vec::new();
@@ -1241,7 +1288,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
12411288
//
12421289
// We suppress warning if we're picking the method only because it is a
12431290
// suggestion.
1244-
self.emit_unstable_name_collision_hint(p, &unstable_candidates, self_ty);
1291+
self.emit_unstable_name_collision_hint(p, &unstable_candidates);
12451292
}
12461293
}
12471294
return Some(pick);
@@ -1251,7 +1298,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
12511298
debug!("searching unstable candidates");
12521299
let res = self.consider_candidates(
12531300
self_ty,
1254-
unstable_candidates.into_iter().map(|(c, _)| c),
1301+
unstable_candidates.iter().map(|(c, _)| c),
12551302
&mut possibly_unsatisfied_predicates,
12561303
None,
12571304
);
@@ -1261,6 +1308,42 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
12611308
res
12621309
}
12631310

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+
12641347
fn consider_candidates<'b, ProbesIter>(
12651348
&self,
12661349
self_ty: Ty<'tcx>,
@@ -1269,10 +1352,11 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
12691352
ty::Predicate<'tcx>,
12701353
Option<ty::Predicate<'tcx>>,
12711354
)>,
1272-
unstable_candidates: Option<&mut Vec<(&'b Candidate<'tcx>, Symbol)>>,
1355+
unstable_candidates: Option<&mut Vec<(Candidate<'tcx>, Symbol)>>,
12731356
) -> Option<PickResult<'tcx>>
12741357
where
12751358
ProbesIter: Iterator<Item = &'b Candidate<'tcx>> + Clone,
1359+
'tcx: 'b,
12761360
{
12771361
let mut applicable_candidates: Vec<_> = probes
12781362
.clone()
@@ -1285,7 +1369,9 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
12851369
debug!("applicable_candidates: {:?}", applicable_candidates);
12861370

12871371
if applicable_candidates.len() > 1 {
1288-
if let Some(pick) = self.collapse_candidates_to_trait_pick(&applicable_candidates[..]) {
1372+
if let Some(pick) =
1373+
self.collapse_candidates_to_trait_pick(self_ty, &applicable_candidates[..])
1374+
{
12891375
return Some(Ok(pick));
12901376
}
12911377
}
@@ -1295,7 +1381,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
12951381
if let stability::EvalResult::Deny { feature, .. } =
12961382
self.tcx.eval_stability(p.item.def_id, None, self.span, None)
12971383
{
1298-
uc.push((p, feature));
1384+
uc.push((p.clone(), feature));
12991385
return false;
13001386
}
13011387
true
@@ -1309,7 +1395,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
13091395

13101396
applicable_candidates.pop().map(|(probe, status)| {
13111397
if status == ProbeResult::Match {
1312-
Ok(probe.to_unadjusted_pick())
1398+
Ok(probe.to_unadjusted_pick(self_ty))
13131399
} else {
13141400
Err(MethodError::BadReturnType)
13151401
}
@@ -1319,8 +1405,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
13191405
fn emit_unstable_name_collision_hint(
13201406
&self,
13211407
stable_pick: &Pick<'_>,
1322-
unstable_candidates: &[(&Candidate<'tcx>, Symbol)],
1323-
self_ty: Ty<'tcx>,
1408+
unstable_candidates: &[(Candidate<'tcx>, Symbol)],
13241409
) {
13251410
self.tcx.struct_span_lint_hir(
13261411
lint::builtin::UNSTABLE_NAME_COLLISIONS,
@@ -1351,7 +1436,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
13511436
"use the fully qualified path to the associated const",
13521437
format!(
13531438
"<{} as {}>::{}",
1354-
self_ty,
1439+
stable_pick.self_ty,
13551440
self.tcx.def_path_str(def_id),
13561441
stable_pick.item.ident
13571442
),
@@ -1591,6 +1676,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
15911676
/// use, so it's ok to just commit to "using the method from the trait Foo".
15921677
fn collapse_candidates_to_trait_pick(
15931678
&self,
1679+
self_ty: Ty<'tcx>,
15941680
probes: &[(&Candidate<'tcx>, ProbeResult)],
15951681
) -> Option<Pick<'tcx>> {
15961682
// Do all probes correspond to the same trait?
@@ -1610,6 +1696,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
16101696
import_ids: probes[0].0.import_ids.clone(),
16111697
autoderefs: 0,
16121698
autoref_or_ptr_adjustment: None,
1699+
self_ty,
16131700
})
16141701
}
16151702

@@ -1828,7 +1915,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
18281915
}
18291916

18301917
impl<'tcx> Candidate<'tcx> {
1831-
fn to_unadjusted_pick(&self) -> Pick<'tcx> {
1918+
fn to_unadjusted_pick(&self, self_ty: Ty<'tcx>) -> Pick<'tcx> {
18321919
Pick {
18331920
item: self.item,
18341921
kind: match self.kind {
@@ -1852,6 +1939,7 @@ impl<'tcx> Candidate<'tcx> {
18521939
import_ids: self.import_ids.clone(),
18531940
autoderefs: 0,
18541941
autoref_or_ptr_adjustment: None,
1942+
self_ty,
18551943
}
18561944
}
18571945
}

src/test/ui/inference/auxiliary/inference_unstable_iterator.rs

+17
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#![feature(staged_api)]
2+
#![feature(arbitrary_self_types)]
23

34
#![stable(feature = "ipu_iterator", since = "1.0.0")]
45

@@ -8,6 +9,22 @@ pub trait IpuIterator {
89
fn ipu_flatten(&self) -> u32 {
910
0
1011
}
12+
13+
#[unstable(feature = "ipu_flatten", issue = "99999")]
14+
fn ipu_by_value_vs_by_ref(self) -> u32 where Self: Sized {
15+
0
16+
}
17+
18+
#[unstable(feature = "ipu_flatten", issue = "99999")]
19+
fn ipu_by_ref_vs_by_ref_mut(&self) -> u32 {
20+
0
21+
}
22+
23+
#[unstable(feature = "ipu_flatten", issue = "99999")]
24+
fn ipu_by_mut_ptr_vs_by_const_ptr(self: *mut Self) -> u32 {
25+
0
26+
}
27+
1128
#[unstable(feature = "assoc_const_ipu_iter", issue = "99999")]
1229
const C: i32;
1330
}

src/test/ui/inference/auxiliary/inference_unstable_itertools.rs

+14
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,22 @@
1+
#![feature(arbitrary_self_types)]
2+
13
pub trait IpuItertools {
24
fn ipu_flatten(&self) -> u32 {
35
1
46
}
57

8+
fn ipu_by_value_vs_by_ref(&self) -> u32 {
9+
1
10+
}
11+
12+
fn ipu_by_ref_vs_by_ref_mut(&mut self) -> u32 {
13+
1
14+
}
15+
16+
fn ipu_by_mut_ptr_vs_by_const_ptr(self: *const Self) -> u32 {
17+
1
18+
}
19+
620
const C: i32;
721
}
822

0 commit comments

Comments
 (0)