diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs index d89759f4dd4..1ebcfd03c14 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs @@ -6,7 +6,6 @@ use super::assembly::{self, Candidate, CandidateSource}; use super::infcx_ext::InferCtxtExt; use super::{EvalCtxt, Goal, QueryResult}; use rustc_hir::def_id::DefId; -use rustc_hir::{Movability, Mutability}; use rustc_infer::infer::InferCtxt; use rustc_infer::traits::query::NoSolution; use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams}; @@ -14,6 +13,8 @@ use rustc_middle::ty::TraitPredicate; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::DUMMY_SP; +mod structural_traits; + impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { fn self_ty(self) -> Ty<'tcx> { self.self_ty() @@ -85,11 +86,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, ) -> QueryResult<'tcx> { - ecx.infcx.probe(|_| { - let constituent_tys = - instantiate_constituent_tys_for_auto_trait(ecx.infcx, goal.predicate.self_ty())?; - ecx.evaluate_goal_for_constituent_tys_and_make_canonical_response(goal, constituent_tys) - }) + ecx.probe_and_evaluate_goal_for_constituent_tys( + goal, + structural_traits::instantiate_constituent_tys_for_auto_trait, + ) } fn consider_trait_alias_candidate( @@ -112,44 +112,46 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, ) -> QueryResult<'tcx> { - ecx.infcx.probe(|_| { - let constituent_tys = - instantiate_constituent_tys_for_sized_trait(ecx.infcx, goal.predicate.self_ty())?; - ecx.evaluate_goal_for_constituent_tys_and_make_canonical_response(goal, constituent_tys) - }) + ecx.probe_and_evaluate_goal_for_constituent_tys( + goal, + structural_traits::instantiate_constituent_tys_for_sized_trait, + ) } fn consider_builtin_copy_clone_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, ) -> QueryResult<'tcx> { - ecx.infcx.probe(|_| { - let constituent_tys = instantiate_constituent_tys_for_copy_clone_trait( - ecx.infcx, - goal.predicate.self_ty(), - )?; - ecx.evaluate_goal_for_constituent_tys_and_make_canonical_response(goal, constituent_tys) - }) + ecx.probe_and_evaluate_goal_for_constituent_tys( + goal, + structural_traits::instantiate_constituent_tys_for_copy_clone_trait, + ) } } impl<'tcx> EvalCtxt<'_, 'tcx> { - fn evaluate_goal_for_constituent_tys_and_make_canonical_response( + /// Convenience function for traits that are structural, i.e. that only + /// have nested subgoals that only change the self type. Unlike other + /// evaluate-like helpers, this does a probe, so it doesn't need to be + /// wrapped in one. + fn probe_and_evaluate_goal_for_constituent_tys( &mut self, goal: Goal<'tcx, TraitPredicate<'tcx>>, - constituent_tys: Vec>, + constituent_tys: impl Fn(&InferCtxt<'tcx>, Ty<'tcx>) -> Result>, NoSolution>, ) -> QueryResult<'tcx> { - self.evaluate_all_and_make_canonical_response( - constituent_tys - .into_iter() - .map(|ty| { - goal.with( - self.tcx(), - ty::Binder::dummy(goal.predicate.with_self_ty(self.tcx(), ty)), - ) - }) - .collect(), - ) + self.infcx.probe(|_| { + self.evaluate_all_and_make_canonical_response( + constituent_tys(self.infcx, goal.predicate.self_ty())? + .into_iter() + .map(|ty| { + goal.with( + self.tcx(), + ty::Binder::dummy(goal.predicate.with_self_ty(self.tcx(), ty)), + ) + }) + .collect(), + ) + }) } pub(super) fn compute_trait_goal( @@ -227,187 +229,3 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { candidate } } - -// 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>, -) -> Result>, NoSolution> { - 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 => Ok(vec![]), - - ty::Placeholder(..) - | ty::Dynamic(..) - | ty::Param(..) - | ty::Foreign(..) - | ty::Alias(ty::Projection, ..) - | ty::Bound(..) - | ty::Infer(ty::TyVar(_)) => { - // FIXME: Do we need to mark anything as ambiguous here? Yeah? - Err(NoSolution) - } - - ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => bug!(), - - ty::RawPtr(ty::TypeAndMut { ty: element_ty, .. }) | ty::Ref(_, element_ty, _) => { - Ok(vec![element_ty]) - } - - ty::Array(element_ty, _) | ty::Slice(element_ty) => Ok(vec![element_ty]), - - ty::Tuple(ref tys) => { - // (T1, ..., Tn) -- meets any bound that all of T1...Tn meet - Ok(tys.iter().collect()) - } - - ty::Closure(_, ref substs) => Ok(vec![substs.as_closure().tupled_upvars_ty()]), - - ty::Generator(_, ref substs, _) => { - let generator_substs = substs.as_generator(); - Ok(vec![generator_substs.tupled_upvars_ty(), generator_substs.witness()]) - } - - ty::GeneratorWitness(types) => { - Ok(infcx.replace_bound_vars_with_placeholders(types).to_vec()) - } - - // For `PhantomData`, we pass `T`. - ty::Adt(def, substs) if def.is_phantom_data() => Ok(vec![substs.type_at(0)]), - - ty::Adt(def, substs) => Ok(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. - Ok(vec![tcx.bound_type_of(def_id).subst(tcx, substs)]) - } - } -} - -fn instantiate_constituent_tys_for_sized_trait<'tcx>( - infcx: &InferCtxt<'tcx>, - ty: Ty<'tcx>, -) -> Result>, NoSolution> { - 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(_) => Ok(vec![]), - - ty::Str - | ty::Slice(_) - | ty::Dynamic(..) - | ty::Foreign(..) - | ty::Alias(..) - | ty::Param(_) => Err(NoSolution), - - ty::Infer(ty::TyVar(_)) => bug!("FIXME: ambiguous"), - - ty::Placeholder(..) - | ty::Bound(..) - | ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => bug!(), - - ty::Tuple(tys) => Ok(tys.to_vec()), - - ty::Adt(def, substs) => { - let sized_crit = def.sized_constraint(infcx.tcx); - Ok(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>, -) -> Result>, NoSolution> { - match *ty.kind() { - ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) - | ty::FnDef(..) - | ty::FnPtr(_) - | ty::Error(_) => Ok(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(..) => Err(NoSolution), - - ty::Dynamic(..) - | ty::Str - | ty::Slice(_) - | ty::Generator(_, _, Movability::Static) - | ty::Foreign(..) - | ty::Ref(_, _, Mutability::Mut) - | ty::Adt(_, _) - | ty::Alias(_, _) - | ty::Param(_) => Err(NoSolution), - - ty::Infer(ty::TyVar(_)) => bug!("FIXME: ambiguous"), - - ty::Placeholder(..) - | ty::Bound(..) - | ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => bug!(), - - ty::Tuple(tys) => Ok(tys.to_vec()), - - ty::Closure(_, substs) => match *substs.as_closure().tupled_upvars_ty().kind() { - ty::Tuple(tys) => Ok(tys.to_vec()), - ty::Infer(ty::TyVar(_)) => bug!("FIXME: ambiguous"), - _ => 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) => Ok(tys.iter().chain([generator.witness()]).collect()), - ty::Infer(ty::TyVar(_)) => bug!("FIXME: ambiguous"), - _ => bug!(), - } - } else { - Err(NoSolution) - } - } - - ty::GeneratorWitness(types) => { - Ok(infcx.replace_bound_vars_with_placeholders(types).to_vec()) - } - } -} diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals/structural_traits.rs b/compiler/rustc_trait_selection/src/solve/trait_goals/structural_traits.rs new file mode 100644 index 00000000000..bbc0c772532 --- /dev/null +++ b/compiler/rustc_trait_selection/src/solve/trait_goals/structural_traits.rs @@ -0,0 +1,179 @@ +use rustc_hir::{Movability, Mutability}; +use rustc_infer::{infer::InferCtxt, traits::query::NoSolution}; +use rustc_middle::ty::{self, Ty}; + +// 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. +pub(super) fn instantiate_constituent_tys_for_auto_trait<'tcx>( + infcx: &InferCtxt<'tcx>, + ty: Ty<'tcx>, +) -> Result>, NoSolution> { + 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 => Ok(vec![]), + + ty::Placeholder(..) + | ty::Dynamic(..) + | ty::Param(..) + | ty::Foreign(..) + | ty::Alias(ty::Projection, ..) + | ty::Bound(..) + | ty::Infer(ty::TyVar(_)) => { + // FIXME: Do we need to mark anything as ambiguous here? Yeah? + Err(NoSolution) + } + + ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => bug!(), + + ty::RawPtr(ty::TypeAndMut { ty: element_ty, .. }) | ty::Ref(_, element_ty, _) => { + Ok(vec![element_ty]) + } + + ty::Array(element_ty, _) | ty::Slice(element_ty) => Ok(vec![element_ty]), + + ty::Tuple(ref tys) => { + // (T1, ..., Tn) -- meets any bound that all of T1...Tn meet + Ok(tys.iter().collect()) + } + + ty::Closure(_, ref substs) => Ok(vec![substs.as_closure().tupled_upvars_ty()]), + + ty::Generator(_, ref substs, _) => { + let generator_substs = substs.as_generator(); + Ok(vec![generator_substs.tupled_upvars_ty(), generator_substs.witness()]) + } + + ty::GeneratorWitness(types) => { + Ok(infcx.replace_bound_vars_with_placeholders(types).to_vec()) + } + + // For `PhantomData`, we pass `T`. + ty::Adt(def, substs) if def.is_phantom_data() => Ok(vec![substs.type_at(0)]), + + ty::Adt(def, substs) => Ok(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. + Ok(vec![tcx.bound_type_of(def_id).subst(tcx, substs)]) + } + } +} + +pub(super) fn instantiate_constituent_tys_for_sized_trait<'tcx>( + infcx: &InferCtxt<'tcx>, + ty: Ty<'tcx>, +) -> Result>, NoSolution> { + 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(_) => Ok(vec![]), + + ty::Str + | ty::Slice(_) + | ty::Dynamic(..) + | ty::Foreign(..) + | ty::Alias(..) + | ty::Param(_) => Err(NoSolution), + + ty::Infer(ty::TyVar(_)) => bug!("FIXME: ambiguous"), + + ty::Placeholder(..) + | ty::Bound(..) + | ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => bug!(), + + ty::Tuple(tys) => Ok(tys.to_vec()), + + ty::Adt(def, substs) => { + let sized_crit = def.sized_constraint(infcx.tcx); + Ok(sized_crit + .0 + .iter() + .map(|ty| sized_crit.rebind(*ty).subst(infcx.tcx, substs)) + .collect()) + } + } +} + +pub(super) fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>( + infcx: &InferCtxt<'tcx>, + ty: Ty<'tcx>, +) -> Result>, NoSolution> { + match *ty.kind() { + ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) + | ty::FnDef(..) + | ty::FnPtr(_) + | ty::Error(_) => Ok(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(..) => Err(NoSolution), + + ty::Dynamic(..) + | ty::Str + | ty::Slice(_) + | ty::Generator(_, _, Movability::Static) + | ty::Foreign(..) + | ty::Ref(_, _, Mutability::Mut) + | ty::Adt(_, _) + | ty::Alias(_, _) + | ty::Param(_) => Err(NoSolution), + + ty::Infer(ty::TyVar(_)) => bug!("FIXME: ambiguous"), + + ty::Placeholder(..) + | ty::Bound(..) + | ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => bug!(), + + ty::Tuple(tys) => Ok(tys.to_vec()), + + ty::Closure(_, substs) => Ok(vec![substs.as_closure().tupled_upvars_ty()]), + + ty::Generator(_, substs, Movability::Movable) => { + if infcx.tcx.features().generator_clone { + let generator = substs.as_generator(); + Ok(vec![generator.tupled_upvars_ty(), generator.witness()]) + } else { + Err(NoSolution) + } + } + + ty::GeneratorWitness(types) => { + Ok(infcx.replace_bound_vars_with_placeholders(types).to_vec()) + } + } +}