diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-06-19 09:26:03 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-06-19 09:26:03 +0000 |
commit | 9918693037dce8aa4bb6f08741b6812923486c18 (patch) | |
tree | 21d2b40bec7e6a7ea664acee056eb3d08e15a1cf /compiler/rustc_trait_selection/src/traits/select | |
parent | Releasing progress-linux version 1.75.0+dfsg1-5~progress7.99u1. (diff) | |
download | rustc-9918693037dce8aa4bb6f08741b6812923486c18.tar.xz rustc-9918693037dce8aa4bb6f08741b6812923486c18.zip |
Merging upstream version 1.76.0+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'compiler/rustc_trait_selection/src/traits/select')
3 files changed, 225 insertions, 165 deletions
diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index f4b6d3bcf..38b1046ac 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -115,6 +115,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { self.assemble_future_candidates(obligation, &mut candidates); } else if lang_items.iterator_trait() == Some(def_id) { self.assemble_iterator_candidates(obligation, &mut candidates); + } else if lang_items.async_iterator_trait() == Some(def_id) { + self.assemble_async_iterator_candidates(obligation, &mut candidates); } self.assemble_closure_candidates(obligation, &mut candidates); @@ -155,10 +157,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { .infcx .probe(|_| self.match_projection_obligation_against_definition_bounds(obligation)); - // FIXME(effects) proper constness needed? - candidates.vec.extend( - result.into_iter().map(|idx| ProjectionCandidate(idx, ty::BoundConstness::NotConst)), - ); + candidates.vec.extend(result.into_iter().map(|idx| ProjectionCandidate(idx))); } /// Given an obligation like `<SomeTrait for T>`, searches the obligations that the caller @@ -261,6 +260,34 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } + fn assemble_async_iterator_candidates( + &mut self, + obligation: &PolyTraitObligation<'tcx>, + candidates: &mut SelectionCandidateSet<'tcx>, + ) { + let self_ty = obligation.self_ty().skip_binder(); + if let ty::Coroutine(did, args, _) = *self_ty.kind() { + // gen constructs get lowered to a special kind of coroutine that + // should directly `impl AsyncIterator`. + if self.tcx().coroutine_is_async_gen(did) { + debug!(?self_ty, ?obligation, "assemble_iterator_candidates",); + + // Can only confirm this candidate if we have constrained + // the `Yield` type to at least `Poll<Option<?0>>`.. + let ty::Adt(_poll_def, args) = *args.as_coroutine().yield_ty().kind() else { + candidates.ambiguous = true; + return; + }; + let ty::Adt(_option_def, _) = *args.type_at(0).kind() else { + candidates.ambiguous = true; + return; + }; + + candidates.vec.push(AsyncIteratorCandidate); + } + } + } + /// Checks for the artificial impl that the compiler will create for an obligation like `X : /// FnMut<..>` where `X` is a closure type. /// @@ -291,8 +318,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } None => { - debug!("assemble_unboxed_candidates: closure_kind not yet known"); - candidates.vec.push(ClosureCandidate { is_const }); + if kind == ty::ClosureKind::FnOnce { + candidates.vec.push(ClosureCandidate { is_const }); + } else { + candidates.ambiguous = true; + } } } } @@ -328,17 +358,23 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // Provide an impl, but only for suitable `fn` pointers. ty::FnPtr(sig) => { if sig.is_fn_trait_compatible() { - candidates.vec.push(FnPointerCandidate { is_const: false }); + candidates + .vec + .push(FnPointerCandidate { fn_host_effect: self.tcx().consts.true_ }); } } // Provide an impl for suitable functions, rejecting `#[target_feature]` functions (RFC 2396). - ty::FnDef(def_id, _) => { - if self.tcx().fn_sig(def_id).skip_binder().is_fn_trait_compatible() - && self.tcx().codegen_fn_attrs(def_id).target_features.is_empty() + ty::FnDef(def_id, args) => { + let tcx = self.tcx(); + if tcx.fn_sig(def_id).skip_binder().is_fn_trait_compatible() + && tcx.codegen_fn_attrs(def_id).target_features.is_empty() { - candidates - .vec - .push(FnPointerCandidate { is_const: self.tcx().is_const_fn(def_id) }); + candidates.vec.push(FnPointerCandidate { + fn_host_effect: tcx + .generics_of(def_id) + .host_effect_index + .map_or(tcx.consts.true_, |idx| args.const_at(idx)), + }); } } _ => {} @@ -375,7 +411,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // consider a "quick reject". This avoids creating more types // and so forth that we need to. let impl_trait_ref = self.tcx().impl_trait_ref(impl_def_id).unwrap(); - if !drcx.args_refs_may_unify(obligation_args, impl_trait_ref.skip_binder().args) { + if !drcx.args_may_unify(obligation_args, impl_trait_ref.skip_binder().args) { return; } if self.reject_fn_ptr_impls( @@ -555,7 +591,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } ty::Alias(ty::Opaque, _) => { - if candidates.vec.iter().any(|c| matches!(c, ProjectionCandidate(..))) { + if candidates.vec.iter().any(|c| matches!(c, ProjectionCandidate(_))) { // We do not generate an auto impl candidate for `impl Trait`s which already // reference our auto trait. // @@ -634,7 +670,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let self_ty = placeholder_trait_predicate.self_ty(); let principal_trait_ref = match self_ty.kind() { - ty::Dynamic(ref data, ..) => { + ty::Dynamic(data, ..) => { if data.auto_traits().any(|did| did == obligation.predicate.def_id()) { debug!( "assemble_candidates_from_object_ty: matched builtin bound, \ @@ -759,10 +795,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { match (source.kind(), target.kind()) { // Trait+Kx+'a -> Trait+Ky+'b (upcasts). - ( - &ty::Dynamic(ref a_data, a_region, ty::Dyn), - &ty::Dynamic(ref b_data, b_region, ty::Dyn), - ) => { + (&ty::Dynamic(a_data, a_region, ty::Dyn), &ty::Dynamic(b_data, b_region, ty::Dyn)) => { // Upcast coercions permit several things: // // 1. Dropping auto traits, e.g., `Foo + Send` to `Foo` @@ -923,9 +956,18 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ) { // If the predicate is `~const Destruct` in a non-const environment, we don't actually need // to check anything. We'll short-circuit checking any obligations in confirmation, too. - // FIXME(effects) - if true { - candidates.vec.push(ConstDestructCandidate(None)); + let Some(host_effect_index) = + self.tcx().generics_of(obligation.predicate.def_id()).host_effect_index + else { + candidates.vec.push(BuiltinCandidate { has_nested: false }); + return; + }; + // If the obligation has `host = true`, then the obligation is non-const and it's always + // trivially implemented. + if obligation.predicate.skip_binder().trait_ref.args.const_at(host_effect_index) + == self.tcx().consts.true_ + { + candidates.vec.push(BuiltinCandidate { has_nested: false }); return; } @@ -1051,7 +1093,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ) { // The regions of a type don't affect the size of the type let tcx = self.tcx(); - let self_ty = tcx.erase_late_bound_regions(obligation.predicate.self_ty()); + let self_ty = tcx.instantiate_bound_regions_with_erased(obligation.predicate.self_ty()); // We should erase regions from both the param-env and type, since both // may have infer regions. Specifically, after canonicalizing and instantiating, // early bound regions turn into region vars in both the new and old solver. diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 4bfa341e3..ce3fc2185 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -9,7 +9,7 @@ use rustc_ast::Mutability; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_hir::lang_items::LangItem; -use rustc_infer::infer::LateBoundRegionConversionTime::HigherRankedType; +use rustc_infer::infer::BoundRegionConversionTime::HigherRankedType; use rustc_infer::infer::{DefineOpaqueTypes, InferOk}; use rustc_middle::traits::{BuiltinImplSource, SelectionOutputTypeParameterMismatch}; use rustc_middle::ty::{ @@ -71,7 +71,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ImplSource::Builtin(BuiltinImplSource::Misc, data) } - ProjectionCandidate(idx, _) => { + ProjectionCandidate(idx) => { let obligations = self.confirm_projection_candidate(obligation, idx)?; ImplSource::Param(obligations) } @@ -98,8 +98,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ImplSource::Builtin(BuiltinImplSource::Misc, vtable_iterator) } - FnPointerCandidate { is_const } => { - let data = self.confirm_fn_pointer_candidate(obligation, is_const)?; + AsyncIteratorCandidate => { + let vtable_iterator = self.confirm_async_iterator_candidate(obligation)?; + ImplSource::Builtin(BuiltinImplSource::Misc, vtable_iterator) + } + + FnPointerCandidate { fn_host_effect } => { + let data = self.confirm_fn_pointer_candidate(obligation, fn_host_effect)?; ImplSource::Builtin(BuiltinImplSource::Misc, data) } @@ -327,8 +332,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // care about other regions. Erasing late-bound regions is equivalent // to instantiating the binder with placeholders then erasing those // placeholder regions. - let predicate = - self.tcx().erase_regions(self.tcx().erase_late_bound_regions(obligation.predicate)); + let predicate = self + .tcx() + .erase_regions(self.tcx().instantiate_bound_regions_with_erased(obligation.predicate)); let Some(assume) = rustc_transmute::Assume::from_const( self.infcx.tcx, @@ -393,7 +399,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation.recursion_depth + 1, obligation.param_env, trait_def_id, - &trait_ref.args, + trait_ref.args, obligation.predicate, ); @@ -454,7 +460,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { recursion_depth, param_env, impl_def_id, - &args.value, + args.value, parent_trait_pred, ); @@ -552,7 +558,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let defs: &ty::Generics = tcx.generics_of(assoc_type); if !defs.params.is_empty() && !tcx.features().generic_associated_types_extended { - tcx.sess.delay_span_bug( + tcx.sess.span_delayed_bug( obligation.cause.span, "GATs in trait object shouldn't have been considered", ); @@ -592,7 +598,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let kind = ty::BoundRegionKind::BrNamed(param.def_id, param.name); let bound_var = ty::BoundVariableKind::Region(kind); bound_vars.push(bound_var); - ty::Region::new_late_bound( + ty::Region::new_bound( tcx, ty::INNERMOST, ty::BoundRegion { @@ -647,8 +653,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { fn confirm_fn_pointer_candidate( &mut self, obligation: &PolyTraitObligation<'tcx>, - // FIXME(effects) - _is_const: bool, + fn_host_effect: ty::Const<'tcx>, ) -> Result<Vec<PredicateObligation<'tcx>>, SelectionError<'tcx>> { debug!(?obligation, "confirm_fn_pointer_candidate"); @@ -669,6 +674,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { self_ty, sig, util::TupleArgumentsFlag::Yes, + fn_host_effect, ) .map_bound(|(trait_ref, _)| trait_ref); @@ -707,7 +713,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation.recursion_depth, obligation.param_env, trait_def_id, - &args, + args, obligation.predicate, ); @@ -730,7 +736,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { debug!(?obligation, ?coroutine_def_id, ?args, "confirm_coroutine_candidate"); - let coroutine_sig = args.as_coroutine().poly_sig(); + let coroutine_sig = args.as_coroutine().sig(); // NOTE: The self-type is a coroutine type and hence is // in fact unparameterized (or at least does not reference any @@ -741,15 +747,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { .no_bound_vars() .expect("unboxed closure type should not capture bound vars from the predicate"); - let trait_ref = super::util::coroutine_trait_ref_and_outputs( + let (trait_ref, _, _) = super::util::coroutine_trait_ref_and_outputs( self.tcx(), obligation.predicate.def_id(), self_ty, coroutine_sig, - ) - .map_bound(|(trait_ref, ..)| trait_ref); + ); - let nested = self.confirm_poly_trait_refs(obligation, trait_ref)?; + let nested = self.confirm_poly_trait_refs(obligation, ty::Binder::dummy(trait_ref))?; debug!(?trait_ref, ?nested, "coroutine candidate obligations"); Ok(nested) @@ -769,17 +774,16 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { debug!(?obligation, ?coroutine_def_id, ?args, "confirm_future_candidate"); - let coroutine_sig = args.as_coroutine().poly_sig(); + let coroutine_sig = args.as_coroutine().sig(); - let trait_ref = super::util::future_trait_ref_and_outputs( + let (trait_ref, _) = super::util::future_trait_ref_and_outputs( self.tcx(), obligation.predicate.def_id(), obligation.predicate.no_bound_vars().expect("future has no bound vars").self_ty(), coroutine_sig, - ) - .map_bound(|(trait_ref, ..)| trait_ref); + ); - let nested = self.confirm_poly_trait_refs(obligation, trait_ref)?; + let nested = self.confirm_poly_trait_refs(obligation, ty::Binder::dummy(trait_ref))?; debug!(?trait_ref, ?nested, "future candidate obligations"); Ok(nested) @@ -799,17 +803,45 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { debug!(?obligation, ?coroutine_def_id, ?args, "confirm_iterator_candidate"); - let gen_sig = args.as_coroutine().poly_sig(); + let gen_sig = args.as_coroutine().sig(); - let trait_ref = super::util::iterator_trait_ref_and_outputs( + let (trait_ref, _) = super::util::iterator_trait_ref_and_outputs( self.tcx(), obligation.predicate.def_id(), obligation.predicate.no_bound_vars().expect("iterator has no bound vars").self_ty(), gen_sig, - ) - .map_bound(|(trait_ref, ..)| trait_ref); + ); - let nested = self.confirm_poly_trait_refs(obligation, trait_ref)?; + let nested = self.confirm_poly_trait_refs(obligation, 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<Vec<PredicateObligation<'tcx>>, SelectionError<'tcx>> { + // Okay to skip binder because the args on coroutine types never + // touch bound regions, they just capture the in-scope + // type/region parameters. + let self_ty = self.infcx.shallow_resolve(obligation.self_ty().skip_binder()); + 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(), + obligation.predicate.no_bound_vars().expect("iterator has no bound vars").self_ty(), + gen_sig, + ); + + let nested = self.confirm_poly_trait_refs(obligation, ty::Binder::dummy(trait_ref))?; debug!(?trait_ref, ?nested, "iterator candidate obligations"); Ok(nested) @@ -820,11 +852,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { &mut self, obligation: &PolyTraitObligation<'tcx>, ) -> Result<Vec<PredicateObligation<'tcx>>, SelectionError<'tcx>> { - let kind = self - .tcx() - .fn_trait_kind_from_def_id(obligation.predicate.def_id()) - .unwrap_or_else(|| bug!("closure candidate for non-fn trait {:?}", obligation)); - // Okay to skip binder because the args on closure types never // touch bound regions, they just capture the in-scope // type/region parameters. @@ -833,16 +860,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { bug!("closure candidate for non-closure {:?}", obligation); }; - let trait_ref = self.closure_trait_ref_unnormalized(obligation, args); - let mut nested = self.confirm_poly_trait_refs(obligation, trait_ref)?; + let trait_ref = + self.closure_trait_ref_unnormalized(obligation, args, self.tcx().consts.true_); + let nested = self.confirm_poly_trait_refs(obligation, trait_ref)?; debug!(?closure_def_id, ?trait_ref, ?nested, "confirm closure candidate obligations"); - nested.push(obligation.with( - self.tcx(), - ty::Binder::dummy(ty::PredicateKind::ClosureKind(closure_def_id, args, kind)), - )); - Ok(nested) } @@ -920,8 +943,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { 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, ty::Dyn) = *a_ty.kind() else { bug!() }; - let ty::Dynamic(b_data, b_region, ty::Dyn) = *b_ty.kind() else { bug!() }; + let ty::Dynamic(a_data, a_region, ty::Dyn) = *a_ty.kind() else { + bug!("expected `dyn` type in `confirm_trait_upcasting_unsize_candidate`") + }; + let ty::Dynamic(b_data, b_region, ty::Dyn) = *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 = @@ -985,7 +1012,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { Ok(match (source.kind(), target.kind()) { // Trait+Kx+'a -> Trait+Ky+'b (auto traits and lifetime subtyping). - (&ty::Dynamic(ref data_a, r_a, dyn_a), &ty::Dynamic(ref data_b, r_b, dyn_b)) + (&ty::Dynamic(data_a, r_a, dyn_a), &ty::Dynamic(data_b, r_b, dyn_b)) if dyn_a == dyn_b => { // See `assemble_candidates_for_unsizing` for more info. @@ -1030,7 +1057,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } // `T` -> `Trait` - (_, &ty::Dynamic(ref data, r, ty::Dyn)) => { + (_, &ty::Dynamic(data, r, ty::Dyn)) => { let mut object_dids = data.auto_traits().chain(data.principal_def_id()); if let Some(did) = object_dids.find(|did| !tcx.check_is_object_safe(*did)) { return Err(TraitNotObjectSafe(did)); @@ -1184,11 +1211,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation: &PolyTraitObligation<'tcx>, impl_def_id: Option<DefId>, ) -> Result<Vec<PredicateObligation<'tcx>>, SelectionError<'tcx>> { - // `~const Destruct` in a non-const environment is always trivially true, since our type is `Drop` - // FIXME(effects) - if true { - return Ok(vec![]); - } + let Some(host_effect_index) = + self.tcx().generics_of(obligation.predicate.def_id()).host_effect_index + else { + bug!() + }; + let host_effect_param: ty::GenericArg<'tcx> = + obligation.predicate.skip_binder().trait_ref.args.const_at(host_effect_index).into(); let drop_trait = self.tcx().require_lang_item(LangItem::Drop, None); @@ -1277,7 +1306,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let tcx = self.tcx(); stack.extend(tcx.coroutine_hidden_types(def_id).map(|bty| { let ty = bty.instantiate(tcx, args); - debug_assert!(!ty.has_late_bound_regions()); + debug_assert!(!ty.has_bound_regions()); ty })) } @@ -1285,7 +1314,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // If we have a projection type, make sure to normalize it so we replace it // with a fresh infer variable ty::Alias(ty::Projection | ty::Inherent, ..) => { - // FIXME(effects) this needs constness let predicate = normalize_with_depth_to( self, obligation.param_env, @@ -1296,7 +1324,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { self.tcx(), LangItem::Destruct, cause.span, - [nested_ty], + [nested_ty.into(), host_effect_param], ), polarity: ty::ImplPolarity::Positive, }), @@ -1316,13 +1344,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // since it's either not `const Drop` (and we raise an error during selection), // or it's an ADT (and we need to check for a custom impl during selection) _ => { - // FIXME(effects) this needs constness let predicate = self_ty.rebind(ty::TraitPredicate { trait_ref: ty::TraitRef::from_lang_item( self.tcx(), LangItem::Destruct, cause.span, - [nested_ty], + [nested_ty.into(), host_effect_param], ), polarity: ty::ImplPolarity::Positive, }); diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 08208cc60..23f7bdd15 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -32,8 +32,8 @@ use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::Diagnostic; use rustc_hir as hir; use rustc_hir::def_id::DefId; +use rustc_infer::infer::BoundRegionConversionTime; use rustc_infer::infer::DefineOpaqueTypes; -use rustc_infer::infer::LateBoundRegionConversionTime; use rustc_infer::traits::TraitObligation; use rustc_middle::dep_graph::dep_kinds; use rustc_middle::dep_graph::DepNodeIndex; @@ -46,6 +46,7 @@ use rustc_middle::ty::GenericArgsRef; use rustc_middle::ty::{self, EarlyBinder, PolyProjectionPredicate, ToPolyTraitRef, ToPredicate}; use rustc_middle::ty::{Ty, TyCtxt, TypeFoldable, TypeVisitableExt}; use rustc_span::symbol::sym; +use rustc_span::Symbol; use std::cell::{Cell, RefCell}; use std::cmp; @@ -59,13 +60,13 @@ mod candidate_assembly; mod confirmation; #[derive(Clone, Debug, Eq, PartialEq, Hash)] -pub enum IntercrateAmbiguityCause { - DownstreamCrate { trait_desc: String, self_desc: Option<String> }, - UpstreamCrateUpdate { trait_desc: String, self_desc: Option<String> }, - ReservationImpl { message: String }, +pub enum IntercrateAmbiguityCause<'tcx> { + DownstreamCrate { trait_ref: ty::TraitRef<'tcx>, self_ty: Option<Ty<'tcx>> }, + UpstreamCrateUpdate { trait_ref: ty::TraitRef<'tcx>, self_ty: Option<Ty<'tcx>> }, + ReservationImpl { message: Symbol }, } -impl IntercrateAmbiguityCause { +impl<'tcx> IntercrateAmbiguityCause<'tcx> { /// Emits notes when the overlap is caused by complex intercrate ambiguities. /// See #23980 for details. pub fn add_intercrate_ambiguity_hint(&self, err: &mut Diagnostic) { @@ -73,28 +74,32 @@ impl IntercrateAmbiguityCause { } pub fn intercrate_ambiguity_hint(&self) -> String { - match self { - IntercrateAmbiguityCause::DownstreamCrate { trait_desc, self_desc } => { - let self_desc = if let Some(ty) = self_desc { - format!(" for type `{ty}`") - } else { - String::new() - }; - format!("downstream crates may implement trait `{trait_desc}`{self_desc}") + with_no_trimmed_paths!(match self { + IntercrateAmbiguityCause::DownstreamCrate { trait_ref, self_ty } => { + format!( + "downstream crates may implement trait `{trait_desc}`{self_desc}", + trait_desc = trait_ref.print_trait_sugared(), + self_desc = if let Some(self_ty) = self_ty { + format!(" for type `{self_ty}`") + } else { + String::new() + } + ) } - IntercrateAmbiguityCause::UpstreamCrateUpdate { trait_desc, self_desc } => { - let self_desc = if let Some(ty) = self_desc { - format!(" for type `{ty}`") - } else { - String::new() - }; + IntercrateAmbiguityCause::UpstreamCrateUpdate { trait_ref, self_ty } => { format!( "upstream crates may add a new impl of trait `{trait_desc}`{self_desc} \ - in future versions" + in future versions", + trait_desc = trait_ref.print_trait_sugared(), + self_desc = if let Some(self_ty) = self_ty { + format!(" for type `{self_ty}`") + } else { + String::new() + } ) } - IntercrateAmbiguityCause::ReservationImpl { message } => message.clone(), - } + IntercrateAmbiguityCause::ReservationImpl { message } => message.to_string(), + }) } } @@ -114,7 +119,7 @@ pub struct SelectionContext<'cx, 'tcx> { /// We don't do his until we detect a coherence error because it can /// lead to false overflow results (#47139) and because always /// computing it may negatively impact performance. - intercrate_ambiguity_causes: Option<FxIndexSet<IntercrateAmbiguityCause>>, + intercrate_ambiguity_causes: Option<FxIndexSet<IntercrateAmbiguityCause<'tcx>>>, /// The mode that trait queries run in, which informs our error handling /// policy. In essence, canonicalized queries need their errors propagated @@ -217,8 +222,8 @@ pub enum TreatInductiveCycleAs { impl From<TreatInductiveCycleAs> for EvaluationResult { fn from(treat: TreatInductiveCycleAs) -> EvaluationResult { match treat { - TreatInductiveCycleAs::Ambig => EvaluatedToUnknown, - TreatInductiveCycleAs::Recur => EvaluatedToRecur, + TreatInductiveCycleAs::Ambig => EvaluatedToAmbigStackDependent, + TreatInductiveCycleAs::Recur => EvaluatedToErrStackDependent, } } } @@ -270,7 +275,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { /// Gets the intercrate ambiguity causes collected since tracking /// was enabled and disables tracking at the same time. If /// tracking is not enabled, just returns an empty vector. - pub fn take_intercrate_ambiguity_causes(&mut self) -> FxIndexSet<IntercrateAmbiguityCause> { + pub fn take_intercrate_ambiguity_causes( + &mut self, + ) -> FxIndexSet<IntercrateAmbiguityCause<'tcx>> { assert!(self.is_intercrate()); self.intercrate_ambiguity_causes.take().unwrap_or_default() } @@ -367,7 +374,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { debug_assert!(!self.infcx.next_trait_solver()); // Watch out for overflow. This intentionally bypasses (and does // not update) the cache. - self.check_recursion_limit(&stack.obligation, &stack.obligation)?; + self.check_recursion_limit(stack.obligation, stack.obligation)?; // Check the cache. Note that we freshen the trait-ref // separately rather than using `stack.fresh_trait_ref` -- @@ -416,7 +423,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let mut no_candidates_apply = true; for c in candidate_set.vec.iter() { - if self.evaluate_candidate(stack, &c)?.may_apply() { + if self.evaluate_candidate(stack, c)?.may_apply() { no_candidates_apply = false; break; } @@ -428,19 +435,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ); if !trait_ref.references_error() { let self_ty = trait_ref.self_ty(); - let (trait_desc, self_desc) = with_no_trimmed_paths!({ - let trait_desc = trait_ref.print_only_trait_path().to_string(); - let self_desc = - self_ty.has_concrete_skeleton().then(|| self_ty.to_string()); - (trait_desc, self_desc) - }); + let self_ty = self_ty.has_concrete_skeleton().then(|| self_ty); let cause = if let Conflict::Upstream = conflict { - IntercrateAmbiguityCause::UpstreamCrateUpdate { - trait_desc, - self_desc, - } + IntercrateAmbiguityCause::UpstreamCrateUpdate { trait_ref, self_ty } } else { - IntercrateAmbiguityCause::DownstreamCrate { trait_desc, self_desc } + IntercrateAmbiguityCause::DownstreamCrate { trait_ref, self_ty } }; debug!(?cause, "evaluate_stack: pushing cause"); self.intercrate_ambiguity_causes.as_mut().unwrap().insert(cause); @@ -799,7 +798,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // A global type with no free lifetimes or generic parameters // outlives anything. if pred.0.has_free_regions() - || pred.0.has_late_bound_regions() + || pred.0.has_bound_regions() || pred.0.has_non_region_infer() || pred.0.has_non_region_infer() { @@ -885,19 +884,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } - ty::PredicateKind::ClosureKind(_, closure_args, kind) => { - match self.infcx.closure_kind(closure_args) { - Some(closure_kind) => { - if closure_kind.extends(kind) { - Ok(EvaluatedToOk) - } else { - Ok(EvaluatedToErr) - } - } - None => Ok(EvaluatedToAmbig), - } - } - ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(uv)) => { match const_evaluatable::is_const_evaluatable( self.infcx, @@ -1004,8 +990,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } } + ty::PredicateKind::NormalizesTo(..) => { + bug!("NormalizesTo is only used by the new solver") + } ty::PredicateKind::AliasRelate(..) => { - bug!("AliasRelate is only used for new solver") + bug!("AliasRelate is only used by the new solver") } ty::PredicateKind::Ambiguous => Ok(EvaluatedToAmbig), ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ty)) => { @@ -1237,15 +1226,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { if unbound_input_types && stack.iter().skip(1).any(|prev| { stack.obligation.param_env == prev.obligation.param_env - && self.match_fresh_trait_refs( - stack.fresh_trait_pred, - prev.fresh_trait_pred, - prev.obligation.param_env, - ) + && self.match_fresh_trait_refs(stack.fresh_trait_pred, prev.fresh_trait_pred) }) { debug!("evaluate_stack --> unbound argument, recursive --> giving up",); - return Ok(EvaluatedToUnknown); + return Ok(EvaluatedToAmbigStackDependent); } match self.candidate_from_obligation(stack) { @@ -1464,20 +1449,17 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { if let ImplCandidate(def_id) = candidate { if let ty::ImplPolarity::Reservation = tcx.impl_polarity(def_id) { if let Some(intercrate_ambiguity_clauses) = &mut self.intercrate_ambiguity_causes { - let value = tcx + let message = tcx .get_attr(def_id, sym::rustc_reservation_impl) .and_then(|a| a.value_str()); - if let Some(value) = value { + if let Some(message) = message { debug!( "filter_reservation_impls: \ reservation impl ambiguity on {:?}", def_id ); - intercrate_ambiguity_clauses.insert( - IntercrateAmbiguityCause::ReservationImpl { - message: value.to_string(), - }, - ); + intercrate_ambiguity_clauses + .insert(IntercrateAmbiguityCause::ReservationImpl { message }); } } return Ok(None); @@ -1751,7 +1733,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let mut nested_obligations = Vec::new(); let infer_predicate = self.infcx.instantiate_binder_with_fresh_vars( obligation.cause.span, - LateBoundRegionConversionTime::HigherRankedType, + BoundRegionConversionTime::HigherRankedType, env_predicate, ); let infer_projection = if potentially_unnormalized_candidates { @@ -1841,7 +1823,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> { // the param_env so that it can be given the lowest priority. See // #50825 for the motivation for this. let is_global = - |cand: &ty::PolyTraitPredicate<'tcx>| cand.is_global() && !cand.has_late_bound_vars(); + |cand: &ty::PolyTraitPredicate<'tcx>| cand.is_global() && !cand.has_bound_vars(); // (*) Prefer `BuiltinCandidate { has_nested: false }`, `PointeeCandidate`, // `DiscriminantKindCandidate`, `ConstDestructCandidate` @@ -1879,7 +1861,9 @@ impl<'tcx> SelectionContext<'_, 'tcx> { } // Drop otherwise equivalent non-const fn pointer candidates - (FnPointerCandidate { .. }, FnPointerCandidate { is_const: false }) => DropVictim::Yes, + (FnPointerCandidate { .. }, FnPointerCandidate { fn_host_effect }) => { + DropVictim::drop_if(*fn_host_effect == self.tcx().consts.true_) + } ( ParamCandidate(ref other_cand), @@ -1889,6 +1873,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> { | CoroutineCandidate | FutureCandidate | IteratorCandidate + | AsyncIteratorCandidate | FnPointerCandidate { .. } | BuiltinObjectCandidate | BuiltinUnsizeCandidate @@ -1896,7 +1881,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> { | BuiltinCandidate { .. } | TraitAliasCandidate | ObjectCandidate(_) - | ProjectionCandidate(..), + | ProjectionCandidate(_), ) => { // We have a where clause so don't go around looking // for impls. Arbitrarily give param candidates priority @@ -1906,7 +1891,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> { // here (see issue #50825). DropVictim::drop_if(!is_global(other_cand)) } - (ObjectCandidate(_) | ProjectionCandidate(..), ParamCandidate(ref victim_cand)) => { + (ObjectCandidate(_) | ProjectionCandidate(_), ParamCandidate(ref victim_cand)) => { // Prefer these to a global where-clause bound // (see issue #50825). if is_global(victim_cand) { DropVictim::Yes } else { DropVictim::No } @@ -1918,6 +1903,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> { | CoroutineCandidate | FutureCandidate | IteratorCandidate + | AsyncIteratorCandidate | FnPointerCandidate { .. } | BuiltinObjectCandidate | BuiltinUnsizeCandidate @@ -1933,26 +1919,27 @@ impl<'tcx> SelectionContext<'_, 'tcx> { ) } - (ProjectionCandidate(i, _), ProjectionCandidate(j, _)) + (ProjectionCandidate(i), ProjectionCandidate(j)) | (ObjectCandidate(i), ObjectCandidate(j)) => { // Arbitrarily pick the lower numbered candidate for backwards // compatibility reasons. Don't let this affect inference. DropVictim::drop_if(i < j && !has_non_region_infer) } - (ObjectCandidate(_), ProjectionCandidate(..)) - | (ProjectionCandidate(..), ObjectCandidate(_)) => { + (ObjectCandidate(_), ProjectionCandidate(_)) + | (ProjectionCandidate(_), ObjectCandidate(_)) => { bug!("Have both object and projection candidate") } // Arbitrarily give projection and object candidates priority. ( - ObjectCandidate(_) | ProjectionCandidate(..), + ObjectCandidate(_) | ProjectionCandidate(_), ImplCandidate(..) | AutoImplCandidate | ClosureCandidate { .. } | CoroutineCandidate | FutureCandidate | IteratorCandidate + | AsyncIteratorCandidate | FnPointerCandidate { .. } | BuiltinObjectCandidate | BuiltinUnsizeCandidate @@ -1968,13 +1955,14 @@ impl<'tcx> SelectionContext<'_, 'tcx> { | CoroutineCandidate | FutureCandidate | IteratorCandidate + | AsyncIteratorCandidate | FnPointerCandidate { .. } | BuiltinObjectCandidate | BuiltinUnsizeCandidate | TraitUpcastingUnsizeCandidate(_) | BuiltinCandidate { .. } | TraitAliasCandidate, - ObjectCandidate(_) | ProjectionCandidate(..), + ObjectCandidate(_) | ProjectionCandidate(_), ) => DropVictim::No, (&ImplCandidate(other_def), &ImplCandidate(victim_def)) => { @@ -2075,6 +2063,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> { | CoroutineCandidate | FutureCandidate | IteratorCandidate + | AsyncIteratorCandidate | FnPointerCandidate { .. } | BuiltinObjectCandidate | BuiltinUnsizeCandidate @@ -2086,6 +2075,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> { | CoroutineCandidate | FutureCandidate | IteratorCandidate + | AsyncIteratorCandidate | FnPointerCandidate { .. } | BuiltinObjectCandidate | BuiltinUnsizeCandidate @@ -2218,7 +2208,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> { } } - ty::CoroutineWitness(def_id, ref args) => { + ty::CoroutineWitness(def_id, args) => { let hidden_types = bind_coroutine_hidden_types_above( self.infcx, def_id, @@ -2307,23 +2297,23 @@ impl<'tcx> SelectionContext<'_, 'tcx> { ty::Array(element_ty, _) | ty::Slice(element_ty) => t.rebind(vec![element_ty]), - ty::Tuple(ref tys) => { + ty::Tuple(tys) => { // (T1, ..., Tn) -- meets any bound that all of T1...Tn meet t.rebind(tys.iter().collect()) } - ty::Closure(_, ref args) => { + ty::Closure(_, args) => { let ty = self.infcx.shallow_resolve(args.as_closure().tupled_upvars_ty()); t.rebind(vec![ty]) } - ty::Coroutine(_, ref args, _) => { + ty::Coroutine(_, args, _) => { let ty = self.infcx.shallow_resolve(args.as_coroutine().tupled_upvars_ty()); let witness = args.as_coroutine().witness(); t.rebind([ty].into_iter().chain(iter::once(witness)).collect()) } - ty::CoroutineWitness(def_id, ref args) => { + ty::CoroutineWitness(def_id, args) => { bind_coroutine_hidden_types_above(self.infcx, def_id, args, t.bound_vars()) } @@ -2436,7 +2426,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> { // the placeholder trait ref may fail due the Generalizer relation // raising a CyclicalTy error due to a sub_root_var relation // for a variable being generalized... - let guar = self.infcx.tcx.sess.delay_span_bug( + let guar = self.infcx.tcx.sess.span_delayed_bug( obligation.cause.span, format!( "Impl {impl_def_id:?} was matchable against {obligation:?} but now is not" @@ -2638,9 +2628,8 @@ impl<'tcx> SelectionContext<'_, 'tcx> { &self, previous: ty::PolyTraitPredicate<'tcx>, current: ty::PolyTraitPredicate<'tcx>, - param_env: ty::ParamEnv<'tcx>, ) -> bool { - let mut matcher = MatchAgainstFreshVars::new(self.tcx(), param_env); + let mut matcher = MatchAgainstFreshVars::new(self.tcx()); matcher.relate(previous, current).is_ok() } @@ -2668,6 +2657,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> { &mut self, obligation: &PolyTraitObligation<'tcx>, args: GenericArgsRef<'tcx>, + fn_host_effect: ty::Const<'tcx>, ) -> ty::PolyTraitRef<'tcx> { let closure_sig = args.as_closure().sig(); @@ -2688,6 +2678,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> { self_ty, closure_sig, util::TupleArgumentsFlag::No, + fn_host_effect, ) .map_bound(|(trait_ref, _)| trait_ref) } @@ -3103,7 +3094,7 @@ fn bind_coroutine_hidden_types_above<'tcx>( kind: ty::BrAnon, }; counter += 1; - ty::Region::new_late_bound(tcx, current_depth, br) + ty::Region::new_bound(tcx, current_depth, br) } r => bug!("unexpected region: {r:?}"), }) |