Try all stable candidates first before trying unstable ones
This commit is contained in:
parent
9740050726
commit
6a207f23eb
3 changed files with 105 additions and 19 deletions
|
@ -751,6 +751,7 @@ fn test_debugging_options_tracking_hash() {
|
||||||
tracked!(panic_abort_tests, true);
|
tracked!(panic_abort_tests, true);
|
||||||
tracked!(panic_in_drop, PanicStrategy::Abort);
|
tracked!(panic_in_drop, PanicStrategy::Abort);
|
||||||
tracked!(partially_uninit_const_threshold, Some(123));
|
tracked!(partially_uninit_const_threshold, Some(123));
|
||||||
|
tracked!(pick_stable_methods_before_any_unstable, false);
|
||||||
tracked!(plt, Some(true));
|
tracked!(plt, Some(true));
|
||||||
tracked!(polonius, true);
|
tracked!(polonius, true);
|
||||||
tracked!(precise_enum_drop_elaboration, false);
|
tracked!(precise_enum_drop_elaboration, false);
|
||||||
|
|
|
@ -1233,6 +1233,8 @@ options! {
|
||||||
and set the maximum total size of a const allocation for which this is allowed (default: never)"),
|
and set the maximum total size of a const allocation for which this is allowed (default: never)"),
|
||||||
perf_stats: bool = (false, parse_bool, [UNTRACKED],
|
perf_stats: bool = (false, parse_bool, [UNTRACKED],
|
||||||
"print some performance-related statistics (default: no)"),
|
"print some performance-related statistics (default: no)"),
|
||||||
|
pick_stable_methods_before_any_unstable: bool = (true, parse_bool, [TRACKED],
|
||||||
|
"try to pick stable methods first before picking any unstable methods (default: yes)"),
|
||||||
plt: Option<bool> = (None, parse_opt_bool, [TRACKED],
|
plt: Option<bool> = (None, parse_opt_bool, [TRACKED],
|
||||||
"whether to use the PLT when calling into shared libraries;
|
"whether to use the PLT when calling into shared libraries;
|
||||||
only has effect for PIC code on systems with ELF binaries
|
only has effect for PIC code on systems with ELF binaries
|
||||||
|
|
|
@ -92,7 +92,7 @@ impl<'a, 'tcx> Deref for ProbeContext<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone)]
|
||||||
struct Candidate<'tcx> {
|
struct Candidate<'tcx> {
|
||||||
// Candidates are (I'm not quite sure, but they are mostly) basically
|
// Candidates are (I'm not quite sure, but they are mostly) basically
|
||||||
// some metadata on top of a `ty::AssocItem` (without substs).
|
// some metadata on top of a `ty::AssocItem` (without substs).
|
||||||
|
@ -132,7 +132,7 @@ struct Candidate<'tcx> {
|
||||||
import_ids: SmallVec<[LocalDefId; 1]>,
|
import_ids: SmallVec<[LocalDefId; 1]>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone)]
|
||||||
enum CandidateKind<'tcx> {
|
enum CandidateKind<'tcx> {
|
||||||
InherentImplCandidate(
|
InherentImplCandidate(
|
||||||
SubstsRef<'tcx>,
|
SubstsRef<'tcx>,
|
||||||
|
@ -1102,13 +1102,37 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pick_core(&mut self) -> Option<PickResult<'tcx>> {
|
fn pick_core(&mut self) -> Option<PickResult<'tcx>> {
|
||||||
let steps = self.steps.clone();
|
let mut unstable_candidates = Vec::new();
|
||||||
|
let pick = self.pick_all_method(Some(&mut unstable_candidates));
|
||||||
|
|
||||||
// find the first step that works
|
// In this case unstable picking is done by `pick_method`.
|
||||||
|
if !self.tcx.sess.opts.debugging_opts.pick_stable_methods_before_any_unstable {
|
||||||
|
return pick;
|
||||||
|
}
|
||||||
|
|
||||||
|
match pick {
|
||||||
|
// Emit a lint if there are unstable candidates alongside the stable ones.
|
||||||
|
//
|
||||||
|
// We suppress warning if we're picking the method only because it is a
|
||||||
|
// suggestion.
|
||||||
|
Some(Ok(ref p)) if !self.is_suggestion.0 && !unstable_candidates.is_empty() => {
|
||||||
|
self.emit_unstable_name_collision_hint(p, &unstable_candidates);
|
||||||
|
pick
|
||||||
|
}
|
||||||
|
Some(_) => pick,
|
||||||
|
None => self.pick_all_method(None),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pick_all_method(
|
||||||
|
&mut self,
|
||||||
|
mut unstable_candidates: Option<&mut Vec<(Candidate<'tcx>, Symbol)>>,
|
||||||
|
) -> Option<PickResult<'tcx>> {
|
||||||
|
let steps = self.steps.clone();
|
||||||
steps
|
steps
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|step| {
|
.filter(|step| {
|
||||||
debug!("pick_core: step={:?}", step);
|
debug!("pick_all_method: step={:?}", step);
|
||||||
// skip types that are from a type error or that would require dereferencing
|
// skip types that are from a type error or that would require dereferencing
|
||||||
// a raw pointer
|
// a raw pointer
|
||||||
!step.self_ty.references_error() && !step.from_unsafe_deref
|
!step.self_ty.references_error() && !step.from_unsafe_deref
|
||||||
|
@ -1124,10 +1148,29 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
||||||
.unwrap_or_else(|_| {
|
.unwrap_or_else(|_| {
|
||||||
span_bug!(self.span, "{:?} was applicable but now isn't?", step.self_ty)
|
span_bug!(self.span, "{:?} was applicable but now isn't?", step.self_ty)
|
||||||
});
|
});
|
||||||
self.pick_by_value_method(step, self_ty).or_else(|| {
|
self.pick_by_value_method(step, self_ty, unstable_candidates.as_deref_mut())
|
||||||
self.pick_autorefd_method(step, self_ty, hir::Mutability::Not)
|
.or_else(|| {
|
||||||
.or_else(|| self.pick_autorefd_method(step, self_ty, hir::Mutability::Mut))
|
self.pick_autorefd_method(
|
||||||
.or_else(|| self.pick_const_ptr_method(step, self_ty))
|
step,
|
||||||
|
self_ty,
|
||||||
|
hir::Mutability::Not,
|
||||||
|
unstable_candidates.as_deref_mut(),
|
||||||
|
)
|
||||||
|
.or_else(|| {
|
||||||
|
self.pick_autorefd_method(
|
||||||
|
step,
|
||||||
|
self_ty,
|
||||||
|
hir::Mutability::Mut,
|
||||||
|
unstable_candidates.as_deref_mut(),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.or_else(|| {
|
||||||
|
self.pick_const_ptr_method(
|
||||||
|
step,
|
||||||
|
self_ty,
|
||||||
|
unstable_candidates.as_deref_mut(),
|
||||||
|
)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.next()
|
.next()
|
||||||
|
@ -1143,12 +1186,13 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
||||||
&mut self,
|
&mut self,
|
||||||
step: &CandidateStep<'tcx>,
|
step: &CandidateStep<'tcx>,
|
||||||
self_ty: Ty<'tcx>,
|
self_ty: Ty<'tcx>,
|
||||||
|
unstable_candidates: Option<&mut Vec<(Candidate<'tcx>, Symbol)>>,
|
||||||
) -> Option<PickResult<'tcx>> {
|
) -> Option<PickResult<'tcx>> {
|
||||||
if step.unsize {
|
if step.unsize {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.pick_method(self_ty).map(|r| {
|
self.pick_method(self_ty, unstable_candidates).map(|r| {
|
||||||
r.map(|mut pick| {
|
r.map(|mut pick| {
|
||||||
pick.autoderefs = step.autoderefs;
|
pick.autoderefs = step.autoderefs;
|
||||||
|
|
||||||
|
@ -1171,6 +1215,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
||||||
step: &CandidateStep<'tcx>,
|
step: &CandidateStep<'tcx>,
|
||||||
self_ty: Ty<'tcx>,
|
self_ty: Ty<'tcx>,
|
||||||
mutbl: hir::Mutability,
|
mutbl: hir::Mutability,
|
||||||
|
unstable_candidates: Option<&mut Vec<(Candidate<'tcx>, Symbol)>>,
|
||||||
) -> Option<PickResult<'tcx>> {
|
) -> Option<PickResult<'tcx>> {
|
||||||
let tcx = self.tcx;
|
let tcx = self.tcx;
|
||||||
|
|
||||||
|
@ -1178,7 +1223,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
||||||
let region = tcx.lifetimes.re_erased;
|
let region = tcx.lifetimes.re_erased;
|
||||||
|
|
||||||
let autoref_ty = tcx.mk_ref(region, ty::TypeAndMut { ty: self_ty, mutbl });
|
let autoref_ty = tcx.mk_ref(region, ty::TypeAndMut { ty: self_ty, mutbl });
|
||||||
self.pick_method(autoref_ty).map(|r| {
|
self.pick_method(autoref_ty, unstable_candidates).map(|r| {
|
||||||
r.map(|mut pick| {
|
r.map(|mut pick| {
|
||||||
pick.autoderefs = step.autoderefs;
|
pick.autoderefs = step.autoderefs;
|
||||||
pick.autoref_or_ptr_adjustment = Some(AutorefOrPtrAdjustment::Autoref {
|
pick.autoref_or_ptr_adjustment = Some(AutorefOrPtrAdjustment::Autoref {
|
||||||
|
@ -1197,6 +1242,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
||||||
&mut self,
|
&mut self,
|
||||||
step: &CandidateStep<'tcx>,
|
step: &CandidateStep<'tcx>,
|
||||||
self_ty: Ty<'tcx>,
|
self_ty: Ty<'tcx>,
|
||||||
|
unstable_candidates: Option<&mut Vec<(Candidate<'tcx>, Symbol)>>,
|
||||||
) -> Option<PickResult<'tcx>> {
|
) -> Option<PickResult<'tcx>> {
|
||||||
// Don't convert an unsized reference to ptr
|
// Don't convert an unsized reference to ptr
|
||||||
if step.unsize {
|
if step.unsize {
|
||||||
|
@ -1210,7 +1256,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
||||||
|
|
||||||
let const_self_ty = ty::TypeAndMut { ty, mutbl: hir::Mutability::Not };
|
let const_self_ty = ty::TypeAndMut { ty, mutbl: hir::Mutability::Not };
|
||||||
let const_ptr_ty = self.tcx.mk_ptr(const_self_ty);
|
let const_ptr_ty = self.tcx.mk_ptr(const_self_ty);
|
||||||
self.pick_method(const_ptr_ty).map(|r| {
|
self.pick_method(const_ptr_ty, unstable_candidates).map(|r| {
|
||||||
r.map(|mut pick| {
|
r.map(|mut pick| {
|
||||||
pick.autoderefs = step.autoderefs;
|
pick.autoderefs = step.autoderefs;
|
||||||
pick.autoref_or_ptr_adjustment = Some(AutorefOrPtrAdjustment::ToConstPtr);
|
pick.autoref_or_ptr_adjustment = Some(AutorefOrPtrAdjustment::ToConstPtr);
|
||||||
|
@ -1219,8 +1265,8 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pick_method(&mut self, self_ty: Ty<'tcx>) -> Option<PickResult<'tcx>> {
|
fn pick_method_with_unstable(&mut self, self_ty: Ty<'tcx>) -> Option<PickResult<'tcx>> {
|
||||||
debug!("pick_method(self_ty={})", self.ty_to_string(self_ty));
|
debug!("pick_method_with_unstable(self_ty={})", self.ty_to_string(self_ty));
|
||||||
|
|
||||||
let mut possibly_unsatisfied_predicates = Vec::new();
|
let mut possibly_unsatisfied_predicates = Vec::new();
|
||||||
let mut unstable_candidates = Vec::new();
|
let mut unstable_candidates = Vec::new();
|
||||||
|
@ -1252,7 +1298,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
||||||
debug!("searching unstable candidates");
|
debug!("searching unstable candidates");
|
||||||
let res = self.consider_candidates(
|
let res = self.consider_candidates(
|
||||||
self_ty,
|
self_ty,
|
||||||
unstable_candidates.into_iter().map(|(c, _)| c),
|
unstable_candidates.iter().map(|(c, _)| c),
|
||||||
&mut possibly_unsatisfied_predicates,
|
&mut possibly_unsatisfied_predicates,
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
|
@ -1262,6 +1308,42 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn pick_method(
|
||||||
|
&mut self,
|
||||||
|
self_ty: Ty<'tcx>,
|
||||||
|
mut unstable_candidates: Option<&mut Vec<(Candidate<'tcx>, Symbol)>>,
|
||||||
|
) -> Option<PickResult<'tcx>> {
|
||||||
|
if !self.tcx.sess.opts.debugging_opts.pick_stable_methods_before_any_unstable {
|
||||||
|
return self.pick_method_with_unstable(self_ty);
|
||||||
|
}
|
||||||
|
|
||||||
|
debug!("pick_method(self_ty={})", self.ty_to_string(self_ty));
|
||||||
|
|
||||||
|
let mut possibly_unsatisfied_predicates = Vec::new();
|
||||||
|
|
||||||
|
for (kind, candidates) in
|
||||||
|
&[("inherent", &self.inherent_candidates), ("extension", &self.extension_candidates)]
|
||||||
|
{
|
||||||
|
debug!("searching {} candidates", kind);
|
||||||
|
let res = self.consider_candidates(
|
||||||
|
self_ty,
|
||||||
|
candidates.iter(),
|
||||||
|
&mut possibly_unsatisfied_predicates,
|
||||||
|
unstable_candidates.as_deref_mut(),
|
||||||
|
);
|
||||||
|
if let Some(pick) = res {
|
||||||
|
return Some(pick);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// `pick_method` may be called twice for the same self_ty if no stable methods
|
||||||
|
// match. Only extend once.
|
||||||
|
if unstable_candidates.is_some() {
|
||||||
|
self.unsatisfied_predicates.extend(possibly_unsatisfied_predicates);
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
fn consider_candidates<'b, ProbesIter>(
|
fn consider_candidates<'b, ProbesIter>(
|
||||||
&self,
|
&self,
|
||||||
self_ty: Ty<'tcx>,
|
self_ty: Ty<'tcx>,
|
||||||
|
@ -1270,10 +1352,11 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
||||||
ty::Predicate<'tcx>,
|
ty::Predicate<'tcx>,
|
||||||
Option<ty::Predicate<'tcx>>,
|
Option<ty::Predicate<'tcx>>,
|
||||||
)>,
|
)>,
|
||||||
unstable_candidates: Option<&mut Vec<(&'b Candidate<'tcx>, Symbol)>>,
|
unstable_candidates: Option<&mut Vec<(Candidate<'tcx>, Symbol)>>,
|
||||||
) -> Option<PickResult<'tcx>>
|
) -> Option<PickResult<'tcx>>
|
||||||
where
|
where
|
||||||
ProbesIter: Iterator<Item = &'b Candidate<'tcx>> + Clone,
|
ProbesIter: Iterator<Item = &'b Candidate<'tcx>> + Clone,
|
||||||
|
'tcx: 'b,
|
||||||
{
|
{
|
||||||
let mut applicable_candidates: Vec<_> = probes
|
let mut applicable_candidates: Vec<_> = probes
|
||||||
.clone()
|
.clone()
|
||||||
|
@ -1298,7 +1381,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
||||||
if let stability::EvalResult::Deny { feature, .. } =
|
if let stability::EvalResult::Deny { feature, .. } =
|
||||||
self.tcx.eval_stability(p.item.def_id, None, self.span, None)
|
self.tcx.eval_stability(p.item.def_id, None, self.span, None)
|
||||||
{
|
{
|
||||||
uc.push((p, feature));
|
uc.push((p.clone(), feature));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
true
|
true
|
||||||
|
@ -1322,7 +1405,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
||||||
fn emit_unstable_name_collision_hint(
|
fn emit_unstable_name_collision_hint(
|
||||||
&self,
|
&self,
|
||||||
stable_pick: &Pick<'_>,
|
stable_pick: &Pick<'_>,
|
||||||
unstable_candidates: &[(&Candidate<'tcx>, Symbol)],
|
unstable_candidates: &[(Candidate<'tcx>, Symbol)],
|
||||||
) {
|
) {
|
||||||
self.tcx.struct_span_lint_hir(
|
self.tcx.struct_span_lint_hir(
|
||||||
lint::builtin::UNSTABLE_NAME_COLLISIONS,
|
lint::builtin::UNSTABLE_NAME_COLLISIONS,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue