diff options
Diffstat (limited to 'compiler/rustc_trait_selection/src/traits')
15 files changed, 490 insertions, 242 deletions
diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index 7ee9eb45309..3b40882ef57 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -368,9 +368,10 @@ fn impl_intersection_has_impossible_obligation<'a, 'cx, 'tcx>( overflowing_predicates: ambiguities .into_iter() .filter(|error| { - matches!(error.code, FulfillmentErrorCode::Ambiguity { - overflow: Some(true) - }) + matches!( + error.code, + FulfillmentErrorCode::Ambiguity { overflow: Some(true) } + ) }) .map(|e| infcx.resolve_vars_if_possible(e.obligation.predicate)) .collect(), @@ -491,13 +492,16 @@ fn plug_infer_with_placeholders<'tcx>( // Comparing against a type variable never registers hidden types anyway DefineOpaqueTypes::Yes, ty, - Ty::new_placeholder(self.infcx.tcx, ty::Placeholder { - universe: self.universe, - bound: ty::BoundTy { - var: self.next_var(), - kind: ty::BoundTyKind::Anon, + Ty::new_placeholder( + self.infcx.tcx, + ty::Placeholder { + universe: self.universe, + bound: ty::BoundTy { + var: self.next_var(), + kind: ty::BoundTyKind::Anon, + }, }, - }), + ), ) else { bug!("we always expect to be able to plug an infer var with placeholder") @@ -517,10 +521,10 @@ fn plug_infer_with_placeholders<'tcx>( // registration happening anyway. DefineOpaqueTypes::Yes, ct, - ty::Const::new_placeholder(self.infcx.tcx, ty::Placeholder { - universe: self.universe, - bound: self.next_var(), - }), + ty::Const::new_placeholder( + self.infcx.tcx, + ty::Placeholder { universe: self.universe, bound: self.next_var() }, + ), ) else { bug!("we always expect to be able to plug an infer var with placeholder") @@ -545,13 +549,16 @@ fn plug_infer_with_placeholders<'tcx>( // Lifetimes don't contain opaque types (or any types for that matter). DefineOpaqueTypes::Yes, r, - ty::Region::new_placeholder(self.infcx.tcx, ty::Placeholder { - universe: self.universe, - bound: ty::BoundRegion { - var: self.next_var(), - kind: ty::BoundRegionKind::Anon, + ty::Region::new_placeholder( + self.infcx.tcx, + ty::Placeholder { + universe: self.universe, + bound: ty::BoundRegion { + var: self.next_var(), + kind: ty::BoundRegionKind::Anon, + }, }, - }), + ), ) else { bug!("we always expect to be able to plug an infer var with placeholder") @@ -763,9 +770,9 @@ fn search_ambiguity_causes<'tcx>( causes: &mut FxIndexSet<IntercrateAmbiguityCause<'tcx>>, ) { infcx.probe(|_| { - infcx.visit_proof_tree(goal, &mut AmbiguityCausesVisitor { - cache: Default::default(), - causes, - }) + infcx.visit_proof_tree( + goal, + &mut AmbiguityCausesVisitor { cache: Default::default(), causes }, + ) }); } diff --git a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs index 617bc87a9d2..740f44ebcad 100644 --- a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs +++ b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs @@ -128,8 +128,7 @@ fn sized_trait_bound_spans<'tcx>( } fn get_sized_bounds(tcx: TyCtxt<'_>, trait_def_id: DefId) -> SmallVec<[Span; 1]> { - tcx.hir() - .get_if_local(trait_def_id) + tcx.hir_get_if_local(trait_def_id) .and_then(|node| match node { hir::Node::Item(hir::Item { kind: hir::ItemKind::Trait(.., generics, bounds, _), @@ -187,7 +186,10 @@ fn predicates_reference_self( fn bounds_reference_self(tcx: TyCtxt<'_>, trait_def_id: DefId) -> SmallVec<[Span; 1]> { tcx.associated_items(trait_def_id) .in_definition_order() + // We're only looking at associated type bounds .filter(|item| item.kind == ty::AssocKind::Type) + // Ignore GATs with `Self: Sized` + .filter(|item| !tcx.generics_require_sized_self(item.def_id)) .flat_map(|item| tcx.explicit_item_bounds(item.def_id).iter_identity_copied()) .filter_map(|(clause, sp)| { // Item bounds *can* have self projections, since they never get @@ -301,7 +303,7 @@ pub fn dyn_compatibility_violations_for_assoc_item( ty::AssocKind::Fn => virtual_call_violations_for_method(tcx, trait_def_id, item) .into_iter() .map(|v| { - let node = tcx.hir().get_if_local(item.def_id); + let node = tcx.hir_get_if_local(item.def_id); // Get an accurate span depending on the violation. let span = match (&v, node) { (MethodViolationCode::ReferencesSelfInput(Some(span)), _) => *span, @@ -346,7 +348,7 @@ fn virtual_call_violations_for_method<'tcx>( generics, kind: hir::TraitItemKind::Fn(sig, _), .. - })) = tcx.hir().get_if_local(method.def_id).as_ref() + })) = tcx.hir_get_if_local(method.def_id).as_ref() { let sm = tcx.sess.source_map(); Some(( @@ -380,7 +382,7 @@ fn virtual_call_violations_for_method<'tcx>( let span = if let Some(hir::Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Fn(sig, _), .. - })) = tcx.hir().get_if_local(method.def_id).as_ref() + })) = tcx.hir_get_if_local(method.def_id).as_ref() { Some(sig.decl.inputs[i].span) } else { @@ -418,7 +420,7 @@ fn virtual_call_violations_for_method<'tcx>( let span = if let Some(hir::Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Fn(sig, _), .. - })) = tcx.hir().get_if_local(method.def_id).as_ref() + })) = tcx.hir_get_if_local(method.def_id).as_ref() { Some(sig.decl.inputs[0].span) } else { @@ -696,11 +698,11 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for IllegalSelfTypeVisitor<'tcx> { ControlFlow::Continue(()) } } - ty::Alias(ty::Projection, ref data) if self.tcx.is_impl_trait_in_trait(data.def_id) => { + ty::Alias(ty::Projection, data) if self.tcx.is_impl_trait_in_trait(data.def_id) => { // We'll deny these later in their own pass ControlFlow::Continue(()) } - ty::Alias(ty::Projection, ref data) => { + ty::Alias(ty::Projection, data) => { match self.allow_self_projections { AllowSelfProjections::Yes => { // This is a projected type `<Foo as SomeTrait>::X`. diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index f2d2dd2f3ce..e39f8e673db 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -1,6 +1,5 @@ use std::marker::PhantomData; -use rustc_data_structures::captures::Captures; use rustc_data_structures::obligation_forest::{ Error, ForestObligation, ObligationForest, ObligationProcessor, Outcome, ProcessResult, }; @@ -900,10 +899,10 @@ impl<'a, 'tcx> FulfillProcessor<'a, 'tcx> { } /// Returns the set of inference variables contained in `args`. -fn args_infer_vars<'a, 'tcx>( - selcx: &SelectionContext<'a, 'tcx>, +fn args_infer_vars<'tcx>( + selcx: &SelectionContext<'_, 'tcx>, args: ty::Binder<'tcx, GenericArgsRef<'tcx>>, -) -> impl Iterator<Item = TyOrConstInferVar> + Captures<'tcx> { +) -> impl Iterator<Item = TyOrConstInferVar> { selcx .infcx .resolve_vars_if_possible(args) diff --git a/compiler/rustc_trait_selection/src/traits/misc.rs b/compiler/rustc_trait_selection/src/traits/misc.rs index 79e178150de..a4b6f330b9d 100644 --- a/compiler/rustc_trait_selection/src/traits/misc.rs +++ b/compiler/rustc_trait_selection/src/traits/misc.rs @@ -208,7 +208,7 @@ pub fn all_fields_implement_trait<'tcx>( } let field_span = tcx.def_span(field.did); - let field_ty_span = match tcx.hir().get_if_local(field.did) { + let field_ty_span = match tcx.hir_get_if_local(field.did) { Some(hir::Node::Field(field_def)) => field_def.ty.span, _ => field_span, }; diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index d4a9664e282..105cb917571 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -660,13 +660,16 @@ fn replace_param_and_infer_args_with_placeholder<'tcx>( self.idx += 1; idx }; - Ty::new_placeholder(self.tcx, ty::PlaceholderType { - universe: ty::UniverseIndex::ROOT, - bound: ty::BoundTy { - var: ty::BoundVar::from_u32(idx), - kind: ty::BoundTyKind::Anon, + Ty::new_placeholder( + self.tcx, + ty::PlaceholderType { + universe: ty::UniverseIndex::ROOT, + bound: ty::BoundTy { + var: ty::BoundVar::from_u32(idx), + kind: ty::BoundTyKind::Anon, + }, }, - }) + ) } else { t.super_fold_with(self) } @@ -674,14 +677,17 @@ fn replace_param_and_infer_args_with_placeholder<'tcx>( fn fold_const(&mut self, c: ty::Const<'tcx>) -> ty::Const<'tcx> { if let ty::ConstKind::Infer(_) = c.kind() { - ty::Const::new_placeholder(self.tcx, ty::PlaceholderConst { - universe: ty::UniverseIndex::ROOT, - bound: ty::BoundVar::from_u32({ - let idx = self.idx; - self.idx += 1; - idx - }), - }) + ty::Const::new_placeholder( + self.tcx, + ty::PlaceholderConst { + universe: ty::UniverseIndex::ROOT, + bound: ty::BoundVar::from_u32({ + let idx = self.idx; + self.idx += 1; + idx + }), + }, + ) } else { c.super_fold_with(self) } diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 537b042bde5..de5aaa5bd97 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -1670,14 +1670,18 @@ fn confirm_closure_candidate<'cx, 'tcx>( } else { let upvars_projection_def_id = tcx.require_lang_item(LangItem::AsyncFnKindUpvars, None); - let tupled_upvars_ty = Ty::new_projection(tcx, upvars_projection_def_id, [ - ty::GenericArg::from(kind_ty), - Ty::from_closure_kind(tcx, ty::ClosureKind::FnOnce).into(), - tcx.lifetimes.re_static.into(), - sig.tupled_inputs_ty.into(), - args.tupled_upvars_ty().into(), - args.coroutine_captures_by_ref_ty().into(), - ]); + let tupled_upvars_ty = Ty::new_projection( + tcx, + upvars_projection_def_id, + [ + ty::GenericArg::from(kind_ty), + Ty::from_closure_kind(tcx, ty::ClosureKind::FnOnce).into(), + tcx.lifetimes.re_static.into(), + sig.tupled_inputs_ty.into(), + args.tupled_upvars_ty().into(), + args.coroutine_captures_by_ref_ty().into(), + ], + ); sig.to_coroutine( tcx, args.parent_args(), @@ -1795,14 +1799,18 @@ fn confirm_async_closure_candidate<'cx, 'tcx>( // will project to the right upvars for the generator, appending the inputs and // coroutine upvars respecting the closure kind. // N.B. No need to register a `AsyncFnKindHelper` goal here, it's already in `nested`. - let tupled_upvars_ty = Ty::new_projection(tcx, upvars_projection_def_id, [ - ty::GenericArg::from(kind_ty), - Ty::from_closure_kind(tcx, goal_kind).into(), - env_region.into(), - sig.tupled_inputs_ty.into(), - args.tupled_upvars_ty().into(), - args.coroutine_captures_by_ref_ty().into(), - ]); + let tupled_upvars_ty = Ty::new_projection( + tcx, + upvars_projection_def_id, + [ + ty::GenericArg::from(kind_ty), + Ty::from_closure_kind(tcx, goal_kind).into(), + env_region.into(), + sig.tupled_inputs_ty.into(), + args.tupled_upvars_ty().into(), + args.coroutine_captures_by_ref_ty().into(), + ], + ); sig.to_coroutine( tcx, args.parent_args(), @@ -1816,17 +1824,16 @@ fn confirm_async_closure_candidate<'cx, 'tcx>( name => bug!("no such associated type: {name}"), }; let projection_term = match item_name { - sym::CallOnceFuture | sym::Output => { - ty::AliasTerm::new(tcx, obligation.predicate.def_id, [ - self_ty, - sig.tupled_inputs_ty, - ]) - } - sym::CallRefFuture => ty::AliasTerm::new(tcx, obligation.predicate.def_id, [ - ty::GenericArg::from(self_ty), - sig.tupled_inputs_ty.into(), - env_region.into(), - ]), + sym::CallOnceFuture | sym::Output => ty::AliasTerm::new( + tcx, + obligation.predicate.def_id, + [self_ty, sig.tupled_inputs_ty], + ), + sym::CallRefFuture => ty::AliasTerm::new( + tcx, + obligation.predicate.def_id, + [ty::GenericArg::from(self_ty), sig.tupled_inputs_ty.into(), env_region.into()], + ), name => bug!("no such associated type: {name}"), }; @@ -1846,17 +1853,20 @@ fn confirm_async_closure_candidate<'cx, 'tcx>( name => bug!("no such associated type: {name}"), }; let projection_term = match item_name { - sym::CallOnceFuture | sym::Output => { - ty::AliasTerm::new(tcx, obligation.predicate.def_id, [ - self_ty, - Ty::new_tup(tcx, sig.inputs()), - ]) - } - sym::CallRefFuture => ty::AliasTerm::new(tcx, obligation.predicate.def_id, [ - ty::GenericArg::from(self_ty), - Ty::new_tup(tcx, sig.inputs()).into(), - env_region.into(), - ]), + sym::CallOnceFuture | sym::Output => ty::AliasTerm::new( + tcx, + obligation.predicate.def_id, + [self_ty, Ty::new_tup(tcx, sig.inputs())], + ), + sym::CallRefFuture => ty::AliasTerm::new( + tcx, + obligation.predicate.def_id, + [ + ty::GenericArg::from(self_ty), + Ty::new_tup(tcx, sig.inputs()).into(), + env_region.into(), + ], + ), name => bug!("no such associated type: {name}"), }; @@ -1879,11 +1889,11 @@ fn confirm_async_closure_candidate<'cx, 'tcx>( sym::CallOnceFuture | sym::Output => { ty::AliasTerm::new(tcx, obligation.predicate.def_id, [self_ty, sig.inputs()[0]]) } - sym::CallRefFuture => ty::AliasTerm::new(tcx, obligation.predicate.def_id, [ - ty::GenericArg::from(self_ty), - sig.inputs()[0].into(), - env_region.into(), - ]), + sym::CallRefFuture => ty::AliasTerm::new( + tcx, + obligation.predicate.def_id, + [ty::GenericArg::from(self_ty), sig.inputs()[0].into(), env_region.into()], + ), name => bug!("no such associated type: {name}"), }; diff --git a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs index 92098e20448..f04a5feba30 100644 --- a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs +++ b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs @@ -2,12 +2,13 @@ use rustc_data_structures::fx::FxHashSet; use rustc_infer::traits::query::type_op::DropckOutlives; use rustc_middle::traits::query::{DropckConstraint, DropckOutlivesResult}; use rustc_middle::ty::{self, EarlyBinder, ParamEnvAnd, Ty, TyCtxt}; -use rustc_span::{DUMMY_SP, Span}; +use rustc_span::Span; use tracing::{debug, instrument}; +use crate::solve::NextSolverError; use crate::traits::query::NoSolution; use crate::traits::query::normalize::QueryNormalizeExt; -use crate::traits::{Normalized, ObligationCause, ObligationCtxt}; +use crate::traits::{FromSolverError, Normalized, ObligationCause, ObligationCtxt}; /// This returns true if the type `ty` is "trivial" for /// dropck-outlives -- that is, if it doesn't require any types to @@ -93,6 +94,20 @@ pub fn compute_dropck_outlives_inner<'tcx>( goal: ParamEnvAnd<'tcx, DropckOutlives<'tcx>>, span: Span, ) -> Result<DropckOutlivesResult<'tcx>, NoSolution> { + match compute_dropck_outlives_with_errors(ocx, goal, span) { + Ok(r) => Ok(r), + Err(_) => Err(NoSolution), + } +} + +pub fn compute_dropck_outlives_with_errors<'tcx, E>( + ocx: &ObligationCtxt<'_, 'tcx, E>, + goal: ParamEnvAnd<'tcx, DropckOutlives<'tcx>>, + span: Span, +) -> Result<DropckOutlivesResult<'tcx>, Vec<E>> +where + E: FromSolverError<'tcx, NextSolverError<'tcx>>, +{ let tcx = ocx.infcx.tcx; let ParamEnvAnd { param_env, value: DropckOutlives { dropped_ty } } = goal; @@ -149,11 +164,11 @@ pub fn compute_dropck_outlives_inner<'tcx>( dtorck_constraint_for_ty_inner( tcx, ocx.infcx.typing_env(param_env), - DUMMY_SP, + span, depth, ty, &mut constraints, - )?; + ); // "outlives" represent types/regions that may be touched // by a destructor. @@ -173,11 +188,20 @@ pub fn compute_dropck_outlives_inner<'tcx>( // do not themselves define a destructor", more or less. We have // to push them onto the stack to be expanded. for ty in constraints.dtorck_types.drain(..) { - let Normalized { value: ty, obligations } = - ocx.infcx.at(&cause, param_env).query_normalize(ty)?; - ocx.register_obligations(obligations); + let ty = if let Ok(Normalized { value: ty, obligations }) = + ocx.infcx.at(&cause, param_env).query_normalize(ty) + { + ocx.register_obligations(obligations); + + debug!("dropck_outlives: ty from dtorck_types = {:?}", ty); + ty + } else { + ocx.deeply_normalize(&cause, param_env, ty)?; - debug!("dropck_outlives: ty from dtorck_types = {:?}", ty); + let errors = ocx.select_where_possible(); + debug!("normalize errors: {ty} ~> {errors:#?}"); + return Err(errors); + }; match ty.kind() { // All parameters live for the duration of the @@ -213,14 +237,14 @@ pub fn dtorck_constraint_for_ty_inner<'tcx>( depth: usize, ty: Ty<'tcx>, constraints: &mut DropckConstraint<'tcx>, -) -> Result<(), NoSolution> { +) { if !tcx.recursion_limit().value_within_limit(depth) { constraints.overflows.push(ty); - return Ok(()); + return; } if trivial_dropck_outlives(tcx, ty) { - return Ok(()); + return; } match ty.kind() { @@ -244,22 +268,20 @@ pub fn dtorck_constraint_for_ty_inner<'tcx>( // single-element containers, behave like their element rustc_data_structures::stack::ensure_sufficient_stack(|| { dtorck_constraint_for_ty_inner(tcx, typing_env, span, depth + 1, *ety, constraints) - })?; + }); } ty::Tuple(tys) => rustc_data_structures::stack::ensure_sufficient_stack(|| { for ty in tys.iter() { - dtorck_constraint_for_ty_inner(tcx, typing_env, span, depth + 1, ty, constraints)?; + dtorck_constraint_for_ty_inner(tcx, typing_env, span, depth + 1, ty, constraints); } - Ok::<_, NoSolution>(()) - })?, + }), ty::Closure(_, args) => rustc_data_structures::stack::ensure_sufficient_stack(|| { for ty in args.as_closure().upvar_tys() { - dtorck_constraint_for_ty_inner(tcx, typing_env, span, depth + 1, ty, constraints)?; + dtorck_constraint_for_ty_inner(tcx, typing_env, span, depth + 1, ty, constraints); } - Ok::<_, NoSolution>(()) - })?, + }), ty::CoroutineClosure(_, args) => { rustc_data_structures::stack::ensure_sufficient_stack(|| { @@ -271,10 +293,9 @@ pub fn dtorck_constraint_for_ty_inner<'tcx>( depth + 1, ty, constraints, - )?; + ); } - Ok::<_, NoSolution>(()) - })? + }) } ty::Coroutine(_, args) => { @@ -313,7 +334,7 @@ pub fn dtorck_constraint_for_ty_inner<'tcx>( ty::Adt(def, args) => { let DropckConstraint { dtorck_types, outlives, overflows } = - tcx.at(span).adt_dtorck_constraint(def.did())?; + tcx.at(span).adt_dtorck_constraint(def.did()); // FIXME: we can try to recursively `dtorck_constraint_on_ty` // there, but that needs some way to handle cycles. constraints @@ -346,9 +367,7 @@ pub fn dtorck_constraint_for_ty_inner<'tcx>( ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) | ty::Error(_) => { // By the time this code runs, all type variables ought to // be fully resolved. - return Err(NoSolution); + tcx.dcx().span_delayed_bug(span, format!("Unresolved type in dropck: {:?}.", ty)); } } - - Ok(()) } diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/normalize.rs index e8c2528aa6e..2f6bbd7f4cf 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/normalize.rs @@ -2,7 +2,7 @@ use std::fmt; use rustc_middle::traits::ObligationCause; use rustc_middle::traits::query::NoSolution; -pub use rustc_middle::traits::query::type_op::Normalize; +pub use rustc_middle::traits::query::type_op::{DeeplyNormalize, Normalize}; use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::{self, Lift, ParamEnvAnd, Ty, TyCtxt, TypeVisitableExt}; use rustc_span::Span; @@ -28,12 +28,53 @@ where } fn perform_locally_with_next_solver( + _ocx: &ObligationCtxt<'_, 'tcx>, + key: ParamEnvAnd<'tcx, Self>, + _span: Span, + ) -> Result<Self::QueryResponse, NoSolution> { + Ok(key.value.value) + } +} + +impl<'tcx, T> super::QueryTypeOp<'tcx> for DeeplyNormalize<T> +where + T: Normalizable<'tcx> + 'tcx, +{ + type QueryResponse = T; + + fn try_fast_path(_tcx: TyCtxt<'tcx>, key: &ParamEnvAnd<'tcx, Self>) -> Option<T> { + if !key.value.value.has_aliases() { Some(key.value.value) } else { None } + } + + fn perform_query( + tcx: TyCtxt<'tcx>, + canonicalized: CanonicalQueryInput<'tcx, ParamEnvAnd<'tcx, Self>>, + ) -> Result<CanonicalQueryResponse<'tcx, Self::QueryResponse>, NoSolution> { + T::type_op_method( + tcx, + CanonicalQueryInput { + typing_mode: canonicalized.typing_mode, + canonical: canonicalized.canonical.unchecked_map( + |ty::ParamEnvAnd { param_env, value }| ty::ParamEnvAnd { + param_env, + value: Normalize { value: value.value }, + }, + ), + }, + ) + } + + fn perform_locally_with_next_solver( ocx: &ObligationCtxt<'_, 'tcx>, key: ParamEnvAnd<'tcx, Self>, span: Span, ) -> Result<Self::QueryResponse, NoSolution> { - // FIXME(-Znext-solver): shouldn't be using old normalizer - Ok(ocx.normalize(&ObligationCause::dummy_with_span(span), key.param_env, key.value.value)) + ocx.deeply_normalize( + &ObligationCause::dummy_with_span(span), + key.param_env, + key.value.value, + ) + .map_err(|_| NoSolution) } } @@ -81,3 +122,14 @@ impl<'tcx> Normalizable<'tcx> for ty::FnSig<'tcx> { tcx.type_op_normalize_fn_sig(canonicalized) } } + +/// This impl is not needed, since we never normalize type outlives predicates +/// in the old solver, but is required by trait bounds to be happy. +impl<'tcx> Normalizable<'tcx> for ty::PolyTypeOutlivesPredicate<'tcx> { + fn type_op_method( + _tcx: TyCtxt<'tcx>, + _canonicalized: CanonicalQueryInput<'tcx, ParamEnvAnd<'tcx, Normalize<Self>>>, + ) -> Result<CanonicalQueryResponse<'tcx, Self>, NoSolution> { + unreachable!("we never normalize PolyTypeOutlivesPredicate") + } +} 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 13a6744c2e9..5b362b2356e 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -12,9 +12,7 @@ use hir::LangItem; use hir::def_id::DefId; use rustc_data_structures::fx::{FxHashSet, FxIndexSet}; use rustc_hir as hir; -use rustc_infer::traits::{ - Obligation, ObligationCause, PolyTraitObligation, PredicateObligations, SelectionError, -}; +use rustc_infer::traits::{Obligation, PolyTraitObligation, SelectionError}; use rustc_middle::ty::fast_reject::DeepRejectCtxt; use rustc_middle::ty::{self, Ty, TypeVisitableExt, TypingMode}; use rustc_middle::{bug, span_bug}; @@ -23,8 +21,6 @@ use tracing::{debug, instrument, trace}; use super::SelectionCandidate::*; use super::{BuiltinImplConditions, SelectionCandidateSet, SelectionContext, TraitObligationStack}; -use crate::traits; -use crate::traits::query::evaluate_obligation::InferCtxtExt; use crate::traits::util; impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { @@ -106,6 +102,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { self.assemble_candidate_for_tuple(obligation, &mut candidates); } else if tcx.is_lang_item(def_id, LangItem::FnPtrTrait) { self.assemble_candidates_for_fn_ptr_trait(obligation, &mut candidates); + } else if tcx.is_lang_item(def_id, LangItem::BikeshedGuaranteedNoDrop) { + self.assemble_candidates_for_bikeshed_guaranteed_no_drop_trait( + obligation, + &mut candidates, + ); } else { if tcx.is_lang_item(def_id, LangItem::Clone) { // Same builtin conditions as `Copy`, i.e., every type which has builtin support @@ -904,54 +905,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { }) } - /// Temporary migration for #89190 - fn need_migrate_deref_output_trait_object( - &mut self, - ty: Ty<'tcx>, - param_env: ty::ParamEnv<'tcx>, - cause: &ObligationCause<'tcx>, - ) -> Option<ty::PolyExistentialTraitRef<'tcx>> { - // Don't drop any candidates in intercrate mode, as it's incomplete. - // (Not that it matters, since `Unsize` is not a stable trait.) - // - // FIXME(@lcnr): This should probably only trigger during analysis, - // disabling candidates during codegen is also questionable. - if let TypingMode::Coherence = self.infcx.typing_mode() { - return None; - } - - let tcx = self.tcx(); - if tcx.features().trait_upcasting() { - return None; - } - - // <ty as Deref> - let trait_ref = ty::TraitRef::new(tcx, tcx.lang_items().deref_trait()?, [ty]); - - let obligation = - traits::Obligation::new(tcx, cause.clone(), param_env, ty::Binder::dummy(trait_ref)); - if !self.infcx.predicate_may_hold(&obligation) { - return None; - } - - self.infcx.probe(|_| { - let ty = traits::normalize_projection_ty( - self, - param_env, - ty::AliasTy::new_from_args(tcx, tcx.lang_items().deref_target()?, trait_ref.args), - cause.clone(), - 0, - // We're *intentionally* throwing these away, - // since we don't actually use them. - &mut PredicateObligations::new(), - ) - .as_type() - .unwrap(); - - if let ty::Dynamic(data, ..) = ty.kind() { data.principal() } else { None } - }) - } - /// Searches for unsizing that might apply to `obligation`. fn assemble_candidates_for_unsizing( &mut self, @@ -972,11 +925,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // T: Trait // so it seems ok if we (conservatively) fail to accept that `Unsize` // obligation above. Should be possible to extend this in the future. - let Some(source) = obligation.self_ty().no_bound_vars() else { + let Some(trait_pred) = obligation.predicate.no_bound_vars() else { // Don't add any candidates if there are bound regions. return; }; - let target = obligation.predicate.skip_binder().trait_ref.args.type_at(1); + let source = trait_pred.self_ty(); + let target = trait_pred.trait_ref.args.type_at(1); debug!(?source, ?target, "assemble_candidates_for_unsizing"); @@ -1019,15 +973,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let principal_a = a_data.principal().unwrap(); let target_trait_did = principal_def_id_b.unwrap(); let source_trait_ref = principal_a.with_self_ty(self.tcx(), source); - if let Some(deref_trait_ref) = self.need_migrate_deref_output_trait_object( - source, - obligation.param_env, - &obligation.cause, - ) { - if deref_trait_ref.def_id() == target_trait_did { - return; - } - } for (idx, upcast_trait_ref) in util::supertraits(self.tcx(), source_trait_ref).enumerate() @@ -1244,4 +1189,48 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } } + + fn assemble_candidates_for_bikeshed_guaranteed_no_drop_trait( + &mut self, + obligation: &PolyTraitObligation<'tcx>, + candidates: &mut SelectionCandidateSet<'tcx>, + ) { + match obligation.predicate.self_ty().skip_binder().kind() { + ty::Ref(..) + | ty::Adt(..) + | ty::Tuple(_) + | ty::Array(..) + | 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::Alias(..) + | ty::Param(_) + | ty::Placeholder(..) + | ty::Closure(..) + | ty::CoroutineClosure(..) + | ty::Coroutine(..) + | ty::UnsafeBinder(_) + | ty::CoroutineWitness(..) + | ty::Bound(..) => { + candidates.vec.push(BikeshedGuaranteedNoDropCandidate); + } + + ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => { + candidates.ambiguous = true; + } + } + } } diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 729ae3f2c2a..32cbb97e314 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -20,6 +20,7 @@ use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt, Upcast}; use rustc_middle::{bug, span_bug}; use rustc_span::def_id::DefId; use rustc_type_ir::elaborate; +use thin_vec::thin_vec; use tracing::{debug, instrument}; use super::SelectionCandidate::{self, *}; @@ -130,6 +131,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { TraitUpcastingUnsizeCandidate(idx) => { self.confirm_trait_upcasting_unsize_candidate(obligation, idx)? } + + BikeshedGuaranteedNoDropCandidate => { + self.confirm_bikeshed_guaranteed_no_drop_candidate(obligation) + } }; // The obligations returned by confirmation are recursively evaluated @@ -301,11 +306,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let make_transmute_obl = |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), - ]); + let trait_ref = ty::TraitRef::new( + tcx, + transmute_trait, + [ + ty::GenericArg::from(dst), + ty::GenericArg::from(src), + ty::GenericArg::from(assume), + ], + ); Obligation::with_depth( tcx, obligation.cause.clone(), @@ -316,10 +325,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { }; let make_freeze_obl = |ty| { - let trait_ref = - ty::TraitRef::new(tcx, tcx.require_lang_item(LangItem::Freeze, None), [ - ty::GenericArg::from(ty), - ]); + let trait_ref = ty::TraitRef::new( + tcx, + tcx.require_lang_item(LangItem::Freeze, None), + [ty::GenericArg::from(ty)], + ); Obligation::with_depth( tcx, obligation.cause.clone(), @@ -863,10 +873,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } 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, - ]) + ty::TraitRef::new( + self.tcx(), + obligation.predicate.def_id(), + [self_ty, sig.tupled_inputs_ty], + ) }) } _ => { @@ -892,10 +903,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { 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, - ]) + 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 @@ -906,10 +918,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { 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()), - ]) + 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`. @@ -934,10 +947,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { 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], - ]) + 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`. @@ -1295,10 +1309,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // 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, - ]), + ty::TraitRef::new( + tcx, + obligation.predicate.def_id(), + [source_tail, target_tail], + ), ); nested.push(tail_unsize_obligation); @@ -1336,6 +1351,93 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { _ => bug!("source: {source}, target: {target}"), }) } + + 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, Some(obligation.cause.span)), + [ty], + ) + }), + )); + } + + ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => { + panic!("unexpected type `{self_ty:?}`") + } + } + + ImplSource::Builtin(BuiltinImplSource::Misc, obligations) + } } /// Compute a goal that some RPITIT (right now, only RPITITs corresponding to Futures) @@ -1359,10 +1461,11 @@ fn pointer_like_goal_for_rpitit<'tcx>( ty::GenericParamDefKind::Lifetime => { let kind = ty::BoundRegionKind::Named(arg.def_id, tcx.item_name(arg.def_id)); bound_vars.push(ty::BoundVariableKind::Region(kind)); - ty::Region::new_bound(tcx, ty::INNERMOST, ty::BoundRegion { - var: ty::BoundVar::from_usize(bound_vars.len() - 1), - kind, - }) + ty::Region::new_bound( + tcx, + ty::INNERMOST, + ty::BoundRegion { var: ty::BoundVar::from_usize(bound_vars.len() - 1), kind }, + ) .into() } ty::GenericParamDefKind::Type { .. } | ty::GenericParamDefKind::Const { .. } => { @@ -1371,9 +1474,11 @@ fn pointer_like_goal_for_rpitit<'tcx>( }); ty::Binder::bind_with_vars( - ty::TraitRef::new(tcx, tcx.require_lang_item(LangItem::PointerLike, Some(cause.span)), [ - Ty::new_projection_from_args(tcx, rpitit_item, args), - ]), + ty::TraitRef::new( + tcx, + tcx.require_lang_item(LangItem::PointerLike, Some(cause.span)), + [Ty::new_projection_from_args(tcx, rpitit_item, args)], + ), tcx.mk_bound_variable_kinds(&bound_vars), ) } diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 99ce1fd9fb4..436ce3dddd9 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -1949,7 +1949,8 @@ impl<'tcx> SelectionContext<'_, 'tcx> { | TraitAliasCandidate | TraitUpcastingUnsizeCandidate(_) | BuiltinObjectCandidate - | BuiltinUnsizeCandidate => false, + | BuiltinUnsizeCandidate + | BikeshedGuaranteedNoDropCandidate => false, // Non-global param candidates have already been handled, global // where-bounds get ignored. ParamCandidate(_) | ImplCandidate(_) => true, @@ -2422,9 +2423,11 @@ impl<'tcx> SelectionContext<'_, 'tcx> { } else { // If this is an ill-formed auto/built-in trait, then synthesize // new error args for the missing generics. - let err_args = ty::GenericArgs::extend_with_error(tcx, trait_def_id, &[ - normalized_ty.into(), - ]); + let err_args = ty::GenericArgs::extend_with_error( + tcx, + trait_def_id, + &[normalized_ty.into()], + ); ty::TraitRef::new_from_args(tcx, trait_def_id, err_args) }; diff --git a/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs b/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs index f39c611d19f..19d3561dd59 100644 --- a/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs +++ b/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs @@ -200,15 +200,12 @@ impl<'tcx> Children { } } -fn iter_children(children: &Children) -> impl Iterator<Item = DefId> + '_ { +fn iter_children(children: &Children) -> impl Iterator<Item = DefId> { let nonblanket = children.non_blanket_impls.iter().flat_map(|(_, v)| v.iter()); children.blanket_impls.iter().chain(nonblanket).cloned() } -fn filtered_children( - children: &mut Children, - st: SimplifiedType, -) -> impl Iterator<Item = DefId> + '_ { +fn filtered_children(children: &mut Children, st: SimplifiedType) -> impl Iterator<Item = DefId> { let nonblanket = children.non_blanket_impls.entry(st).or_default().iter(); children.blanket_impls.iter().chain(nonblanket).cloned() } diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs index d30363ec158..15f5cf916a4 100644 --- a/compiler/rustc_trait_selection/src/traits/util.rs +++ b/compiler/rustc_trait_selection/src/traits/util.rs @@ -47,11 +47,11 @@ pub fn expand_trait_aliases<'tcx>( queue.extend( tcx.explicit_super_predicates_of(trait_pred.def_id()) .iter_identity_copied() - .map(|(clause, span)| { + .map(|(super_clause, span)| { let mut spans = spans.clone(); spans.push(span); ( - clause.instantiate_supertrait( + super_clause.instantiate_supertrait( tcx, clause.kind().rebind(trait_pred.trait_ref), ), diff --git a/compiler/rustc_trait_selection/src/traits/vtable.rs b/compiler/rustc_trait_selection/src/traits/vtable.rs index 000e6a765d3..165174c0bcc 100644 --- a/compiler/rustc_trait_selection/src/traits/vtable.rs +++ b/compiler/rustc_trait_selection/src/traits/vtable.rs @@ -196,7 +196,7 @@ fn own_existential_vtable_entries(tcx: TyCtxt<'_>, trait_def_id: DefId) -> &[Def fn own_existential_vtable_entries_iter( tcx: TyCtxt<'_>, trait_def_id: DefId, -) -> impl Iterator<Item = DefId> + '_ { +) -> impl Iterator<Item = DefId> { let trait_methods = tcx .associated_items(trait_def_id) .in_definition_order() @@ -318,9 +318,17 @@ pub(crate) fn first_method_vtable_slot<'tcx>(tcx: TyCtxt<'tcx>, key: ty::TraitRe bug!(); }; let source_principal = tcx.instantiate_bound_regions_with_erased( - source.principal().unwrap().with_self_ty(tcx, tcx.types.trait_object_dummy_self), + source.principal().unwrap().with_self_ty(tcx, key.self_ty()), ); + // We're monomorphizing a call to a dyn trait object that can never be constructed. + if tcx.instantiate_and_check_impossible_predicates(( + source_principal.def_id, + source_principal.args, + )) { + return 0; + } + let target_principal = ty::ExistentialTraitRef::erase_self_ty(tcx, key); let vtable_segment_callback = { @@ -373,19 +381,27 @@ pub(crate) fn supertrait_vtable_slot<'tcx>( let (source, target) = key; // If the target principal is `None`, we can just return `None`. - let ty::Dynamic(target, _, _) = *target.kind() else { + let ty::Dynamic(target_data, _, _) = *target.kind() else { bug!(); }; - let target_principal = tcx.instantiate_bound_regions_with_erased(target.principal()?); + let target_principal = tcx.instantiate_bound_regions_with_erased(target_data.principal()?); // Given that we have a target principal, it is a bug for there not to be a source principal. - let ty::Dynamic(source, _, _) = *source.kind() else { + let ty::Dynamic(source_data, _, _) = *source.kind() else { bug!(); }; let source_principal = tcx.instantiate_bound_regions_with_erased( - source.principal().unwrap().with_self_ty(tcx, tcx.types.trait_object_dummy_self), + source_data.principal().unwrap().with_self_ty(tcx, source), ); + // We're monomorphizing a dyn trait object upcast that can never be constructed. + if tcx.instantiate_and_check_impossible_predicates(( + source_principal.def_id, + source_principal.args, + )) { + return None; + } + let vtable_segment_callback = { let mut vptr_offset = 0; move |segment| { diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index 96051ad0aa5..7f3e3ce4781 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -8,8 +8,9 @@ use rustc_middle::ty::{ self, GenericArg, GenericArgKind, GenericArgsRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, }; -use rustc_span::Span; +use rustc_session::parse::feature_err; use rustc_span::def_id::{DefId, LocalDefId}; +use rustc_span::{Span, sym}; use tracing::{debug, instrument, trace}; use crate::infer::InferCtxt; @@ -288,7 +289,7 @@ fn extend_cause_with_original_assoc_item_obligation<'tcx>( && let Some(impl_item) = items.iter().find(|item| item.id.owner_id.to_def_id() == impl_item_id) { - Some(tcx.hir().impl_item(impl_item.id).expect_type().span) + Some(tcx.hir_impl_item(impl_item.id).expect_type().span) } else { None } @@ -704,8 +705,47 @@ impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for WfPredicates<'a, 'tcx> { )); } - ty::Pat(subty, _) => { + ty::Pat(subty, pat) => { self.require_sized(subty, ObligationCauseCode::Misc); + match *pat { + ty::PatternKind::Range { start, end, include_end: _ } => { + let mut check = |c| { + let cause = self.cause(ObligationCauseCode::Misc); + self.out.push(traits::Obligation::with_depth( + tcx, + cause.clone(), + self.recursion_depth, + self.param_env, + ty::Binder::dummy(ty::PredicateKind::Clause( + ty::ClauseKind::ConstArgHasType(c, subty), + )), + )); + if !tcx.features().generic_pattern_types() { + if c.has_param() { + if self.span.is_dummy() { + self.tcx().dcx().delayed_bug( + "feature error should be reported elsewhere, too", + ); + } else { + feature_err( + &self.tcx().sess, + sym::generic_pattern_types, + self.span, + "wraparound pattern type ranges cause monomorphization time errors", + ) + .emit(); + } + } + } + }; + if let Some(start) = start { + check(start) + } + if let Some(end) = end { + check(end) + } + } + } } ty::Tuple(tys) => { @@ -841,7 +881,10 @@ impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for WfPredicates<'a, 'tcx> { ty.map_bound(|ty| { ty::TraitRef::new( self.tcx(), - self.tcx().require_lang_item(LangItem::Copy, Some(self.span)), + self.tcx().require_lang_item( + LangItem::BikeshedGuaranteedNoDrop, + Some(self.span), + ), [ty], ) }), |
