diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 993e95b351484..230429d325ff1 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -1252,6 +1252,10 @@ impl<'tcx> InstantiatedPredicates<'tcx> { pub fn is_empty(&self) -> bool { self.predicates.is_empty() } + + pub fn into_iter(self) -> impl Iterator<Item = (ty::Predicate<'tcx>, Span)> { + std::iter::zip(self.predicates, self.spans) + } } #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable, TyEncodable, TyDecodable, Lift)] diff --git a/compiler/rustc_trait_selection/src/solve/assembly.rs b/compiler/rustc_trait_selection/src/solve/assembly.rs index e9ddad11ff23e..67ee168bccb1d 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly.rs @@ -1,5 +1,7 @@ //! Code shared by trait and projection goals for candidate assembly. +use crate::traits::TupleArgumentsFlag; + use super::infcx_ext::InferCtxtExt; use super::{ fixme_instantiate_canonical_query_response, CanonicalGoal, CanonicalResponse, Certainty, @@ -44,6 +46,45 @@ pub(super) trait GoalKind<'tcx>: TypeFoldable<'tcx> + Copy { goal: Goal<'tcx, Self>, impl_def_id: DefId, ); + + fn consider_trait_alias_candidate( + acx: &mut AssemblyCtxt<'_, 'tcx, Self>, + goal: Goal<'tcx, Self>, + ); + + fn consider_alias_bound_candidates( + acx: &mut AssemblyCtxt<'_, 'tcx, Self>, + goal: Goal<'tcx, Self>, + alias_ty: ty::AliasTy<'tcx>, + ); + + fn consider_object_bound_candidates( + acx: &mut AssemblyCtxt<'_, 'tcx, Self>, + goal: Goal<'tcx, Self>, + object_bounds: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>, + ); + + fn consider_param_env_candidates( + acx: &mut AssemblyCtxt<'_, 'tcx, Self>, + goal: Goal<'tcx, Self>, + ); + + fn consider_auto_trait_candidate( + acx: &mut AssemblyCtxt<'_, 'tcx, Self>, + goal: Goal<'tcx, Self>, + ); + + fn consider_fn_candidate( + acx: &mut AssemblyCtxt<'_, 'tcx, Self>, + goal: Goal<'tcx, Self>, + bound_sig: ty::PolyFnSig<'tcx>, + tuple_arguments: TupleArgumentsFlag, + ); + + fn consider_builtin_trait_candidates( + acx: &mut AssemblyCtxt<'_, 'tcx, Self>, + goal: Goal<'tcx, Self>, + ); } /// An abstraction which correctly deals with the canonical results for candidates. @@ -69,6 +110,18 @@ impl<'a, 'tcx, G: GoalKind<'tcx>> AssemblyCtxt<'a, 'tcx, G> { acx.assemble_impl_candidates(goal); + acx.assemble_bound_candidates(goal); + + acx.assemble_param_env_candidates(goal); + + acx.assemble_auto_trait_candidates(goal); + + acx.assemble_trait_alias_candidates(goal); + + acx.assemble_fn_like_candidates(goal); + + G::consider_builtin_trait_candidates(&mut acx, goal); + acx.candidates } @@ -111,7 +164,10 @@ impl<'a, 'tcx, G: GoalKind<'tcx>> AssemblyCtxt<'a, 'tcx, G> { // NOTE: Alternatively we could call `evaluate_goal` here and only have a `Normalized` candidate. // This doesn't work as long as we use `CandidateSource` in both winnowing and to resolve associated items. - let goal = goal.with(tcx, goal.predicate.with_self_ty(tcx, normalized_ty)); + let goal = goal.with( + tcx, + goal.predicate.with_self_ty(tcx, self.infcx.shallow_resolve(normalized_ty)), + ); let mut orig_values = OriginalQueryValues::default(); let goal = self.infcx.canonicalize_query(goal, &mut orig_values); let normalized_candidates = @@ -147,4 +203,53 @@ impl<'a, 'tcx, G: GoalKind<'tcx>> AssemblyCtxt<'a, 'tcx, G> { |impl_def_id| G::consider_impl_candidate(self, goal, impl_def_id), ); } + + fn assemble_bound_candidates(&mut self, goal: Goal<'tcx, G>) { + match *goal.predicate.self_ty().kind() { + ty::Alias(_, alias_ty) => G::consider_alias_bound_candidates(self, goal, alias_ty), + ty::Dynamic(predicates, _, _) => { + G::consider_object_bound_candidates(self, goal, predicates) + } + _ => {} + } + } + + fn assemble_param_env_candidates(&mut self, goal: Goal<'tcx, G>) { + G::consider_param_env_candidates(self, goal); + } + + fn assemble_auto_trait_candidates(&mut self, goal: Goal<'tcx, G>) { + if self.cx.tcx.trait_is_auto(goal.predicate.trait_def_id(self.cx.tcx)) { + G::consider_auto_trait_candidate(self, goal); + } + } + + fn assemble_trait_alias_candidates(&mut self, goal: Goal<'tcx, G>) { + if self.cx.tcx.is_trait_alias(goal.predicate.trait_def_id(self.cx.tcx)) { + G::consider_trait_alias_candidate(self, goal); + } + } + + fn assemble_fn_like_candidates(&mut self, goal: Goal<'tcx, G>) { + let tcx = self.cx.tcx; + let trait_def_id = goal.predicate.trait_def_id(tcx); + if let Some(goal_kind) = tcx.fn_trait_kind_from_def_id(trait_def_id) { + match *goal.predicate.self_ty().kind() { + ty::FnDef(def_id, substs) => { + G::consider_fn_candidate(self, goal, tcx.bound_fn_sig(def_id).subst(tcx, substs), TupleArgumentsFlag::Yes) + } + ty::FnPtr(sig) => { + G::consider_fn_candidate(self, goal, sig, TupleArgumentsFlag::Yes) + } + ty::Closure(_, substs) => { + if let Some(kind) = self.infcx.closure_kind(substs) + && kind.extends(goal_kind) + { + G::consider_fn_candidate(self, goal, substs.as_closure().sig(), TupleArgumentsFlag::No) + } + } + _ => {} + } + } + } } diff --git a/compiler/rustc_trait_selection/src/solve/project_goals.rs b/compiler/rustc_trait_selection/src/solve/project_goals.rs index 3d649bea19ddf..68cdc24204788 100644 --- a/compiler/rustc_trait_selection/src/solve/project_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/project_goals.rs @@ -211,6 +211,59 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { acx.try_insert_candidate(CandidateSource::Impl(impl_def_id), certainty); }) } + + fn consider_trait_alias_candidate( + _acx: &mut AssemblyCtxt<'_, 'tcx, Self>, + _goal: Goal<'tcx, Self>, + ) { + // Trait aliases never have (their own) associated types + } + + fn consider_alias_bound_candidates( + _acx: &mut AssemblyCtxt<'_, 'tcx, Self>, + _goal: Goal<'tcx, ProjectionPredicate<'tcx>>, + _alias_ty: ty::AliasTy<'tcx>, + ) { + todo!() + } + + fn consider_object_bound_candidates( + _acx: &mut AssemblyCtxt<'_, 'tcx, Self>, + _goal: Goal<'tcx, Self>, + _object_bounds: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>, + ) { + todo!() + } + + fn consider_param_env_candidates( + _acx: &mut AssemblyCtxt<'_, 'tcx, Self>, + _goal: Goal<'tcx, Self>, + ) { + todo!() + } + + fn consider_auto_trait_candidate( + _acx: &mut AssemblyCtxt<'_, 'tcx, Self>, + _goal: Goal<'tcx, Self>, + ) { + // Auto traits never have associated types + } + + fn consider_fn_candidate( + _acx: &mut AssemblyCtxt<'_, 'tcx, Self>, + _goal: Goal<'tcx, Self>, + _bound_sig: ty::PolyFnSig<'tcx>, + _tuple_arguments: crate::traits::TupleArgumentsFlag, + ) { + todo!() + } + + fn consider_builtin_trait_candidates( + _acx: &mut AssemblyCtxt<'_, 'tcx, Self>, + _goal: Goal<'tcx, Self>, + ) { + todo!(); + } } /// This behavior is also implemented in `rustc_ty_utils` and in the old `project` code. diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs index c69cc39acb53c..a15f4b2f89edf 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs @@ -2,22 +2,30 @@ use std::iter; +use crate::traits::TupleArgumentsFlag; + use super::assembly::{self, AssemblyCtxt}; -use super::{CanonicalGoal, EvalCtxt, Goal, QueryResult}; +use super::{CanonicalGoal, Certainty, EvalCtxt, Goal, MaybeCause, QueryResult}; + use rustc_hir::def_id::DefId; -use rustc_infer::infer::InferOk; +use rustc_hir::{Movability, Mutability, Unsafety}; +use rustc_infer::infer::{InferCtxt, InferOk, LateBoundRegionConversionTime}; use rustc_infer::traits::query::NoSolution; +use rustc_infer::traits::util::supertraits; use rustc_infer::traits::ObligationCause; use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams}; -use rustc_middle::ty::TraitPredicate; use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_middle::ty::{TraitPredicate, TypeVisitable}; use rustc_span::DUMMY_SP; +use rustc_target::spec::abi::Abi; #[allow(dead_code)] // FIXME: implement and use all variants. #[derive(Debug, Clone, Copy)] pub(super) enum CandidateSource { /// Some user-defined impl with the given `DefId`. Impl(DefId), + /// The automatic implementation of a trait alias. + TraitAlias, /// The n-th caller bound in the `param_env` of our goal. /// /// This is pretty much always a bound from the `where`-clauses of the @@ -36,6 +44,11 @@ pub(super) enum CandidateSource { /// We know that `<Whatever as Trait>::Assoc: OtherTrait` holds by looking at /// the bounds on `Trait::Assoc`. AliasBound(usize), + /// Implementation of `Trait` or its supertraits for a `dyn Trait + Send + Sync`. + ObjectBound(usize), + /// Implementation of `Send` or other explicitly listed *auto* traits for + /// a `dyn Trait + Send + Sync` + ObjectAutoBound, /// A builtin implementation for some specific traits, used in cases /// where we cannot rely an ordinary library implementations. /// @@ -47,6 +60,9 @@ pub(super) enum CandidateSource { /// at the constituent types of the `self_ty` to check whether the auto trait /// is implemented for those. AutoImpl, + /// An automatic impl for `Fn`/`FnMut`/`FnOnce` for fn pointers, fn items, + /// and closures. + Fn, } type Candidate<'tcx> = assembly::Candidate<'tcx, TraitPredicate<'tcx>>; @@ -68,7 +84,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { fn consider_impl_candidate( acx: &mut AssemblyCtxt<'_, 'tcx, Self>, - goal: Goal<'tcx, TraitPredicate<'tcx>>, + goal: Goal<'tcx, Self>, impl_def_id: DefId, ) { let tcx = acx.cx.tcx; @@ -108,6 +124,474 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { acx.try_insert_candidate(CandidateSource::Impl(impl_def_id), certainty); }) } + + fn consider_trait_alias_candidate( + acx: &mut AssemblyCtxt<'_, 'tcx, Self>, + goal: Goal<'tcx, Self>, + ) { + let tcx = acx.cx.tcx; + acx.infcx.probe(|_| { + let nested_goals = tcx + .predicates_of(goal.predicate.def_id()) + .instantiate_own(tcx, goal.predicate.trait_ref.substs) + .predicates + .into_iter() + .map(|pred| goal.with(tcx, pred)) + .collect(); + let Ok(certainty) = acx.cx.evaluate_all(acx.infcx, nested_goals) else { return }; + acx.try_insert_candidate(CandidateSource::TraitAlias, certainty); + }) + } + + fn consider_alias_bound_candidates( + acx: &mut AssemblyCtxt<'_, 'tcx, Self>, + goal: Goal<'tcx, Self>, + alias_ty: ty::AliasTy<'tcx>, + ) { + for (idx, (predicate, _)) in acx + .cx + .tcx + .bound_explicit_item_bounds(alias_ty.def_id) + .subst_iter_copied(acx.cx.tcx, alias_ty.substs) + .enumerate() + { + let Some(poly_trait_pred) = predicate.to_opt_poly_trait_pred() else { continue }; + if poly_trait_pred.skip_binder().def_id() != goal.predicate.def_id() { + continue; + }; + // FIXME: constness? polarity? + let poly_trait_ref = poly_trait_pred.map_bound(|trait_pred| trait_pred.trait_ref); + // FIXME: Faster to do a filter first with a rejection context? + match_poly_trait_ref_against_goal( + acx, + goal, + poly_trait_ref, + CandidateSource::AliasBound(idx), + ); + } + } + + fn consider_object_bound_candidates( + acx: &mut AssemblyCtxt<'_, 'tcx, Self>, + goal: Goal<'tcx, Self>, + object_bounds: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>, + ) { + if let Some(principal_trait_ref) = object_bounds.principal() { + let principal_trait_ref = + principal_trait_ref.with_self_ty(acx.cx.tcx, goal.predicate.self_ty()); + + for (idx, poly_trait_ref) in supertraits(acx.cx.tcx, principal_trait_ref).enumerate() { + if poly_trait_ref.skip_binder().def_id != goal.predicate.def_id() { + continue; + }; + match_poly_trait_ref_against_goal( + acx, + goal, + poly_trait_ref, + CandidateSource::ObjectBound(idx), + ); + } + } + + if object_bounds.auto_traits().any(|def_id| def_id == goal.predicate.def_id()) { + acx.try_insert_candidate(CandidateSource::ObjectAutoBound, Certainty::Yes); + } + } + + fn consider_param_env_candidates( + acx: &mut AssemblyCtxt<'_, 'tcx, Self>, + goal: Goal<'tcx, Self>, + ) { + for (idx, predicate) in goal.param_env.caller_bounds().iter().enumerate() { + let Some(poly_trait_pred) = predicate.to_opt_poly_trait_pred() else { continue }; + if poly_trait_pred.skip_binder().def_id() != goal.predicate.def_id() { + continue; + }; + // FIXME: constness? polarity? + let poly_trait_ref = poly_trait_pred.map_bound(|trait_pred| trait_pred.trait_ref); + // FIXME: Faster to do a filter first with a rejection context? + + match_poly_trait_ref_against_goal( + acx, + goal, + poly_trait_ref, + CandidateSource::ParamEnv(idx), + ); + } + } + + fn consider_auto_trait_candidate( + acx: &mut AssemblyCtxt<'_, 'tcx, Self>, + goal: Goal<'tcx, Self>, + ) { + // FIXME: We need to give auto trait candidates less precedence than impl candidates? + acx.infcx.probe(|_| { + let components = + instantiate_constituent_tys_for_auto_trait(acx.infcx, goal.predicate.self_ty()); + evaluate_goal_for_components(acx, goal, components, CandidateSource::AutoImpl); + }) + } + + fn consider_fn_candidate( + acx: &mut AssemblyCtxt<'_, 'tcx, Self>, + goal: Goal<'tcx, Self>, + bound_sig: ty::PolyFnSig<'tcx>, + tuple_args_flag: TupleArgumentsFlag, + ) { + if bound_sig.unsafety() != Unsafety::Normal || bound_sig.c_variadic() { + return; + } + + // Binder skipped here (*) + let (arguments_tuple, expected_abi) = match tuple_args_flag { + TupleArgumentsFlag::No => (bound_sig.skip_binder().inputs()[0], Abi::RustCall), + TupleArgumentsFlag::Yes => { + (acx.cx.tcx.intern_tup(bound_sig.skip_binder().inputs()), Abi::Rust) + } + }; + if expected_abi != bound_sig.abi() { + return; + } + // (*) Rebound here + let found_trait_ref = bound_sig.rebind( + acx.cx + .tcx + .mk_trait_ref(goal.predicate.def_id(), [goal.predicate.self_ty(), arguments_tuple]), + ); + + acx.infcx.probe(|_| { + // FIXME: This needs to validate that `fn() -> TY` has `TY: Sized`. + match_poly_trait_ref_against_goal(acx, goal, found_trait_ref, CandidateSource::Fn); + }) + } + + fn consider_builtin_trait_candidates( + acx: &mut AssemblyCtxt<'_, 'tcx, Self>, + goal: Goal<'tcx, Self>, + ) { + let lang_items = acx.cx.tcx.lang_items(); + let trait_def_id = goal.predicate.def_id(); + let self_ty = goal.predicate.self_ty(); + + if Some(trait_def_id) == lang_items.sized_trait() { + acx.infcx.probe(|_| { + let components = instantiate_constituent_tys_for_sized_trait(acx.infcx, self_ty); + evaluate_goal_for_components(acx, goal, components, CandidateSource::Builtin); + }) + } else if Some(trait_def_id) == lang_items.copy_trait() + || Some(trait_def_id) == lang_items.clone_trait() + { + acx.infcx.probe(|_| { + let components = + instantiate_constituent_tys_for_copy_clone_trait(acx.infcx, self_ty); + evaluate_goal_for_components(acx, goal, components, CandidateSource::Builtin); + }) + } else if Some(trait_def_id) == lang_items.discriminant_kind_trait() + || Some(trait_def_id) == lang_items.pointee_trait() + { + // `Pointee` and `DiscriminantKind` are implemented by all traits unconditionally + acx.try_insert_candidate(CandidateSource::Builtin, Certainty::Yes); + } else if Some(trait_def_id) == lang_items.tuple_trait() { + match *self_ty.kind() { + ty::Infer(ty::TyVar(_)) => acx.try_insert_candidate( + CandidateSource::Builtin, + Certainty::Maybe(MaybeCause::Ambiguity), + ), + ty::Tuple(_) => acx.try_insert_candidate(CandidateSource::Builtin, Certainty::Yes), + _ => {} + } + } else if Some(trait_def_id) == lang_items.pointer_sized() { + let erased_self_ty = acx.cx.tcx.erase_regions(self_ty); + if erased_self_ty.has_non_region_infer() { + acx.try_insert_candidate( + CandidateSource::Builtin, + Certainty::Maybe(MaybeCause::Ambiguity), + ) + } else { + let usize_layout = acx + .cx + .tcx + .layout_of(ty::ParamEnv::empty().and(acx.cx.tcx.types.usize)) + .unwrap(); + if let Ok(layout) = acx.cx.tcx.layout_of(goal.param_env.and(self_ty)) + && layout.layout.size() == usize_layout.layout.size() + && layout.layout.align().abi == usize_layout.layout.align().abi + { + acx.try_insert_candidate(CandidateSource::Builtin, Certainty::Yes); + } + } + } else if Some(trait_def_id) == lang_items.coerce_unsized_trait() + || Some(trait_def_id) == lang_items.unsize_trait() + { + // FIXME + } + } +} + +fn match_poly_trait_ref_against_goal<'tcx>( + acx: &mut AssemblyCtxt<'_, 'tcx, TraitPredicate<'tcx>>, + goal: Goal<'tcx, TraitPredicate<'tcx>>, + trait_ref: ty::PolyTraitRef<'tcx>, + candidate: CandidateSource, +) { + acx.infcx.probe(|_| { + let trait_ref = acx.infcx.replace_bound_vars_with_fresh_vars( + DUMMY_SP, + LateBoundRegionConversionTime::HigherRankedType, + trait_ref, + ); + + let Ok(InferOk { obligations, .. }) = acx + .infcx + .at(&ObligationCause::dummy(), goal.param_env) + .define_opaque_types(false) + .sup(goal.predicate.trait_ref, trait_ref) + .map_err(|e| debug!("failed to equate trait refs: {e:?}")) + else { + return + }; + + let nested_goals = obligations.into_iter().map(|o| o.into()).collect(); + + let Ok(certainty) = acx.cx.evaluate_all(acx.infcx, nested_goals) else { return }; + acx.try_insert_candidate(candidate, certainty); + }) +} + +// Evaluate the goal with a new set of self types, combined with a certainty. +fn evaluate_goal_for_components<'tcx>( + acx: &mut AssemblyCtxt<'_, 'tcx, TraitPredicate<'tcx>>, + goal: Goal<'tcx, TraitPredicate<'tcx>>, + components: ComponentsAndCertainty<'tcx>, + candidate: CandidateSource, +) { + let components = match components { + ComponentsAndCertainty::Yes(components) => components, + ComponentsAndCertainty::Maybe => { + acx.try_insert_candidate(candidate, Certainty::Maybe(MaybeCause::Ambiguity)); + return; + } + ComponentsAndCertainty::No => { + return; + } + }; + + let nested_goals = components + .into_iter() + .map(|ty| { + Goal::new( + acx.cx.tcx, + goal.param_env, + ty::Binder::dummy(goal.predicate.with_self_ty(acx.cx.tcx, ty)), + ) + }) + .collect(); + + let Ok(certainty) = acx.cx.evaluate_all(acx.infcx, nested_goals) else { return }; + acx.try_insert_candidate(candidate, certainty); +} + +enum ComponentsAndCertainty<'tcx> { + Yes(Vec<Ty<'tcx>>), + Maybe, + No, +} + +// Calculates the constituent types of a type for `auto trait` purposes. +// +// For types with an "existential" binder, i.e. generator witnesses, we also +// instantiate the binder with placeholders eagerly. +fn instantiate_constituent_tys_for_auto_trait<'tcx>( + infcx: &InferCtxt<'tcx>, + ty: Ty<'tcx>, +) -> ComponentsAndCertainty<'tcx> { + let tcx = infcx.tcx; + match *ty.kind() { + ty::Uint(_) + | ty::Int(_) + | ty::Bool + | ty::Float(_) + | ty::FnDef(..) + | ty::FnPtr(_) + | ty::Str + | ty::Error(_) + | ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) + | ty::Never + | ty::Char => ComponentsAndCertainty::Yes(vec![]), + + ty::Placeholder(..) + | ty::Dynamic(..) + | ty::Param(..) + | ty::Foreign(..) + | ty::Alias(ty::Projection, ..) + | ty::Bound(..) => ComponentsAndCertainty::No, + + ty::Infer(ty::TyVar(_)) => ComponentsAndCertainty::Maybe, + + ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => bug!(), + + ty::RawPtr(ty::TypeAndMut { ty: element_ty, .. }) | ty::Ref(_, element_ty, _) => { + ComponentsAndCertainty::Yes(vec![element_ty]) + } + + ty::Array(element_ty, _) | ty::Slice(element_ty) => { + ComponentsAndCertainty::Yes(vec![element_ty]) + } + + ty::Tuple(ref tys) => { + // (T1, ..., Tn) -- meets any bound that all of T1...Tn meet + ComponentsAndCertainty::Yes(tys.iter().collect()) + } + + ty::Closure(_, ref substs) => { + ComponentsAndCertainty::Yes(vec![substs.as_closure().tupled_upvars_ty()]) + } + + ty::Generator(_, ref substs, _) => { + let generator_substs = substs.as_generator(); + ComponentsAndCertainty::Yes(vec![ + generator_substs.tupled_upvars_ty(), + generator_substs.witness(), + ]) + } + + ty::GeneratorWitness(types) => { + ComponentsAndCertainty::Yes(infcx.replace_bound_vars_with_placeholders(types).to_vec()) + } + + // For `PhantomData<T>`, we pass `T`. + ty::Adt(def, substs) if def.is_phantom_data() => { + ComponentsAndCertainty::Yes(vec![substs.type_at(0)]) + } + + ty::Adt(def, substs) => { + ComponentsAndCertainty::Yes(def.all_fields().map(|f| f.ty(tcx, substs)).collect()) + } + + ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => { + // We can resolve the `impl Trait` to its concrete type, + // which enforces a DAG between the functions requiring + // the auto trait bounds in question. + ComponentsAndCertainty::Yes(vec![tcx.bound_type_of(def_id).subst(tcx, substs)]) + } + } +} + +fn instantiate_constituent_tys_for_sized_trait<'tcx>( + infcx: &InferCtxt<'tcx>, + ty: Ty<'tcx>, +) -> ComponentsAndCertainty<'tcx> { + match *ty.kind() { + 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::Generator(..) + | ty::GeneratorWitness(..) + | ty::Array(..) + | ty::Closure(..) + | ty::Never + | ty::Dynamic(_, _, ty::DynStar) + | ty::Error(_) => ComponentsAndCertainty::Yes(vec![]), + + ty::Str + | ty::Slice(_) + | ty::Dynamic(..) + | ty::Foreign(..) + | ty::Alias(..) + | ty::Param(_) => ComponentsAndCertainty::No, + + ty::Infer(ty::TyVar(_)) => ComponentsAndCertainty::Maybe, + + ty::Placeholder(..) + | ty::Bound(..) + | ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => bug!(), + + ty::Tuple(tys) => ComponentsAndCertainty::Yes(tys.to_vec()), + + ty::Adt(def, substs) => { + let sized_crit = def.sized_constraint(infcx.tcx); + ComponentsAndCertainty::Yes( + sized_crit + .0 + .iter() + .map(|ty| sized_crit.rebind(*ty).subst(infcx.tcx, substs)) + .collect(), + ) + } + } +} + +fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>( + infcx: &InferCtxt<'tcx>, + ty: Ty<'tcx>, +) -> ComponentsAndCertainty<'tcx> { + match *ty.kind() { + ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) + | ty::FnDef(..) + | ty::FnPtr(_) + | ty::Error(_) => ComponentsAndCertainty::Yes(vec![]), + + // Implementations are provided in core + ty::Uint(_) + | ty::Int(_) + | ty::Bool + | ty::Float(_) + | ty::Char + | ty::RawPtr(..) + | ty::Never + | ty::Ref(_, _, Mutability::Not) + | ty::Array(..) => ComponentsAndCertainty::No, + + ty::Dynamic(..) + | ty::Str + | ty::Slice(_) + | ty::Generator(_, _, Movability::Static) + | ty::Foreign(..) + | ty::Ref(_, _, Mutability::Mut) + | ty::Adt(_, _) + | ty::Alias(_, _) + | ty::Param(_) => ComponentsAndCertainty::No, + + ty::Infer(ty::TyVar(_)) => ComponentsAndCertainty::Maybe, + + ty::Placeholder(..) + | ty::Bound(..) + | ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => bug!(), + + ty::Tuple(tys) => ComponentsAndCertainty::Yes(tys.to_vec()), + + ty::Closure(_, substs) => match *substs.as_closure().tupled_upvars_ty().kind() { + ty::Tuple(tys) => ComponentsAndCertainty::Yes(tys.to_vec()), + ty::Infer(ty::TyVar(_)) => ComponentsAndCertainty::Maybe, + _ => bug!(), + }, + + ty::Generator(_, substs, Movability::Movable) => { + if infcx.tcx.features().generator_clone { + let generator = substs.as_generator(); + match *generator.tupled_upvars_ty().kind() { + ty::Tuple(tys) => ComponentsAndCertainty::Yes( + tys.iter().chain([generator.witness()]).collect(), + ), + ty::Infer(ty::TyVar(_)) => ComponentsAndCertainty::Maybe, + _ => bug!(), + } + } else { + ComponentsAndCertainty::No + } + } + + ty::GeneratorWitness(types) => { + ComponentsAndCertainty::Yes(infcx.replace_bound_vars_with_placeholders(types).to_vec()) + } + } } impl<'tcx> EvalCtxt<'tcx> { @@ -167,10 +651,14 @@ impl<'tcx> EvalCtxt<'tcx> { // FIXME: implement this match (candidate.source, other.source) { (CandidateSource::Impl(_), _) + | (CandidateSource::TraitAlias, _) | (CandidateSource::ParamEnv(_), _) | (CandidateSource::AliasBound(_), _) + | (CandidateSource::ObjectBound(_), _) + | (CandidateSource::ObjectAutoBound, _) | (CandidateSource::Builtin, _) - | (CandidateSource::AutoImpl, _) => unimplemented!(), + | (CandidateSource::AutoImpl, _) + | (CandidateSource::Fn, _) => unimplemented!(), } } diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 37b40a2f75adc..340922220384c 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -60,6 +60,7 @@ pub use self::specialize::{specialization_graph, translate_substs, OverlapError} pub use self::structural_match::{ search_for_adt_const_param_violation, search_for_structural_match_violation, }; +pub use self::util::TupleArgumentsFlag; pub use self::util::{ elaborate_obligations, elaborate_predicates, elaborate_predicates_with_span, elaborate_trait_ref, elaborate_trait_refs,