| //! Confirmation. | |
| //! | |
| //! Confirmation unifies the output type parameters of the trait | |
| //! with the values found in the obligation, possibly yielding a | |
| //! type error. See the [rustc dev guide] for more details. | |
| //! | |
| //! [rustc dev guide]: | |
| //! https://rustc-dev-guide.rust-lang.org/traits/resolution.html#confirmation | |
| use std::ops::ControlFlow; | |
| use rustc_data_structures::stack::ensure_sufficient_stack; | |
| use rustc_hir::lang_items::LangItem; | |
| use rustc_infer::infer::{BoundRegionConversionTime, DefineOpaqueTypes, InferOk}; | |
| use rustc_infer::traits::ObligationCauseCode; | |
| use rustc_middle::traits::{BuiltinImplSource, SignatureMismatchData}; | |
| use rustc_middle::ty::{ | |
| self, GenericArgsRef, Region, SizedTraitKind, Ty, TyCtxt, Unnormalized, Upcast, | |
| }; | |
| use rustc_middle::{bug, span_bug}; | |
| use rustc_span::def_id::DefId; | |
| use thin_vec::thin_vec; | |
| use tracing::{debug, instrument}; | |
| use super::SelectionCandidate::{self, *}; | |
| 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::{ | |
| ImplSource, ImplSourceUserDefinedData, Normalized, Obligation, ObligationCause, | |
| PolyTraitObligation, PredicateObligation, Selection, SelectionError, TraitObligation, | |
| }; | |
| impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { | |
| #[instrument(level = "debug", skip(self))] | |
| pub(super) fn confirm_candidate( | |
| &mut self, | |
| obligation: &PolyTraitObligation<'tcx>, | |
| candidate: SelectionCandidate<'tcx>, | |
| ) -> Result<Selection<'tcx>, SelectionError<'tcx>> { | |
| Ok(match candidate { | |
| SizedCandidate => { | |
| let data = self.confirm_builtin_candidate(obligation); | |
| ImplSource::Builtin(BuiltinImplSource::Misc, data) | |
| } | |
| BuiltinCandidate => { | |
| let data = self.confirm_builtin_candidate(obligation); | |
| ImplSource::Builtin(BuiltinImplSource::Misc, data) | |
| } | |
| TransmutabilityCandidate => { | |
| let data = self.confirm_transmutability_candidate(obligation)?; | |
| ImplSource::Builtin(BuiltinImplSource::Misc, data) | |
| } | |
| ParamCandidate(param) => { | |
| let obligations = | |
| self.confirm_param_candidate(obligation, param.map_bound(|t| t.trait_ref)); | |
| ImplSource::Param(obligations) | |
| } | |
| ImplCandidate(impl_def_id) => { | |
| ImplSource::UserDefined(self.confirm_impl_candidate(obligation, impl_def_id)) | |
| } | |
| AutoImplCandidate => { | |
| let data = self.confirm_auto_impl_candidate(obligation)?; | |
| ImplSource::Builtin(BuiltinImplSource::Misc, data) | |
| } | |
| ProjectionCandidate { idx, .. } => { | |
| let obligations = self.confirm_projection_candidate(obligation, idx)?; | |
| ImplSource::Param(obligations) | |
| } | |
| ObjectCandidate(idx) => self.confirm_object_candidate(obligation, idx)?, | |
| ClosureCandidate { .. } => { | |
| let vtable_closure = self.confirm_closure_candidate(obligation)?; | |
| ImplSource::Builtin(BuiltinImplSource::Misc, vtable_closure) | |
| } | |
| AsyncClosureCandidate => { | |
| let vtable_closure = self.confirm_async_closure_candidate(obligation)?; | |
| ImplSource::Builtin(BuiltinImplSource::Misc, vtable_closure) | |
| } | |
| // No nested obligations or confirmation process. The checks that we do in | |
| // candidate assembly are sufficient. | |
| AsyncFnKindHelperCandidate => { | |
| ImplSource::Builtin(BuiltinImplSource::Misc, PredicateObligations::new()) | |
| } | |
| CoroutineCandidate => { | |
| let vtable_coroutine = self.confirm_coroutine_candidate(obligation)?; | |
| ImplSource::Builtin(BuiltinImplSource::Misc, vtable_coroutine) | |
| } | |
| FutureCandidate => { | |
| let vtable_future = self.confirm_future_candidate(obligation)?; | |
| ImplSource::Builtin(BuiltinImplSource::Misc, vtable_future) | |
| } | |
| IteratorCandidate => { | |
| let vtable_iterator = self.confirm_iterator_candidate(obligation)?; | |
| ImplSource::Builtin(BuiltinImplSource::Misc, vtable_iterator) | |
| } | |
| AsyncIteratorCandidate => { | |
| let vtable_iterator = self.confirm_async_iterator_candidate(obligation)?; | |
| ImplSource::Builtin(BuiltinImplSource::Misc, vtable_iterator) | |
| } | |
| FnPointerCandidate => { | |
| let data = self.confirm_fn_pointer_candidate(obligation)?; | |
| ImplSource::Builtin(BuiltinImplSource::Misc, data) | |
| } | |
| TraitAliasCandidate => { | |
| let data = self.confirm_trait_alias_candidate(obligation); | |
| ImplSource::Builtin(BuiltinImplSource::Misc, data) | |
| } | |
| BuiltinObjectCandidate => { | |
| // This indicates something like `Trait + Send: Send`. In this case, we know that | |
| // this holds because that's what the object type is telling us, and there's really | |
| // no additional obligations to prove and no types in particular to unify, etc. | |
| ImplSource::Builtin(BuiltinImplSource::Misc, PredicateObligations::new()) | |
| } | |
| BuiltinUnsizeCandidate => self.confirm_builtin_unsize_candidate(obligation)?, | |
| TraitUpcastingUnsizeCandidate(idx) => { | |
| self.confirm_trait_upcasting_unsize_candidate(obligation, idx)? | |
| } | |
| BikeshedGuaranteedNoDropCandidate => { | |
| self.confirm_bikeshed_guaranteed_no_drop_candidate(obligation) | |
| } | |
| }) | |
| } | |
| fn confirm_projection_candidate( | |
| &mut self, | |
| obligation: &PolyTraitObligation<'tcx>, | |
| idx: usize, | |
| ) -> Result<PredicateObligations<'tcx>, SelectionError<'tcx>> { | |
| let placeholder_trait_predicate = | |
| self.infcx.enter_forall_and_leak_universe(obligation.predicate).trait_ref; | |
| let placeholder_self_ty = self.infcx.shallow_resolve(placeholder_trait_predicate.self_ty()); | |
| let candidate_predicate = self | |
| .for_each_item_bound( | |
| placeholder_self_ty, | |
| |_, clause, clause_idx, _| { | |
| if clause_idx == idx { | |
| ControlFlow::Break(clause) | |
| } else { | |
| ControlFlow::Continue(()) | |
| } | |
| }, | |
| || unreachable!(), | |
| ) | |
| .break_value() | |
| .expect("expected to index into clause that exists"); | |
| let candidate_predicate = candidate_predicate | |
| .as_trait_clause() | |
| .expect("projection candidate is not a trait predicate"); | |
| let candidate_predicate = | |
| util::lazily_elaborate_sizedness_candidate(self.infcx, obligation, candidate_predicate); | |
| let candidate = candidate_predicate.map_bound(|t| t.trait_ref); | |
| let candidate = self.infcx.instantiate_binder_with_fresh_vars( | |
| obligation.cause.span, | |
| BoundRegionConversionTime::HigherRankedType, | |
| candidate, | |
| ); | |
| let mut obligations = PredicateObligations::new(); | |
| let candidate = normalize_with_depth_to( | |
| self, | |
| obligation.param_env, | |
| obligation.cause.clone(), | |
| obligation.recursion_depth + 1, | |
| candidate, | |
| &mut obligations, | |
| ); | |
| obligations.extend( | |
| self.infcx | |
| .at(&obligation.cause, obligation.param_env) | |
| .eq(DefineOpaqueTypes::No, placeholder_trait_predicate, candidate) | |
| .map(|InferOk { obligations, .. }| obligations) | |
| .map_err(|_| SelectionError::Unimplemented)?, | |
| ); | |
| Ok(obligations) | |
| } | |
| fn confirm_param_candidate( | |
| &mut self, | |
| obligation: &PolyTraitObligation<'tcx>, | |
| param: ty::PolyTraitRef<'tcx>, | |
| ) -> PredicateObligations<'tcx> { | |
| debug!(?obligation, ?param, "confirm_param_candidate"); | |
| let param = util::lazily_elaborate_sizedness_candidate( | |
| self.infcx, | |
| obligation, | |
| param.upcast(self.infcx.tcx), | |
| ) | |
| .map_bound(|p| p.trait_ref); | |
| // During evaluation, we already checked that this | |
| // where-clause trait-ref could be unified with the obligation | |
| // trait-ref. Repeat that unification now without any | |
| // transactional boundary; it should not fail. | |
| match self.match_where_clause_trait_ref(obligation, param) { | |
| Ok(obligations) => obligations, | |
| Err(()) => { | |
| bug!( | |
| "Where clause `{:?}` was applicable to `{:?}` but now is not", | |
| param, | |
| obligation | |
| ); | |
| } | |
| } | |
| } | |
| #[instrument(level = "debug", skip(self), ret)] | |
| fn confirm_builtin_candidate( | |
| &mut self, | |
| obligation: &PolyTraitObligation<'tcx>, | |
| ) -> PredicateObligations<'tcx> { | |
| debug!(?obligation, "confirm_builtin_candidate"); | |
| let tcx = self.tcx(); | |
| let trait_def = obligation.predicate.def_id(); | |
| 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(self_ty, SizedTraitKind::MetaSized) | |
| } | |
| Some(LangItem::PointeeSized) => { | |
| bug!("`PointeeSized` is removing during lowering"); | |
| } | |
| Some(LangItem::Copy | LangItem::Clone | LangItem::TrivialClone) => { | |
| 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::Field | |
| | LangItem::FnPtrTrait | |
| | LangItem::PointeeTrait | |
| | LangItem::Tuple | |
| | LangItem::Unpin, | |
| ) => ty::Binder::dummy(vec![]), | |
| other => bug!("unexpected builtin trait {trait_def:?} ({other:?})"), | |
| }; | |
| let types = self.infcx.enter_forall_and_leak_universe(types); | |
| let cause = obligation.derived_cause(ObligationCauseCode::BuiltinDerived); | |
| self.collect_predicates_for_types( | |
| obligation.param_env, | |
| cause, | |
| obligation.recursion_depth + 1, | |
| trait_def, | |
| types, | |
| ) | |
| } | |
| #[instrument(level = "debug", skip(self))] | |
| fn confirm_transmutability_candidate( | |
| &mut self, | |
| obligation: &PolyTraitObligation<'tcx>, | |
| ) -> Result<PredicateObligations<'tcx>, SelectionError<'tcx>> { | |
| use rustc_transmute::{Answer, Assume, Condition}; | |
| /// Flatten the `Condition` tree into a conjunction of obligations. | |
| #[instrument(level = "debug", skip(tcx, obligation))] | |
| fn flatten_answer_tree<'tcx>( | |
| tcx: TyCtxt<'tcx>, | |
| obligation: &PolyTraitObligation<'tcx>, | |
| cond: Condition<Region<'tcx>, Ty<'tcx>>, | |
| assume: Assume, | |
| ) -> PredicateObligations<'tcx> { | |
| match cond { | |
| // FIXME(bryangarza): Add separate `IfAny` case, instead of treating as `IfAll` | |
| // Not possible until the trait solver supports disjunctions of obligations | |
| Condition::IfAll(conds) | Condition::IfAny(conds) => conds | |
| .into_iter() | |
| .flat_map(|cond| flatten_answer_tree(tcx, obligation, cond, assume)) | |
| .collect(), | |
| Condition::Immutable { ty } => { | |
| let trait_ref = ty::TraitRef::new( | |
| tcx, | |
| tcx.require_lang_item(LangItem::Freeze, obligation.cause.span), | |
| [ty::GenericArg::from(ty)], | |
| ); | |
| thin_vec![Obligation::with_depth( | |
| tcx, | |
| obligation.cause.clone(), | |
| obligation.recursion_depth + 1, | |
| obligation.param_env, | |
| trait_ref, | |
| )] | |
| } | |
| Condition::Outlives { long, short } => { | |
| let outlives = ty::OutlivesPredicate(long, short); | |
| thin_vec![Obligation::with_depth( | |
| tcx, | |
| obligation.cause.clone(), | |
| obligation.recursion_depth + 1, | |
| obligation.param_env, | |
| outlives, | |
| )] | |
| } | |
| Condition::Transmutable { src, dst } => { | |
| let transmute_trait = obligation.predicate.def_id(); | |
| let assume = obligation.predicate.skip_binder().trait_ref.args.const_at(2); | |
| let trait_ref = ty::TraitRef::new( | |
| tcx, | |
| transmute_trait, | |
| [ | |
| ty::GenericArg::from(dst), | |
| ty::GenericArg::from(src), | |
| ty::GenericArg::from(assume), | |
| ], | |
| ); | |
| thin_vec![Obligation::with_depth( | |
| tcx, | |
| obligation.cause.clone(), | |
| obligation.recursion_depth + 1, | |
| obligation.param_env, | |
| trait_ref, | |
| )] | |
| } | |
| } | |
| } | |
| let predicate = self.infcx.enter_forall_and_leak_universe(obligation.predicate); | |
| let mut assume = predicate.trait_ref.args.const_at(2); | |
| if self.tcx().features().generic_const_exprs() { | |
| assume = crate::traits::evaluate_const(self.infcx, assume, obligation.param_env) | |
| } | |
| let Some(assume) = rustc_transmute::Assume::from_const(self.infcx.tcx, assume) else { | |
| return Err(SelectionError::Unimplemented); | |
| }; | |
| let dst = predicate.trait_ref.args.type_at(0); | |
| let src = predicate.trait_ref.args.type_at(1); | |
| debug!(?src, ?dst); | |
| let mut transmute_env = rustc_transmute::TransmuteTypeEnv::new(self.infcx.tcx); | |
| let maybe_transmutable = transmute_env.is_transmutable(src, dst, assume); | |
| let fully_flattened = match maybe_transmutable { | |
| Answer::No(_) => Err(SelectionError::Unimplemented)?, | |
| Answer::If(cond) => flatten_answer_tree(self.tcx(), obligation, cond, assume), | |
| Answer::Yes => PredicateObligations::new(), | |
| }; | |
| debug!(?fully_flattened); | |
| Ok(fully_flattened) | |
| } | |
| /// This handles the case where an `auto trait Foo` impl is being used. | |
| /// The idea is that the impl applies to `X : Foo` if the following conditions are met: | |
| /// | |
| /// 1. For each constituent type `Y` in `X`, `Y : Foo` holds | |
| /// 2. For each where-clause `C` declared on `Foo`, `[Self => X] C` holds. | |
| fn confirm_auto_impl_candidate( | |
| &mut self, | |
| obligation: &PolyTraitObligation<'tcx>, | |
| ) -> Result<PredicateObligations<'tcx>, SelectionError<'tcx>> { | |
| ensure_sufficient_stack(|| { | |
| assert_eq!(obligation.predicate.polarity(), ty::PredicatePolarity::Positive); | |
| 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 constituents = self.constituent_types_for_auto_trait(self_ty)?; | |
| let constituents = self.infcx.enter_forall_and_leak_universe(constituents); | |
| let cause = obligation.derived_cause(ObligationCauseCode::BuiltinDerived); | |
| let mut obligations = self.collect_predicates_for_types( | |
| obligation.param_env, | |
| cause.clone(), | |
| obligation.recursion_depth + 1, | |
| obligation.predicate.def_id(), | |
| constituents.types, | |
| ); | |
| // Only normalize these goals if `-Zhigher-ranked-assumptions` is enabled, since | |
| // we don't want to cause ourselves to do extra work if we're not even able to | |
| // take advantage of these assumption clauses. | |
| if self.tcx().sess.opts.unstable_opts.higher_ranked_assumptions { | |
| // FIXME(coroutine_clone): We could uplift this into `collect_predicates_for_types` | |
| // and do this for `Copy`/`Clone` too, but that's feature-gated so it doesn't really | |
| // matter yet. | |
| for assumption in constituents.assumptions { | |
| let assumption = normalize_with_depth_to( | |
| self, | |
| obligation.param_env, | |
| cause.clone(), | |
| obligation.recursion_depth + 1, | |
| assumption, | |
| &mut obligations, | |
| ); | |
| self.infcx.register_region_assumption(assumption); | |
| } | |
| } | |
| Ok(obligations) | |
| }) | |
| } | |
| fn confirm_impl_candidate( | |
| &mut self, | |
| obligation: &PolyTraitObligation<'tcx>, | |
| impl_def_id: DefId, | |
| ) -> ImplSourceUserDefinedData<'tcx, PredicateObligation<'tcx>> { | |
| debug!(?obligation, ?impl_def_id, "confirm_impl_candidate"); | |
| // First, create the generic parameters by matching the impl again, | |
| // this time not in a probe. | |
| let args = self.rematch_impl(impl_def_id, obligation); | |
| debug!(?args, "impl args"); | |
| ensure_sufficient_stack(|| { | |
| self.vtable_impl( | |
| impl_def_id, | |
| args, | |
| &obligation.cause, | |
| obligation.recursion_depth + 1, | |
| obligation.param_env, | |
| obligation.predicate, | |
| ) | |
| }) | |
| } | |
| fn vtable_impl( | |
| &mut self, | |
| impl_def_id: DefId, | |
| args: Normalized<'tcx, GenericArgsRef<'tcx>>, | |
| cause: &ObligationCause<'tcx>, | |
| recursion_depth: usize, | |
| param_env: ty::ParamEnv<'tcx>, | |
| parent_trait_pred: ty::Binder<'tcx, ty::TraitPredicate<'tcx>>, | |
| ) -> ImplSourceUserDefinedData<'tcx, PredicateObligation<'tcx>> { | |
| debug!(?impl_def_id, ?args, ?recursion_depth, "vtable_impl"); | |
| let mut impl_obligations = self.impl_or_trait_obligations( | |
| cause, | |
| recursion_depth, | |
| param_env, | |
| impl_def_id, | |
| args.value, | |
| parent_trait_pred, | |
| ); | |
| debug!(?impl_obligations, "vtable_impl"); | |
| // Because of RFC447, the impl-trait-ref and obligations | |
| // are sufficient to determine the impl args, without | |
| // relying on projections in the impl-trait-ref. | |
| // | |
| // e.g., `impl<U: Tr, V: Iterator<Item=U>> Foo<<U as Tr>::T> for V` | |
| impl_obligations.extend(args.obligations); | |
| ImplSourceUserDefinedData { impl_def_id, args: args.value, nested: impl_obligations } | |
| } | |
| fn confirm_object_candidate( | |
| &mut self, | |
| obligation: &PolyTraitObligation<'tcx>, | |
| index: usize, | |
| ) -> Result<ImplSource<'tcx, PredicateObligation<'tcx>>, SelectionError<'tcx>> { | |
| let tcx = self.tcx(); | |
| debug!(?obligation, ?index, "confirm_object_candidate"); | |
| let trait_predicate = self.infcx.enter_forall_and_leak_universe(obligation.predicate); | |
| let self_ty = self.infcx.shallow_resolve(trait_predicate.self_ty()); | |
| let ty::Dynamic(data, ..) = *self_ty.kind() else { | |
| span_bug!(obligation.cause.span, "object candidate with non-object"); | |
| }; | |
| let object_trait_ref = data.principal().unwrap_or_else(|| { | |
| span_bug!(obligation.cause.span, "object candidate with no principal") | |
| }); | |
| let object_trait_ref = self.infcx.instantiate_binder_with_fresh_vars( | |
| obligation.cause.span, | |
| BoundRegionConversionTime::HigherRankedType, | |
| object_trait_ref, | |
| ); | |
| let object_trait_ref = object_trait_ref.with_self_ty(self.tcx(), self_ty); | |
| let mut nested = PredicateObligations::new(); | |
| let mut supertraits = util::supertraits(tcx, ty::Binder::dummy(object_trait_ref)); | |
| let unnormalized_upcast_trait_ref = | |
| supertraits.nth(index).expect("supertraits iterator no longer has as many elements"); | |
| let upcast_trait_ref = self.infcx.instantiate_binder_with_fresh_vars( | |
| obligation.cause.span, | |
| BoundRegionConversionTime::HigherRankedType, | |
| unnormalized_upcast_trait_ref, | |
| ); | |
| let upcast_trait_ref = normalize_with_depth_to( | |
| self, | |
| obligation.param_env, | |
| obligation.cause.clone(), | |
| obligation.recursion_depth + 1, | |
| upcast_trait_ref, | |
| &mut nested, | |
| ); | |
| nested.extend( | |
| self.infcx | |
| .at(&obligation.cause, obligation.param_env) | |
| .eq(DefineOpaqueTypes::No, trait_predicate.trait_ref, upcast_trait_ref) | |
| .map(|InferOk { obligations, .. }| obligations) | |
| .map_err(|_| SelectionError::Unimplemented)?, | |
| ); | |
| // Check supertraits hold. This is so that their associated type bounds | |
| // will be checked in the code below. | |
| for (supertrait, _) in tcx | |
| .explicit_super_predicates_of(trait_predicate.def_id()) | |
| .iter_instantiated_copied(tcx, trait_predicate.trait_ref.args) | |
| .map(Unnormalized::skip_norm_wip) | |
| { | |
| let normalized_supertrait = normalize_with_depth_to( | |
| self, | |
| obligation.param_env, | |
| obligation.cause.clone(), | |
| obligation.recursion_depth + 1, | |
| supertrait, | |
| &mut nested, | |
| ); | |
| nested.push(obligation.with(tcx, normalized_supertrait)); | |
| } | |
| let assoc_types: Vec<_> = tcx | |
| .associated_items(trait_predicate.def_id()) | |
| .in_definition_order() | |
| // Associated types that require `Self: Sized` do not show up in the built-in | |
| // implementation of `Trait for dyn Trait`, and can be dropped here. | |
| .filter(|item| !tcx.generics_require_sized_self(item.def_id)) | |
| .filter_map(|item| if item.is_type() { Some(item.def_id) } else { None }) | |
| .collect(); | |
| for assoc_type in assoc_types { | |
| let defs: &ty::Generics = tcx.generics_of(assoc_type); | |
| if !defs.own_params.is_empty() { | |
| tcx.dcx().span_delayed_bug( | |
| obligation.cause.span, | |
| "GATs in trait object shouldn't have been considered", | |
| ); | |
| return Err(SelectionError::TraitDynIncompatible(trait_predicate.trait_ref.def_id)); | |
| } | |
| // This maybe belongs in wf, but that can't (doesn't) handle | |
| // higher-ranked things. | |
| // Prevent, e.g., `dyn Iterator<Item = str>`. | |
| for bound in self.tcx().item_bounds(assoc_type).transpose_iter() { | |
| let normalized_bound = normalize_with_depth_to( | |
| self, | |
| obligation.param_env, | |
| obligation.cause.clone(), | |
| obligation.recursion_depth + 1, | |
| bound.instantiate(tcx, trait_predicate.trait_ref.args).skip_norm_wip(), | |
| &mut nested, | |
| ); | |
| nested.push(obligation.with(tcx, normalized_bound)); | |
| } | |
| } | |
| debug!(?nested, "object nested obligations"); | |
| Ok(ImplSource::Builtin(BuiltinImplSource::Object(index), nested)) | |
| } | |
| fn confirm_fn_pointer_candidate( | |
| &mut self, | |
| obligation: &PolyTraitObligation<'tcx>, | |
| ) -> Result<PredicateObligations<'tcx>, SelectionError<'tcx>> { | |
| debug!(?obligation, "confirm_fn_pointer_candidate"); | |
| let placeholder_predicate = self.infcx.enter_forall_and_leak_universe(obligation.predicate); | |
| let self_ty = self.infcx.shallow_resolve(placeholder_predicate.self_ty()); | |
| let tcx = self.tcx(); | |
| let sig = self_ty.fn_sig(tcx); | |
| let trait_ref = closure_trait_ref_and_return_type( | |
| tcx, | |
| obligation.predicate.def_id(), | |
| self_ty, | |
| sig, | |
| util::TupleArgumentsFlag::Yes, | |
| ) | |
| .map_bound(|(trait_ref, _)| trait_ref); | |
| let mut nested = | |
| self.equate_trait_refs(obligation.with(tcx, placeholder_predicate), trait_ref)?; | |
| let cause = obligation.derived_cause(ObligationCauseCode::BuiltinDerived); | |
| // Confirm the `type Output: Sized;` bound that is present on `FnOnce` | |
| let output_ty = self.infcx.enter_forall_and_leak_universe(sig.output()); | |
| let output_ty = normalize_with_depth_to( | |
| self, | |
| obligation.param_env, | |
| cause.clone(), | |
| obligation.recursion_depth, | |
| output_ty, | |
| &mut nested, | |
| ); | |
| let tr = ty::TraitRef::new( | |
| self.tcx(), | |
| self.tcx().require_lang_item(LangItem::Sized, cause.span), | |
| [output_ty], | |
| ); | |
| nested.push(Obligation::new(self.infcx.tcx, cause, obligation.param_env, tr)); | |
| Ok(nested) | |
| } | |
| fn confirm_trait_alias_candidate( | |
| &mut self, | |
| obligation: &PolyTraitObligation<'tcx>, | |
| ) -> PredicateObligations<'tcx> { | |
| debug!(?obligation, "confirm_trait_alias_candidate"); | |
| let predicate = self.infcx.enter_forall_and_leak_universe(obligation.predicate); | |
| let trait_ref = predicate.trait_ref; | |
| let trait_def_id = trait_ref.def_id; | |
| let args = trait_ref.args; | |
| let trait_obligations = self.impl_or_trait_obligations( | |
| &obligation.cause, | |
| obligation.recursion_depth, | |
| obligation.param_env, | |
| trait_def_id, | |
| args, | |
| obligation.predicate, | |
| ); | |
| debug!(?trait_def_id, ?trait_obligations, "trait alias obligations"); | |
| trait_obligations | |
| } | |
| fn confirm_coroutine_candidate( | |
| &mut self, | |
| obligation: &PolyTraitObligation<'tcx>, | |
| ) -> Result<PredicateObligations<'tcx>, SelectionError<'tcx>> { | |
| let placeholder_predicate = self.infcx.enter_forall_and_leak_universe(obligation.predicate); | |
| let self_ty = self.infcx.shallow_resolve(placeholder_predicate.self_ty()); | |
| let ty::Coroutine(coroutine_def_id, args) = *self_ty.kind() else { | |
| bug!("closure candidate for non-closure {:?}", obligation); | |
| }; | |
| debug!(?obligation, ?coroutine_def_id, ?args, "confirm_coroutine_candidate"); | |
| let coroutine_sig = args.as_coroutine().sig(); | |
| let (trait_ref, _, _) = super::util::coroutine_trait_ref_and_outputs( | |
| self.tcx(), | |
| obligation.predicate.def_id(), | |
| self_ty, | |
| coroutine_sig, | |
| ); | |
| let nested = self.equate_trait_refs( | |
| obligation.with(self.tcx(), placeholder_predicate), | |
| ty::Binder::dummy(trait_ref), | |
| )?; | |
| debug!(?trait_ref, ?nested, "coroutine candidate obligations"); | |
| Ok(nested) | |
| } | |
| fn confirm_future_candidate( | |
| &mut self, | |
| obligation: &PolyTraitObligation<'tcx>, | |
| ) -> Result<PredicateObligations<'tcx>, SelectionError<'tcx>> { | |
| let placeholder_predicate = self.infcx.enter_forall_and_leak_universe(obligation.predicate); | |
| let self_ty = self.infcx.shallow_resolve(placeholder_predicate.self_ty()); | |
| let ty::Coroutine(coroutine_def_id, args) = *self_ty.kind() else { | |
| bug!("closure candidate for non-closure {:?}", obligation); | |
| }; | |
| debug!(?obligation, ?coroutine_def_id, ?args, "confirm_future_candidate"); | |
| let coroutine_sig = args.as_coroutine().sig(); | |
| let (trait_ref, _) = super::util::future_trait_ref_and_outputs( | |
| self.tcx(), | |
| obligation.predicate.def_id(), | |
| self_ty, | |
| coroutine_sig, | |
| ); | |
| let nested = self.equate_trait_refs( | |
| obligation.with(self.tcx(), placeholder_predicate), | |
| ty::Binder::dummy(trait_ref), | |
| )?; | |
| debug!(?trait_ref, ?nested, "future candidate obligations"); | |
| Ok(nested) | |
| } | |
| fn confirm_iterator_candidate( | |
| &mut self, | |
| obligation: &PolyTraitObligation<'tcx>, | |
| ) -> Result<PredicateObligations<'tcx>, SelectionError<'tcx>> { | |
| let placeholder_predicate = self.infcx.enter_forall_and_leak_universe(obligation.predicate); | |
| let self_ty = self.infcx.shallow_resolve(placeholder_predicate.self_ty()); | |
| let ty::Coroutine(coroutine_def_id, args) = *self_ty.kind() else { | |
| bug!("closure candidate for non-closure {:?}", obligation); | |
| }; | |
| debug!(?obligation, ?coroutine_def_id, ?args, "confirm_iterator_candidate"); | |
| let gen_sig = args.as_coroutine().sig(); | |
| let (trait_ref, _) = super::util::iterator_trait_ref_and_outputs( | |
| self.tcx(), | |
| obligation.predicate.def_id(), | |
| self_ty, | |
| gen_sig, | |
| ); | |
| let nested = self.equate_trait_refs( | |
| obligation.with(self.tcx(), placeholder_predicate), | |
| ty::Binder::dummy(trait_ref), | |
| )?; | |
| debug!(?trait_ref, ?nested, "iterator candidate obligations"); | |
| Ok(nested) | |
| } | |
| fn confirm_async_iterator_candidate( | |
| &mut self, | |
| obligation: &PolyTraitObligation<'tcx>, | |
| ) -> Result<PredicateObligations<'tcx>, SelectionError<'tcx>> { | |
| let placeholder_predicate = self.infcx.enter_forall_and_leak_universe(obligation.predicate); | |
| let self_ty = self.infcx.shallow_resolve(placeholder_predicate.self_ty()); | |
| let ty::Coroutine(coroutine_def_id, args) = *self_ty.kind() else { | |
| bug!("closure candidate for non-closure {:?}", obligation); | |
| }; | |
| debug!(?obligation, ?coroutine_def_id, ?args, "confirm_async_iterator_candidate"); | |
| let gen_sig = args.as_coroutine().sig(); | |
| let (trait_ref, _) = super::util::async_iterator_trait_ref_and_outputs( | |
| self.tcx(), | |
| obligation.predicate.def_id(), | |
| self_ty, | |
| gen_sig, | |
| ); | |
| let nested = self.equate_trait_refs( | |
| obligation.with(self.tcx(), placeholder_predicate), | |
| ty::Binder::dummy(trait_ref), | |
| )?; | |
| debug!(?trait_ref, ?nested, "iterator candidate obligations"); | |
| Ok(nested) | |
| } | |
| #[instrument(skip(self), level = "debug")] | |
| fn confirm_closure_candidate( | |
| &mut self, | |
| obligation: &PolyTraitObligation<'tcx>, | |
| ) -> Result<PredicateObligations<'tcx>, SelectionError<'tcx>> { | |
| let placeholder_predicate = self.infcx.enter_forall_and_leak_universe(obligation.predicate); | |
| let self_ty: Ty<'_> = self.infcx.shallow_resolve(placeholder_predicate.self_ty()); | |
| let trait_ref = match *self_ty.kind() { | |
| ty::Closure(..) => { | |
| self.closure_trait_ref_unnormalized(self_ty, obligation.predicate.def_id()) | |
| } | |
| ty::CoroutineClosure(_, args) => { | |
| args.as_coroutine_closure().coroutine_closure_sig().map_bound(|sig| { | |
| ty::TraitRef::new( | |
| self.tcx(), | |
| obligation.predicate.def_id(), | |
| [self_ty, sig.tupled_inputs_ty], | |
| ) | |
| }) | |
| } | |
| _ => { | |
| bug!("closure candidate for non-closure {:?}", obligation); | |
| } | |
| }; | |
| self.equate_trait_refs(obligation.with(self.tcx(), placeholder_predicate), trait_ref) | |
| } | |
| #[instrument(skip(self), level = "debug")] | |
| fn confirm_async_closure_candidate( | |
| &mut self, | |
| obligation: &PolyTraitObligation<'tcx>, | |
| ) -> Result<PredicateObligations<'tcx>, SelectionError<'tcx>> { | |
| let placeholder_predicate = self.infcx.enter_forall_and_leak_universe(obligation.predicate); | |
| let self_ty = self.infcx.shallow_resolve(placeholder_predicate.self_ty()); | |
| let tcx = self.tcx(); | |
| let mut nested = PredicateObligations::new(); | |
| let (trait_ref, kind_ty) = match *self_ty.kind() { | |
| ty::CoroutineClosure(_, args) => { | |
| let args = args.as_coroutine_closure(); | |
| let trait_ref = args.coroutine_closure_sig().map_bound(|sig| { | |
| ty::TraitRef::new( | |
| self.tcx(), | |
| obligation.predicate.def_id(), | |
| [self_ty, sig.tupled_inputs_ty], | |
| ) | |
| }); | |
| // Note that unlike below, we don't need to check `Future + Sized` for | |
| // the output coroutine because they are `Future + Sized` by construction. | |
| (trait_ref, args.kind_ty()) | |
| } | |
| ty::FnDef(..) | ty::FnPtr(..) => { | |
| let sig = self_ty.fn_sig(tcx); | |
| let trait_ref = sig.map_bound(|sig| { | |
| ty::TraitRef::new( | |
| self.tcx(), | |
| obligation.predicate.def_id(), | |
| [self_ty, Ty::new_tup(tcx, sig.inputs())], | |
| ) | |
| }); | |
| // We must additionally check that the return type impls `Future + Sized`. | |
| let future_trait_def_id = | |
| tcx.require_lang_item(LangItem::Future, obligation.cause.span); | |
| nested.push(obligation.with( | |
| tcx, | |
| sig.output().map_bound(|output_ty| { | |
| ty::TraitRef::new(tcx, future_trait_def_id, [output_ty]) | |
| }), | |
| )); | |
| let sized_trait_def_id = | |
| tcx.require_lang_item(LangItem::Sized, obligation.cause.span); | |
| nested.push(obligation.with( | |
| tcx, | |
| sig.output().map_bound(|output_ty| { | |
| ty::TraitRef::new(tcx, sized_trait_def_id, [output_ty]) | |
| }), | |
| )); | |
| (trait_ref, Ty::from_closure_kind(tcx, ty::ClosureKind::Fn)) | |
| } | |
| ty::Closure(_, args) => { | |
| let args = args.as_closure(); | |
| let sig = args.sig(); | |
| let trait_ref = sig.map_bound(|sig| { | |
| ty::TraitRef::new( | |
| self.tcx(), | |
| obligation.predicate.def_id(), | |
| [self_ty, sig.inputs()[0]], | |
| ) | |
| }); | |
| // We must additionally check that the return type impls `Future + Sized`. | |
| let future_trait_def_id = | |
| tcx.require_lang_item(LangItem::Future, obligation.cause.span); | |
| let placeholder_output_ty = self.infcx.enter_forall_and_leak_universe(sig.output()); | |
| nested.push(obligation.with( | |
| tcx, | |
| ty::TraitRef::new(tcx, future_trait_def_id, [placeholder_output_ty]), | |
| )); | |
| let sized_trait_def_id = | |
| tcx.require_lang_item(LangItem::Sized, obligation.cause.span); | |
| nested.push(obligation.with( | |
| tcx, | |
| sig.output().map_bound(|output_ty| { | |
| ty::TraitRef::new(tcx, sized_trait_def_id, [output_ty]) | |
| }), | |
| )); | |
| (trait_ref, args.kind_ty()) | |
| } | |
| _ => bug!("expected callable type for AsyncFn candidate"), | |
| }; | |
| nested.extend( | |
| self.equate_trait_refs(obligation.with(tcx, placeholder_predicate), trait_ref)?, | |
| ); | |
| let goal_kind = | |
| self.tcx().async_fn_trait_kind_from_def_id(obligation.predicate.def_id()).unwrap(); | |
| // If we have not yet determined the `ClosureKind` of the closure or coroutine-closure, | |
| // then additionally register an `AsyncFnKindHelper` goal which will fail if the kind | |
| // is constrained to an insufficient type later on. | |
| if let Some(closure_kind) = self.infcx.shallow_resolve(kind_ty).to_opt_closure_kind() { | |
| if !closure_kind.extends(goal_kind) { | |
| return Err(SelectionError::Unimplemented); | |
| } | |
| } else { | |
| nested.push(Obligation::new( | |
| self.tcx(), | |
| obligation.derived_cause(ObligationCauseCode::BuiltinDerived), | |
| obligation.param_env, | |
| ty::TraitRef::new( | |
| self.tcx(), | |
| self.tcx() | |
| .require_lang_item(LangItem::AsyncFnKindHelper, obligation.cause.span), | |
| [kind_ty, Ty::from_closure_kind(self.tcx(), goal_kind)], | |
| ), | |
| )); | |
| } | |
| Ok(nested) | |
| } | |
| /// In the case of closure types and fn pointers, | |
| /// we currently treat the input type parameters on the trait as | |
| /// outputs. This means that when we have a match we have only | |
| /// considered the self type, so we have to go back and make sure | |
| /// to relate the argument types too. This is kind of wrong, but | |
| /// since we control the full set of impls, also not that wrong, | |
| /// and it DOES yield better error messages (since we don't report | |
| /// errors as if there is no applicable impl, but rather report | |
| /// errors are about mismatched argument types. | |
| /// | |
| /// Here is an example. Imagine we have a closure expression | |
| /// and we desugared it so that the type of the expression is | |
| /// `Closure`, and `Closure` expects `i32` as argument. Then it | |
| /// is "as if" the compiler generated this impl: | |
| /// ```ignore (illustrative) | |
| /// impl Fn(i32) for Closure { ... } | |
| /// ``` | |
| /// Now imagine our obligation is `Closure: Fn(usize)`. So far | |
| /// we have matched the self type `Closure`. At this point we'll | |
| /// compare the `i32` to `usize` and generate an error. | |
| /// | |
| /// Note that this checking occurs *after* the impl has selected, | |
| /// because these output type parameters should not affect the | |
| /// selection of the impl. Therefore, if there is a mismatch, we | |
| /// report an error to the user. | |
| #[instrument(skip(self), level = "trace")] | |
| fn equate_trait_refs( | |
| &mut self, | |
| obligation: TraitObligation<'tcx>, | |
| found_trait_ref: ty::PolyTraitRef<'tcx>, | |
| ) -> Result<PredicateObligations<'tcx>, SelectionError<'tcx>> { | |
| let found_trait_ref = self.infcx.instantiate_binder_with_fresh_vars( | |
| obligation.cause.span, | |
| BoundRegionConversionTime::HigherRankedType, | |
| found_trait_ref, | |
| ); | |
| // Normalize the obligation and expected trait refs together, because why not | |
| let Normalized { obligations: nested, value: (obligation_trait_ref, found_trait_ref) } = | |
| ensure_sufficient_stack(|| { | |
| normalize_with_depth( | |
| self, | |
| obligation.param_env, | |
| obligation.cause.clone(), | |
| obligation.recursion_depth + 1, | |
| (obligation.predicate.trait_ref, found_trait_ref), | |
| ) | |
| }); | |
| // needed to define opaque types for tests/ui/type-alias-impl-trait/assoc-projection-ice.rs | |
| self.infcx | |
| .at(&obligation.cause, obligation.param_env) | |
| .eq(DefineOpaqueTypes::Yes, obligation_trait_ref, found_trait_ref) | |
| .map(|InferOk { mut obligations, .. }| { | |
| obligations.extend(nested); | |
| obligations | |
| }) | |
| .map_err(|terr| { | |
| SelectionError::SignatureMismatch(Box::new(SignatureMismatchData { | |
| expected_trait_ref: obligation_trait_ref, | |
| found_trait_ref, | |
| terr, | |
| })) | |
| }) | |
| } | |
| fn confirm_trait_upcasting_unsize_candidate( | |
| &mut self, | |
| obligation: &PolyTraitObligation<'tcx>, | |
| idx: usize, | |
| ) -> Result<ImplSource<'tcx, PredicateObligation<'tcx>>, SelectionError<'tcx>> { | |
| let tcx = self.tcx(); | |
| // `assemble_candidates_for_unsizing` should ensure there are no late-bound | |
| // regions here. See the comment there for more details. | |
| let predicate = obligation.predicate.no_bound_vars().unwrap(); | |
| let a_ty = self.infcx.shallow_resolve(predicate.self_ty()); | |
| let b_ty = self.infcx.shallow_resolve(predicate.trait_ref.args.type_at(1)); | |
| let ty::Dynamic(a_data, a_region) = *a_ty.kind() else { | |
| bug!("expected `dyn` type in `confirm_trait_upcasting_unsize_candidate`") | |
| }; | |
| let ty::Dynamic(b_data, b_region) = *b_ty.kind() else { | |
| bug!("expected `dyn` type in `confirm_trait_upcasting_unsize_candidate`") | |
| }; | |
| let source_principal = a_data.principal().unwrap().with_self_ty(tcx, a_ty); | |
| let unnormalized_upcast_principal = | |
| util::supertraits(tcx, source_principal).nth(idx).unwrap(); | |
| let nested = self | |
| .match_upcast_principal( | |
| obligation, | |
| unnormalized_upcast_principal, | |
| a_data, | |
| b_data, | |
| a_region, | |
| b_region, | |
| )? | |
| .expect("did not expect ambiguity during confirmation"); | |
| Ok(ImplSource::Builtin(BuiltinImplSource::TraitUpcasting(idx), nested)) | |
| } | |
| fn confirm_builtin_unsize_candidate( | |
| &mut self, | |
| obligation: &PolyTraitObligation<'tcx>, | |
| ) -> Result<ImplSource<'tcx, PredicateObligation<'tcx>>, SelectionError<'tcx>> { | |
| let tcx = self.tcx(); | |
| // `assemble_candidates_for_unsizing` should ensure there are no late-bound | |
| // regions here. See the comment there for more details. | |
| let source = self.infcx.shallow_resolve(obligation.self_ty().no_bound_vars().unwrap()); | |
| let target = obligation.predicate.skip_binder().trait_ref.args.type_at(1); | |
| let target = self.infcx.shallow_resolve(target); | |
| debug!(?source, ?target, "confirm_builtin_unsize_candidate"); | |
| Ok(match (source.kind(), target.kind()) { | |
| // `dyn Trait + Kx + 'a` -> `dyn Trait + Ky + 'b` (auto traits and lifetime subtyping). | |
| (&ty::Dynamic(data_a, r_a), &ty::Dynamic(data_b, r_b)) => { | |
| // See `assemble_candidates_for_unsizing` for more info. | |
| // We already checked the compatibility of auto traits within `assemble_candidates_for_unsizing`. | |
| let existential_predicates = if data_b.principal().is_some() { | |
| tcx.mk_poly_existential_predicates_from_iter( | |
| data_a | |
| .principal() | |
| .map(|b| b.map_bound(ty::ExistentialPredicate::Trait)) | |
| .into_iter() | |
| .chain( | |
| data_a | |
| .projection_bounds() | |
| .map(|b| b.map_bound(ty::ExistentialPredicate::Projection)), | |
| ) | |
| .chain( | |
| data_b | |
| .auto_traits() | |
| .map(ty::ExistentialPredicate::AutoTrait) | |
| .map(ty::Binder::dummy), | |
| ), | |
| ) | |
| } else { | |
| // If we're unsizing to a dyn type that has no principal, then drop | |
| // the principal and projections from the type. We use the auto traits | |
| // from the RHS type since as we noted that we've checked for auto | |
| // trait compatibility during unsizing. | |
| tcx.mk_poly_existential_predicates_from_iter( | |
| data_b | |
| .auto_traits() | |
| .map(ty::ExistentialPredicate::AutoTrait) | |
| .map(ty::Binder::dummy), | |
| ) | |
| }; | |
| let source_trait = Ty::new_dynamic(tcx, existential_predicates, r_b); | |
| // Require that the traits involved in this upcast are **equal**; | |
| // only the **lifetime bound** is changed. | |
| let InferOk { mut obligations, .. } = self | |
| .infcx | |
| .at(&obligation.cause, obligation.param_env) | |
| .sup(DefineOpaqueTypes::Yes, target, source_trait) | |
| .map_err(|_| SelectionError::Unimplemented)?; | |
| // Register one obligation for 'a: 'b. | |
| let outlives = ty::OutlivesPredicate(r_a, r_b); | |
| obligations.push(Obligation::with_depth( | |
| tcx, | |
| obligation.cause.clone(), | |
| obligation.recursion_depth + 1, | |
| obligation.param_env, | |
| obligation.predicate.rebind(outlives), | |
| )); | |
| ImplSource::Builtin(BuiltinImplSource::Misc, obligations) | |
| } | |
| // `T` -> `dyn Trait` | |
| (_, &ty::Dynamic(data, r)) => { | |
| let mut object_dids = data.auto_traits().chain(data.principal_def_id()); | |
| if let Some(did) = object_dids.find(|did| !tcx.is_dyn_compatible(*did)) { | |
| return Err(SelectionError::TraitDynIncompatible(did)); | |
| } | |
| let predicate_to_obligation = |predicate| { | |
| Obligation::with_depth( | |
| tcx, | |
| obligation.cause.clone(), | |
| obligation.recursion_depth + 1, | |
| obligation.param_env, | |
| predicate, | |
| ) | |
| }; | |
| // Create obligations: | |
| // - Casting `T` to `Trait` | |
| // - For all the various builtin bounds attached to the object cast. (In other | |
| // words, if the object type is `Foo + Send`, this would create an obligation for | |
| // the `Send` check.) | |
| // - Projection predicates | |
| let mut nested: PredicateObligations<'_> = data | |
| .iter() | |
| .map(|predicate| predicate_to_obligation(predicate.with_self_ty(tcx, source))) | |
| .collect(); | |
| // We can only make objects from sized types. | |
| let tr = ty::TraitRef::new( | |
| tcx, | |
| tcx.require_lang_item(LangItem::Sized, obligation.cause.span), | |
| [source], | |
| ); | |
| nested.push(predicate_to_obligation(tr.upcast(tcx))); | |
| // If the type is `Foo + 'a`, ensure that the type | |
| // being cast to `Foo + 'a` outlives `'a`: | |
| let outlives = ty::OutlivesPredicate(source, r); | |
| nested.push(predicate_to_obligation( | |
| ty::ClauseKind::TypeOutlives(outlives).upcast(tcx), | |
| )); | |
| ImplSource::Builtin(BuiltinImplSource::Misc, nested) | |
| } | |
| // `[T; n]` -> `[T]` | |
| (&ty::Array(a, _), &ty::Slice(b)) => { | |
| let InferOk { obligations, .. } = self | |
| .infcx | |
| .at(&obligation.cause, obligation.param_env) | |
| .eq(DefineOpaqueTypes::Yes, b, a) | |
| .map_err(|_| SelectionError::Unimplemented)?; | |
| ImplSource::Builtin(BuiltinImplSource::Misc, obligations) | |
| } | |
| // `Struct<T>` -> `Struct<U>` | |
| (&ty::Adt(def, args_a), &ty::Adt(_, args_b)) => { | |
| let unsizing_params = tcx.unsizing_params_for_adt(def.did()); | |
| if unsizing_params.is_empty() { | |
| return Err(SelectionError::Unimplemented); | |
| } | |
| let tail_field = def.non_enum_variant().tail(); | |
| let tail_field_ty = tcx.type_of(tail_field.did); | |
| let mut nested = PredicateObligations::new(); | |
| // Extract `TailField<T>` and `TailField<U>` from `Struct<T>` and `Struct<U>`, | |
| // normalizing in the process, since `type_of` returns something directly from | |
| // HIR ty lowering (which means it's un-normalized). | |
| let source_tail = normalize_with_depth_to( | |
| self, | |
| obligation.param_env, | |
| obligation.cause.clone(), | |
| obligation.recursion_depth + 1, | |
| tail_field_ty.instantiate(tcx, args_a).skip_norm_wip(), | |
| &mut nested, | |
| ); | |
| let target_tail = normalize_with_depth_to( | |
| self, | |
| obligation.param_env, | |
| obligation.cause.clone(), | |
| obligation.recursion_depth + 1, | |
| tail_field_ty.instantiate(tcx, args_b).skip_norm_wip(), | |
| &mut nested, | |
| ); | |
| // Check that the source struct with the target's | |
| // unsizing parameters is equal to the target. | |
| let args = | |
| tcx.mk_args_from_iter(args_a.iter().enumerate().map(|(i, k)| { | |
| if unsizing_params.contains(i as u32) { args_b[i] } else { k } | |
| })); | |
| let new_struct = Ty::new_adt(tcx, def, args); | |
| let InferOk { obligations, .. } = self | |
| .infcx | |
| .at(&obligation.cause, obligation.param_env) | |
| .eq(DefineOpaqueTypes::Yes, target, new_struct) | |
| .map_err(|_| SelectionError::Unimplemented)?; | |
| nested.extend(obligations); | |
| // Construct the nested `TailField<T>: Unsize<TailField<U>>` predicate. | |
| let tail_unsize_obligation = obligation.with( | |
| tcx, | |
| ty::TraitRef::new( | |
| tcx, | |
| obligation.predicate.def_id(), | |
| [source_tail, target_tail], | |
| ), | |
| ); | |
| nested.push(tail_unsize_obligation); | |
| ImplSource::Builtin(BuiltinImplSource::Misc, nested) | |
| } | |
| _ => bug!("source: {source}, target: {target}"), | |
| }) | |
| } | |
| /// This trait is indirectly exposed on stable, so do *not* extend the set of types that | |
| /// implement the trait without FCP! | |
| fn confirm_bikeshed_guaranteed_no_drop_candidate( | |
| &mut self, | |
| obligation: &PolyTraitObligation<'tcx>, | |
| ) -> ImplSource<'tcx, PredicateObligation<'tcx>> { | |
| let mut obligations = thin_vec![]; | |
| let tcx = self.tcx(); | |
| let self_ty = obligation.predicate.self_ty(); | |
| match *self_ty.skip_binder().kind() { | |
| // `&mut T` and `&T` always implement `BikeshedGuaranteedNoDrop`. | |
| ty::Ref(..) => {} | |
| // `ManuallyDrop<T>` always implements `BikeshedGuaranteedNoDrop`. | |
| ty::Adt(def, _) if def.is_manually_drop() => {} | |
| // Arrays and tuples implement `BikeshedGuaranteedNoDrop` only if | |
| // their constituent types implement `BikeshedGuaranteedNoDrop`. | |
| ty::Tuple(tys) => { | |
| obligations.extend(tys.iter().map(|elem_ty| { | |
| obligation.with( | |
| tcx, | |
| self_ty.rebind(ty::TraitRef::new( | |
| tcx, | |
| obligation.predicate.def_id(), | |
| [elem_ty], | |
| )), | |
| ) | |
| })); | |
| } | |
| ty::Array(elem_ty, _) => { | |
| obligations.push(obligation.with( | |
| tcx, | |
| self_ty.rebind(ty::TraitRef::new( | |
| tcx, | |
| obligation.predicate.def_id(), | |
| [elem_ty], | |
| )), | |
| )); | |
| } | |
| // All other types implement `BikeshedGuaranteedNoDrop` only if | |
| // they implement `Copy`. We could be smart here and short-circuit | |
| // some trivially `Copy`/`!Copy` types, but there's no benefit. | |
| ty::FnDef(..) | |
| | ty::FnPtr(..) | |
| | ty::Error(_) | |
| | ty::Uint(_) | |
| | ty::Int(_) | |
| | ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) | |
| | ty::Bool | |
| | ty::Float(_) | |
| | ty::Char | |
| | ty::RawPtr(..) | |
| | ty::Never | |
| | ty::Pat(..) | |
| | ty::Dynamic(..) | |
| | ty::Str | |
| | ty::Slice(_) | |
| | ty::Foreign(..) | |
| | ty::Adt(..) | |
| | ty::Alias(..) | |
| | ty::Param(_) | |
| | ty::Placeholder(..) | |
| | ty::Closure(..) | |
| | ty::CoroutineClosure(..) | |
| | ty::Coroutine(..) | |
| | ty::UnsafeBinder(_) | |
| | ty::CoroutineWitness(..) | |
| | ty::Bound(..) => { | |
| obligations.push(obligation.with( | |
| tcx, | |
| self_ty.map_bound(|ty| { | |
| ty::TraitRef::new( | |
| tcx, | |
| tcx.require_lang_item(LangItem::Copy, obligation.cause.span), | |
| [ty], | |
| ) | |
| }), | |
| )); | |
| } | |
| ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => { | |
| panic!("unexpected type `{self_ty:?}`") | |
| } | |
| } | |
| ImplSource::Builtin(BuiltinImplSource::Misc, obligations) | |
| } | |
| } |