Skip to content

Instantiate auto trait/Copy/Clone/Sized before computing constituent types binder #143538

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
180 changes: 149 additions & 31 deletions compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ use rustc_middle::{bug, span_bug};
use tracing::{debug, instrument, trace};

use super::SelectionCandidate::*;
use super::{BuiltinImplConditions, SelectionCandidateSet, SelectionContext, TraitObligationStack};
use super::{SelectionCandidateSet, SelectionContext, TraitObligationStack};
use crate::traits::util;

impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
Expand Down Expand Up @@ -75,8 +75,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
self.assemble_candidates_from_impls(obligation, &mut candidates);

// For other types, we'll use the builtin rules.
let copy_conditions = self.copy_clone_conditions(obligation);
self.assemble_builtin_bound_candidates(copy_conditions, &mut candidates);
self.assemble_builtin_copy_clone_candidate(
obligation.predicate.self_ty().skip_binder(),
&mut candidates,
);
}
Some(LangItem::DiscriminantKind) => {
// `DiscriminantKind` is automatically implemented for every type.
Expand All @@ -88,14 +90,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
}
Some(LangItem::Sized) => {
self.assemble_builtin_sized_candidate(
obligation,
obligation.predicate.self_ty().skip_binder(),
&mut candidates,
SizedTraitKind::Sized,
);
}
Some(LangItem::MetaSized) => {
self.assemble_builtin_sized_candidate(
obligation,
obligation.predicate.self_ty().skip_binder(),
&mut candidates,
SizedTraitKind::MetaSized,
);
Expand Down Expand Up @@ -357,14 +359,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
obligation: &PolyTraitObligation<'tcx>,
candidates: &mut SelectionCandidateSet<'tcx>,
) {
let self_ty = obligation.self_ty().skip_binder();
// gen constructs get lowered to a special kind of coroutine that
// should directly `impl FusedIterator`.
if let ty::Coroutine(did, ..) = self_ty.kind()
&& self.tcx().coroutine_is_gen(*did)
{
debug!(?self_ty, ?obligation, "assemble_fused_iterator_candidates",);

if self.coroutine_is_gen(obligation.self_ty().skip_binder()) {
candidates.vec.push(BuiltinCandidate);
}
}
Expand Down Expand Up @@ -1113,41 +1108,164 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
}
}

/// Assembles the `Sized` and `MetaSized` traits which are built-in to the language itself.
/// Assembles `Copy` and `Clone` candidates for built-in types with no libcore-defined
/// `Copy` or `Clone` impls.
#[instrument(level = "debug", skip(self, candidates))]
fn assemble_builtin_sized_candidate(
fn assemble_builtin_copy_clone_candidate(
&mut self,
obligation: &PolyTraitObligation<'tcx>,
self_ty: Ty<'tcx>,
candidates: &mut SelectionCandidateSet<'tcx>,
sizedness: SizedTraitKind,
) {
match self.sizedness_conditions(obligation, sizedness) {
BuiltinImplConditions::Where(_nested) => {
candidates.vec.push(SizedCandidate);
match *self_ty.kind() {
// These impls are built-in because we cannot express sufficiently
// generic impls in libcore.
ty::FnDef(..)
| ty::FnPtr(..)
| ty::Error(_)
| ty::Tuple(..)
| ty::CoroutineWitness(..)
| ty::Pat(..) => {
candidates.vec.push(BuiltinCandidate);
}

// Implementations provided in libcore.
ty::Uint(_)
| ty::Int(_)
| ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
| ty::Bool
| ty::Float(_)
| ty::Char
| ty::RawPtr(..)
| ty::Never
| ty::Ref(_, _, hir::Mutability::Not)
| ty::Array(..) => {}

// FIXME(unsafe_binder): Should we conditionally
// (i.e. universally) implement copy/clone?
ty::UnsafeBinder(_) => {}

// Not `Sized`, which is a supertrait of `Copy`/`Clone`.
ty::Dynamic(..) | ty::Str | ty::Slice(..) | ty::Foreign(..) => {}

// Not `Copy` or `Clone` by design.
ty::Ref(_, _, hir::Mutability::Mut) => {}

ty::Coroutine(coroutine_def_id, args) => {
match self.tcx().coroutine_movability(coroutine_def_id) {
hir::Movability::Static => {}
hir::Movability::Movable => {
if self.tcx().features().coroutine_clone() {
let resolved_upvars =
self.infcx.shallow_resolve(args.as_coroutine().tupled_upvars_ty());
let resolved_witness =
self.infcx.shallow_resolve(args.as_coroutine().witness());
if resolved_upvars.is_ty_var() || resolved_witness.is_ty_var() {
// Not yet resolved.
candidates.ambiguous = true;
} else {
candidates.vec.push(BuiltinCandidate);
}
}
}
}
}
BuiltinImplConditions::None => {}
BuiltinImplConditions::Ambiguous => {

ty::Closure(_, args) => {
let resolved_upvars =
self.infcx.shallow_resolve(args.as_closure().tupled_upvars_ty());
if resolved_upvars.is_ty_var() {
// Not yet resolved.
candidates.ambiguous = true;
} else {
candidates.vec.push(BuiltinCandidate);
}
}

ty::CoroutineClosure(_, args) => {
let resolved_upvars =
self.infcx.shallow_resolve(args.as_coroutine_closure().tupled_upvars_ty());
if resolved_upvars.is_ty_var() {
// Not yet resolved.
candidates.ambiguous = true;
} else {
candidates.vec.push(BuiltinCandidate);
}
}

// Fallback to whatever user-defined impls or param-env clauses exist in this case.
ty::Adt(..) | ty::Alias(..) | ty::Param(..) | ty::Placeholder(..) => {}

ty::Infer(ty::TyVar(_)) => {
candidates.ambiguous = true;
}

// Only appears when assembling higher-ranked `for<T> T: Clone`.
ty::Bound(..) => {}

ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
bug!("asked to assemble builtin bounds of unexpected type: {:?}", self_ty);
}
}
}

/// Assembles the trait which are built-in to the language itself:
/// e.g. `Copy` and `Clone`.
/// Assembles the `Sized` and `MetaSized` traits which are built-in to the language itself.
#[instrument(level = "debug", skip(self, candidates))]
fn assemble_builtin_bound_candidates(
fn assemble_builtin_sized_candidate(
&mut self,
conditions: BuiltinImplConditions<'tcx>,
self_ty: Ty<'tcx>,
candidates: &mut SelectionCandidateSet<'tcx>,
sizedness: SizedTraitKind,
) {
match conditions {
BuiltinImplConditions::Where(_) => {
candidates.vec.push(BuiltinCandidate);
match *self_ty.kind() {
// Always sized.
ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
| ty::Uint(_)
| ty::Int(_)
| ty::Bool
| ty::Float(_)
| ty::FnDef(..)
| ty::FnPtr(..)
| ty::RawPtr(..)
| ty::Char
| ty::Ref(..)
| ty::Coroutine(..)
| ty::CoroutineWitness(..)
| ty::Array(..)
| ty::Closure(..)
| ty::CoroutineClosure(..)
| ty::Never
| ty::Error(_) => {
candidates.vec.push(SizedCandidate);
}

// Conditionally `Sized`.
ty::Tuple(..) | ty::Pat(..) | ty::Adt(..) | ty::UnsafeBinder(_) => {
candidates.vec.push(SizedCandidate);
}
BuiltinImplConditions::None => {}
BuiltinImplConditions::Ambiguous => {

// `MetaSized` but not `Sized`.
ty::Str | ty::Slice(_) | ty::Dynamic(..) => match sizedness {
SizedTraitKind::Sized => {}
SizedTraitKind::MetaSized => {
candidates.vec.push(SizedCandidate);
}
},

// Not `MetaSized` or `Sized`.
ty::Foreign(..) => {}

ty::Alias(..) | ty::Param(_) | ty::Placeholder(..) => {}

ty::Infer(ty::TyVar(_)) => {
candidates.ambiguous = true;
}

// Only appears when assembling higher-ranked `for<T> T: Sized`.
ty::Bound(..) => {}

ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
bug!("asked to assemble builtin bounds of unexpected type: {:?}", self_ty);
}
}
}

Expand Down
27 changes: 17 additions & 10 deletions compiler/rustc_trait_selection/src/traits/select/confirmation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ use thin_vec::thin_vec;
use tracing::{debug, instrument};

use super::SelectionCandidate::{self, *};
use super::{BuiltinImplConditions, PredicateObligations, SelectionContext};
use super::{PredicateObligations, SelectionContext};
use crate::traits::normalize::{normalize_with_depth, normalize_with_depth_to};
use crate::traits::util::{self, closure_trait_ref_and_return_type};
use crate::traits::{
Expand Down Expand Up @@ -257,29 +257,35 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
debug!(?obligation, "confirm_builtin_candidate");
let tcx = self.tcx();
let trait_def = obligation.predicate.def_id();
let conditions = match tcx.as_lang_item(trait_def) {
Some(LangItem::Sized) => self.sizedness_conditions(obligation, SizedTraitKind::Sized),
let self_ty = self.infcx.shallow_resolve(
self.infcx.enter_forall_and_leak_universe(obligation.predicate.self_ty()),
);
let types = match tcx.as_lang_item(trait_def) {
Some(LangItem::Sized) => self.sizedness_conditions(self_ty, SizedTraitKind::Sized),
Some(LangItem::MetaSized) => {
self.sizedness_conditions(obligation, SizedTraitKind::MetaSized)
self.sizedness_conditions(self_ty, SizedTraitKind::MetaSized)
}
Some(LangItem::PointeeSized) => {
bug!("`PointeeSized` is removing during lowering");
}
Some(LangItem::Copy | LangItem::Clone) => self.copy_clone_conditions(obligation),
Some(LangItem::FusedIterator) => self.fused_iterator_conditions(obligation),
Some(LangItem::Copy | LangItem::Clone) => self.copy_clone_conditions(self_ty),
Some(LangItem::FusedIterator) => {
if self.coroutine_is_gen(self_ty) {
ty::Binder::dummy(vec![])
} else {
unreachable!("tried to assemble `FusedIterator` for non-gen coroutine");
}
}
Some(
LangItem::Destruct
| LangItem::DiscriminantKind
| LangItem::FnPtrTrait
| LangItem::PointeeTrait
| LangItem::Tuple
| LangItem::Unpin,
) => BuiltinImplConditions::Where(ty::Binder::dummy(vec![])),
) => ty::Binder::dummy(vec![]),
other => bug!("unexpected builtin trait {trait_def:?} ({other:?})"),
};
let BuiltinImplConditions::Where(types) = conditions else {
bug!("obligation {:?} had matched a builtin impl but now doesn't", obligation);
};
let types = self.infcx.enter_forall_and_leak_universe(types);

let cause = obligation.derived_cause(ObligationCauseCode::BuiltinDerived);
Expand Down Expand Up @@ -403,6 +409,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {

let self_ty =
obligation.predicate.self_ty().map_bound(|ty| self.infcx.shallow_resolve(ty));
let self_ty = self.infcx.enter_forall_and_leak_universe(self_ty);

let types = self.constituent_types_for_ty(self_ty)?;
let types = self.infcx.enter_forall_and_leak_universe(types);
Expand Down
Loading
Loading