Prefer built-in sized impls for rigid types always
This commit is contained in:
parent
52daa7d835
commit
f9696dda6e
4 changed files with 41 additions and 6 deletions
|
@ -95,10 +95,13 @@ pub type EvaluationCache<'tcx, ENV> = Cache<(ENV, ty::PolyTraitPredicate<'tcx>),
|
||||||
/// parameter environment.
|
/// parameter environment.
|
||||||
#[derive(PartialEq, Eq, Debug, Clone, TypeVisitable)]
|
#[derive(PartialEq, Eq, Debug, Clone, TypeVisitable)]
|
||||||
pub enum SelectionCandidate<'tcx> {
|
pub enum SelectionCandidate<'tcx> {
|
||||||
|
/// UwU
|
||||||
|
SizedCandidate,
|
||||||
|
|
||||||
/// A builtin implementation for some specific traits, used in cases
|
/// A builtin implementation for some specific traits, used in cases
|
||||||
/// where we cannot rely an ordinary library implementations.
|
/// where we cannot rely an ordinary library implementations.
|
||||||
///
|
///
|
||||||
/// The most notable examples are `sized`, `Copy` and `Clone`. This is also
|
/// The most notable examples are `Copy` and `Clone`. This is also
|
||||||
/// used for the `DiscriminantKind` and `Pointee` trait, both of which have
|
/// used for the `DiscriminantKind` and `Pointee` trait, both of which have
|
||||||
/// an associated type.
|
/// an associated type.
|
||||||
BuiltinCandidate {
|
BuiltinCandidate {
|
||||||
|
|
|
@ -86,10 +86,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
// `Pointee` is automatically implemented for every type.
|
// `Pointee` is automatically implemented for every type.
|
||||||
candidates.vec.push(BuiltinCandidate { has_nested: false });
|
candidates.vec.push(BuiltinCandidate { has_nested: false });
|
||||||
} else if tcx.is_lang_item(def_id, LangItem::Sized) {
|
} else if tcx.is_lang_item(def_id, LangItem::Sized) {
|
||||||
// Sized is never implementable by end-users, it is
|
self.assemble_builtin_sized_candidate(obligation, &mut candidates);
|
||||||
// always automatically computed.
|
|
||||||
let sized_conditions = self.sized_conditions(obligation);
|
|
||||||
self.assemble_builtin_bound_candidates(sized_conditions, &mut candidates);
|
|
||||||
} else if tcx.is_lang_item(def_id, LangItem::Unsize) {
|
} else if tcx.is_lang_item(def_id, LangItem::Unsize) {
|
||||||
self.assemble_candidates_for_unsizing(obligation, &mut candidates);
|
self.assemble_candidates_for_unsizing(obligation, &mut candidates);
|
||||||
} else if tcx.is_lang_item(def_id, LangItem::Destruct) {
|
} else if tcx.is_lang_item(def_id, LangItem::Destruct) {
|
||||||
|
@ -1059,6 +1056,25 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
/// Assembles the trait which are built-in to the language itself:
|
/// Assembles the trait which are built-in to the language itself:
|
||||||
/// `Copy`, `Clone` and `Sized`.
|
/// `Copy`, `Clone` and `Sized`.
|
||||||
#[instrument(level = "debug", skip(self, candidates))]
|
#[instrument(level = "debug", skip(self, candidates))]
|
||||||
|
fn assemble_builtin_sized_candidate(
|
||||||
|
&mut self,
|
||||||
|
obligation: &PolyTraitObligation<'tcx>,
|
||||||
|
candidates: &mut SelectionCandidateSet<'tcx>,
|
||||||
|
) {
|
||||||
|
match self.sized_conditions(obligation) {
|
||||||
|
BuiltinImplConditions::Where(_) => {
|
||||||
|
candidates.vec.push(SizedCandidate);
|
||||||
|
}
|
||||||
|
BuiltinImplConditions::None => {}
|
||||||
|
BuiltinImplConditions::Ambiguous => {
|
||||||
|
candidates.ambiguous = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Assembles the trait which are built-in to the language itself:
|
||||||
|
/// e.g. `Copy` and `Clone`.
|
||||||
|
#[instrument(level = "debug", skip(self, candidates))]
|
||||||
fn assemble_builtin_bound_candidates(
|
fn assemble_builtin_bound_candidates(
|
||||||
&mut self,
|
&mut self,
|
||||||
conditions: BuiltinImplConditions<'tcx>,
|
conditions: BuiltinImplConditions<'tcx>,
|
||||||
|
|
|
@ -40,6 +40,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
candidate: SelectionCandidate<'tcx>,
|
candidate: SelectionCandidate<'tcx>,
|
||||||
) -> Result<Selection<'tcx>, SelectionError<'tcx>> {
|
) -> Result<Selection<'tcx>, SelectionError<'tcx>> {
|
||||||
let mut impl_src = match candidate {
|
let mut impl_src = match candidate {
|
||||||
|
SizedCandidate => {
|
||||||
|
let data = self.confirm_builtin_candidate(obligation, true);
|
||||||
|
ImplSource::Builtin(BuiltinImplSource::Misc, data)
|
||||||
|
}
|
||||||
|
|
||||||
BuiltinCandidate { has_nested } => {
|
BuiltinCandidate { has_nested } => {
|
||||||
let data = self.confirm_builtin_candidate(obligation, has_nested);
|
let data = self.confirm_builtin_candidate(obligation, has_nested);
|
||||||
ImplSource::Builtin(BuiltinImplSource::Misc, data)
|
ImplSource::Builtin(BuiltinImplSource::Misc, data)
|
||||||
|
|
|
@ -1801,6 +1801,16 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
|
||||||
return Some(candidates.pop().unwrap().candidate);
|
return Some(candidates.pop().unwrap().candidate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We prefer `Sized` candidates over everything.
|
||||||
|
let mut sized_candidates =
|
||||||
|
candidates.iter().filter(|c| matches!(c.candidate, SizedCandidate));
|
||||||
|
if let Some(_sized_candidate) = sized_candidates.next() {
|
||||||
|
// There should only ever be a single sized candidate
|
||||||
|
// as they would otherwise overlap.
|
||||||
|
debug_assert_eq!(sized_candidates.next(), None);
|
||||||
|
return Some(SizedCandidate);
|
||||||
|
}
|
||||||
|
|
||||||
// We prefer trivial builtin candidates, i.e. builtin impls without any nested
|
// We prefer trivial builtin candidates, i.e. builtin impls without any nested
|
||||||
// requirements, over all others. This is a fix for #53123 and prevents winnowing
|
// requirements, over all others. This is a fix for #53123 and prevents winnowing
|
||||||
// from accidentally extending the lifetime of a variable.
|
// from accidentally extending the lifetime of a variable.
|
||||||
|
@ -1940,7 +1950,8 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
|
||||||
// Don't use impl candidates which overlap with other candidates.
|
// Don't use impl candidates which overlap with other candidates.
|
||||||
// This should pretty much only ever happen with malformed impls.
|
// This should pretty much only ever happen with malformed impls.
|
||||||
if candidates.iter().all(|c| match c.candidate {
|
if candidates.iter().all(|c| match c.candidate {
|
||||||
BuiltinCandidate { has_nested: _ }
|
SizedCandidate
|
||||||
|
| BuiltinCandidate { has_nested: _ }
|
||||||
| TransmutabilityCandidate
|
| TransmutabilityCandidate
|
||||||
| AutoImplCandidate
|
| AutoImplCandidate
|
||||||
| ClosureCandidate { .. }
|
| ClosureCandidate { .. }
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue