diff options
| author | Ralf Jung <post@ralfj.de> | 2023-05-10 08:31:30 +0200 |
|---|---|---|
| committer | Ralf Jung <post@ralfj.de> | 2023-05-10 08:31:30 +0200 |
| commit | efa68d02d2ee74f7b70703caef44ff53b92fe910 (patch) | |
| tree | 082e0bc9195c513423a06ef48bb1825f2c2feb97 /compiler/rustc_trait_selection/src | |
| parent | 53801d3f085f8b635f0e0f668584c1d618cb1d9d (diff) | |
| parent | 65dfca8488d635552eb246eb8e15df646e987cff (diff) | |
| download | rust-efa68d02d2ee74f7b70703caef44ff53b92fe910.tar.gz rust-efa68d02d2ee74f7b70703caef44ff53b92fe910.zip | |
Merge from rustc
Diffstat (limited to 'compiler/rustc_trait_selection/src')
14 files changed, 311 insertions, 74 deletions
diff --git a/compiler/rustc_trait_selection/src/errors.rs b/compiler/rustc_trait_selection/src/errors.rs index df7c4df1868..54e22cc3d7f 100644 --- a/compiler/rustc_trait_selection/src/errors.rs +++ b/compiler/rustc_trait_selection/src/errors.rs @@ -89,3 +89,11 @@ impl IntoDiagnostic<'_> for NegativePositiveConflict<'_> { diag } } + +#[derive(Diagnostic)] +#[diag(trait_selection_inherent_projection_normalization_overflow)] +pub struct InherentProjectionNormalizationOverflow { + #[primary_span] + pub span: Span, + pub ty: String, +} diff --git a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs index 996dc329dcb..0ede32c753c 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs @@ -33,7 +33,7 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait<'tcx>( ty::Dynamic(..) | ty::Param(..) | ty::Foreign(..) - | ty::Alias(ty::Projection, ..) + | ty::Alias(ty::Projection | ty::Inherent, ..) | ty::Placeholder(..) | ty::Bound(..) | ty::Infer(_) => { diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs index 6c98fadd148..04b38edc126 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs @@ -655,7 +655,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { ty::Dynamic(..) | ty::Param(..) | ty::Foreign(..) - | ty::Alias(ty::Projection, ..) + | ty::Alias(ty::Projection | ty::Inherent, ..) | ty::Placeholder(..) => Some(Err(NoSolution)), ty::Infer(_) | ty::Bound(_, _) => bug!("unexpected type `{self_ty}`"), diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index b7690f79933..969e5fa64b0 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -322,7 +322,9 @@ fn negative_impl(tcx: TyCtxt<'_>, impl1_def_id: DefId, impl2_def_id: DefId) -> b let selcx = &mut SelectionContext::new(&infcx); let impl2_substs = infcx.fresh_substs_for_item(DUMMY_SP, impl2_def_id); let (subject2, obligations) = - impl_subject_and_oblig(selcx, impl_env, impl2_def_id, impl2_substs); + impl_subject_and_oblig(selcx, impl_env, impl2_def_id, impl2_substs, |_, _| { + ObligationCause::dummy() + }); !equate(&infcx, impl_env, subject1, subject2, obligations, impl1_def_id) } @@ -673,7 +675,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for OrphanChecker<'tcx> { | ty::RawPtr(..) | ty::Never | ty::Tuple(..) - | ty::Alias(ty::Projection, ..) => self.found_non_local_ty(ty), + | ty::Alias(ty::Projection | ty::Inherent, ..) => self.found_non_local_ty(ty), ty::Param(..) => self.found_param_ty(ty), diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index afb64da8b61..c9e2ed092d1 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -1687,13 +1687,14 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { ty::Tuple(..) => Some(10), ty::Param(..) => Some(11), ty::Alias(ty::Projection, ..) => Some(12), - ty::Alias(ty::Opaque, ..) => Some(13), - ty::Never => Some(14), - ty::Adt(..) => Some(15), - ty::Generator(..) => Some(16), - ty::Foreign(..) => Some(17), - ty::GeneratorWitness(..) => Some(18), - ty::GeneratorWitnessMIR(..) => Some(19), + ty::Alias(ty::Inherent, ..) => Some(13), + ty::Alias(ty::Opaque, ..) => Some(14), + ty::Never => Some(15), + ty::Adt(..) => Some(16), + ty::Generator(..) => Some(17), + ty::Foreign(..) => Some(18), + ty::GeneratorWitness(..) => Some(19), + ty::GeneratorWitnessMIR(..) => Some(20), ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) | ty::Error(_) => None, } } diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index d8e5725d3ca..38daca5377a 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -49,12 +49,15 @@ pub use self::object_safety::astconv_object_safety_violations; pub use self::object_safety::is_vtable_safe_method; pub use self::object_safety::MethodViolationCode; pub use self::object_safety::ObjectSafetyViolation; -pub use self::project::{normalize_projection_type, NormalizeExt}; +pub use self::project::NormalizeExt; +pub use self::project::{normalize_inherent_projection, normalize_projection_type}; pub use self::select::{EvaluationCache, SelectionCache, SelectionContext}; pub use self::select::{EvaluationResult, IntercrateAmbiguityCause, OverflowError}; pub use self::specialize::specialization_graph::FutureCompatOverlapError; pub use self::specialize::specialization_graph::FutureCompatOverlapErrorKind; -pub use self::specialize::{specialization_graph, translate_substs, OverlapError}; +pub use self::specialize::{ + specialization_graph, translate_substs, translate_substs_with_cause, OverlapError, +}; pub use self::structural_match::{ search_for_adt_const_param_violation, search_for_structural_match_violation, }; diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 8c74860cdf3..8e684b7ac23 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -16,6 +16,7 @@ use super::{ }; use super::{Normalized, NormalizedTy, ProjectionCacheEntry, ProjectionCacheKey}; +use crate::errors::InherentProjectionNormalizationOverflow; use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use crate::infer::{InferCtxt, InferOk, LateBoundRegionConversionTime}; use crate::traits::error_reporting::TypeErrCtxtExt as _; @@ -370,10 +371,14 @@ pub(crate) fn needs_normalization<'tcx, T: TypeVisitable<TyCtxt<'tcx>>>( reveal: Reveal, ) -> bool { match reveal { - Reveal::UserFacing => value - .has_type_flags(ty::TypeFlags::HAS_TY_PROJECTION | ty::TypeFlags::HAS_CT_PROJECTION), + Reveal::UserFacing => value.has_type_flags( + ty::TypeFlags::HAS_TY_PROJECTION + | ty::TypeFlags::HAS_TY_INHERENT + | ty::TypeFlags::HAS_CT_PROJECTION, + ), Reveal::All => value.has_type_flags( ty::TypeFlags::HAS_TY_PROJECTION + | ty::TypeFlags::HAS_TY_INHERENT | ty::TypeFlags::HAS_TY_OPAQUE | ty::TypeFlags::HAS_CT_PROJECTION, ), @@ -616,6 +621,51 @@ impl<'a, 'b, 'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTypeNormalizer<'a, 'b, 'tcx ); normalized_ty } + + ty::Inherent if !data.has_escaping_bound_vars() => { + // This branch is *mostly* just an optimization: when we don't + // have escaping bound vars, we don't need to replace them with + // placeholders (see branch below). *Also*, we know that we can + // register an obligation to *later* project, since we know + // there won't be bound vars there. + + let data = data.fold_with(self); + + // FIXME(inherent_associated_types): Do we need to honor `self.eager_inference_replacement` + // here like `ty::Projection`? + normalize_inherent_projection( + self.selcx, + self.param_env, + data, + self.cause.clone(), + self.depth, + &mut self.obligations, + ) + } + + ty::Inherent => { + let infcx = self.selcx.infcx; + let (data, mapped_regions, mapped_types, mapped_consts) = + BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, data); + let data = data.fold_with(self); + let ty = normalize_inherent_projection( + self.selcx, + self.param_env, + data, + self.cause.clone(), + self.depth, + &mut self.obligations, + ); + + PlaceholderReplacer::replace_placeholders( + infcx, + mapped_regions, + mapped_types, + mapped_consts, + &self.universes, + ty, + ) + } } } @@ -1204,6 +1254,115 @@ fn normalize_to_error<'a, 'tcx>( Normalized { value: new_value, obligations: vec![trait_obligation] } } +/// Confirm and normalize the given inherent projection. +#[instrument(level = "debug", skip(selcx, param_env, cause, obligations))] +pub fn normalize_inherent_projection<'a, 'b, 'tcx>( + selcx: &'a mut SelectionContext<'b, 'tcx>, + param_env: ty::ParamEnv<'tcx>, + alias_ty: ty::AliasTy<'tcx>, + cause: ObligationCause<'tcx>, + depth: usize, + obligations: &mut Vec<PredicateObligation<'tcx>>, +) -> Ty<'tcx> { + let tcx = selcx.tcx(); + + if !tcx.recursion_limit().value_within_limit(depth) { + // Halt compilation because it is important that overflows never be masked. + tcx.sess.emit_fatal(InherentProjectionNormalizationOverflow { + span: cause.span, + ty: alias_ty.to_string(), + }); + } + + let substs = compute_inherent_assoc_ty_substs( + selcx, + param_env, + alias_ty, + cause.clone(), + depth, + obligations, + ); + + // Register the obligations arising from the impl and from the associated type itself. + let predicates = tcx.predicates_of(alias_ty.def_id).instantiate(tcx, substs); + for (predicate, span) in predicates { + let predicate = normalize_with_depth_to( + selcx, + param_env, + cause.clone(), + depth + 1, + predicate, + obligations, + ); + + let nested_cause = ObligationCause::new( + cause.span, + cause.body_id, + // FIXME(inherent_associated_types): Since we can't pass along the self type to the + // cause code, inherent projections will be printed with identity substitutions in + // diagnostics which is not ideal. + // Consider creating separate cause codes for this specific situation. + if span.is_dummy() { + super::ItemObligation(alias_ty.def_id) + } else { + super::BindingObligation(alias_ty.def_id, span) + }, + ); + + obligations.push(Obligation::with_depth( + tcx, + nested_cause, + depth + 1, + param_env, + predicate, + )); + } + + let ty = tcx.type_of(alias_ty.def_id).subst(tcx, substs); + + let mut ty = selcx.infcx.resolve_vars_if_possible(ty); + if ty.has_projections() { + ty = normalize_with_depth_to(selcx, param_env, cause.clone(), depth + 1, ty, obligations); + } + + ty +} + +pub fn compute_inherent_assoc_ty_substs<'a, 'b, 'tcx>( + selcx: &'a mut SelectionContext<'b, 'tcx>, + param_env: ty::ParamEnv<'tcx>, + alias_ty: ty::AliasTy<'tcx>, + cause: ObligationCause<'tcx>, + depth: usize, + obligations: &mut Vec<PredicateObligation<'tcx>>, +) -> ty::SubstsRef<'tcx> { + let tcx = selcx.tcx(); + + let impl_def_id = tcx.parent(alias_ty.def_id); + let impl_substs = selcx.infcx.fresh_substs_for_item(cause.span, impl_def_id); + + let impl_ty = tcx.type_of(impl_def_id).subst(tcx, impl_substs); + let impl_ty = + normalize_with_depth_to(selcx, param_env, cause.clone(), depth + 1, impl_ty, obligations); + + // Infer the generic parameters of the impl by unifying the + // impl type with the self type of the projection. + let self_ty = alias_ty.self_ty(); + match selcx.infcx.at(&cause, param_env).eq(DefineOpaqueTypes::No, impl_ty, self_ty) { + Ok(mut ok) => obligations.append(&mut ok.obligations), + Err(_) => { + tcx.sess.delay_span_bug( + cause.span, + format!( + "{self_ty:?} was a subtype of {impl_ty:?} during selection but now it is not" + ), + ); + } + } + + alias_ty.rebase_substs_onto_impl(impl_substs, tcx) +} + enum Projected<'tcx> { Progress(Progress<'tcx>), NoProgress(ty::Term<'tcx>), diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs index a986a9b6a71..8bf934cb78a 100644 --- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs @@ -257,11 +257,11 @@ impl<'cx, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'cx, 'tcx> ty::Opaque => ty.try_super_fold_with(self)?, - ty::Projection => { + ty::Projection | ty::Inherent => { // See note in `rustc_trait_selection::traits::project` - let tcx = self.infcx.tcx; let infcx = self.infcx; + let tcx = infcx.tcx; // Just an optimization: When we don't have escaping bound vars, // we don't need to replace them with placeholders. let (data, maps) = if data.has_escaping_bound_vars() { @@ -276,12 +276,15 @@ impl<'cx, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'cx, 'tcx> let mut orig_values = OriginalQueryValues::default(); // HACK(matthewjasper) `'static` is special-cased in selection, // so we cannot canonicalize it. - let c_data = self - .infcx + let c_data = infcx .canonicalize_query_keep_static(self.param_env.and(data), &mut orig_values); debug!("QueryNormalizer: c_data = {:#?}", c_data); debug!("QueryNormalizer: orig_values = {:#?}", orig_values); - let result = tcx.normalize_projection_ty(c_data)?; + let result = match kind { + ty::Projection => tcx.normalize_projection_ty(c_data), + ty::Inherent => tcx.normalize_inherent_projection_ty(c_data), + _ => unreachable!(), + }?; // We don't expect ambiguity. if result.is_ambiguous() { // Rustdoc normalizes possibly not well-formed types, so only @@ -294,8 +297,8 @@ impl<'cx, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'cx, 'tcx> } return Err(NoSolution); } - let InferOk { value: result, obligations } = - self.infcx.instantiate_query_response_and_region_obligations( + let InferOk { value: result, obligations } = infcx + .instantiate_query_response_and_region_obligations( self.cause, self.param_env, &orig_values, 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 33f502f8182..a8fb55df2d3 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -498,7 +498,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // this trait and type. } ty::Param(..) - | ty::Alias(ty::Projection, ..) + | ty::Alias(ty::Projection | ty::Inherent, ..) | ty::Placeholder(..) | ty::Bound(..) => { // In these cases, we don't know what the actual diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 422285d9474..616187b69dd 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -1268,7 +1268,7 @@ 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::Alias(ty::Projection | ty::Inherent, ..) => { let predicate = normalize_with_depth_to( self, obligation.param_env, diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 246d3ea2ef2..e4f5a84f424 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -2315,7 +2315,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> { | ty::Dynamic(..) | ty::Param(..) | ty::Foreign(..) - | ty::Alias(ty::Projection, ..) + | ty::Alias(ty::Projection | ty::Inherent, ..) | ty::Bound(..) | ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => { bug!("asked to assemble constituent types of unexpected type: {:?}", t); diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs index 233d35aed38..9a4b72013b8 100644 --- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs @@ -83,6 +83,30 @@ pub fn translate_substs<'tcx>( source_substs: SubstsRef<'tcx>, target_node: specialization_graph::Node, ) -> SubstsRef<'tcx> { + translate_substs_with_cause( + infcx, + param_env, + source_impl, + source_substs, + target_node, + |_, _| ObligationCause::dummy(), + ) +} + +/// Like [translate_substs], but obligations from the parent implementation +/// are registered with the provided `ObligationCause`. +/// +/// This is for reporting *region* errors from those bounds. Type errors should +/// not happen because the specialization graph already checks for those, and +/// will result in an ICE. +pub fn translate_substs_with_cause<'tcx>( + infcx: &InferCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, + source_impl: DefId, + source_substs: SubstsRef<'tcx>, + target_node: specialization_graph::Node, + cause: impl Fn(usize, Span) -> ObligationCause<'tcx>, +) -> SubstsRef<'tcx> { debug!( "translate_substs({:?}, {:?}, {:?}, {:?})", param_env, source_impl, source_substs, target_node @@ -99,14 +123,13 @@ pub fn translate_substs<'tcx>( return source_substs; } - fulfill_implication(infcx, param_env, source_trait_ref, target_impl).unwrap_or_else( - |()| { + fulfill_implication(infcx, param_env, source_trait_ref, source_impl, target_impl, cause) + .unwrap_or_else(|()| { bug!( "When translating substitutions from {source_impl:?} to {target_impl:?}, \ the expected specialization failed to hold" ) - }, - ) + }) } specialization_graph::Node::Trait(..) => source_trait_ref.substs, }; @@ -153,20 +176,12 @@ pub(super) fn specializes(tcx: TyCtxt<'_>, (impl1_def_id, impl2_def_id): (DefId, // Create an infcx, taking the predicates of impl1 as assumptions: let infcx = tcx.infer_ctxt().build(); - let impl1_trait_ref = - match traits::fully_normalize(&infcx, ObligationCause::dummy(), penv, impl1_trait_ref) { - Ok(impl1_trait_ref) => impl1_trait_ref, - Err(_errors) => { - tcx.sess.delay_span_bug( - tcx.def_span(impl1_def_id), - format!("failed to fully normalize {impl1_trait_ref}"), - ); - impl1_trait_ref - } - }; // Attempt to prove that impl2 applies, given all of the above. - fulfill_implication(&infcx, penv, impl1_trait_ref, impl2_def_id).is_ok() + fulfill_implication(&infcx, penv, impl1_trait_ref, impl1_def_id, impl2_def_id, |_, _| { + ObligationCause::dummy() + }) + .is_ok() } /// Attempt to fulfill all obligations of `target_impl` after unification with @@ -178,23 +193,41 @@ fn fulfill_implication<'tcx>( infcx: &InferCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, source_trait_ref: ty::TraitRef<'tcx>, + source_impl: DefId, target_impl: DefId, + error_cause: impl Fn(usize, Span) -> ObligationCause<'tcx>, ) -> Result<SubstsRef<'tcx>, ()> { debug!( "fulfill_implication({:?}, trait_ref={:?} |- {:?} applies)", param_env, source_trait_ref, target_impl ); + let source_trait_ref = match traits::fully_normalize( + &infcx, + ObligationCause::dummy(), + param_env, + source_trait_ref, + ) { + Ok(source_trait_ref) => source_trait_ref, + Err(_errors) => { + infcx.tcx.sess.delay_span_bug( + infcx.tcx.def_span(source_impl), + format!("failed to fully normalize {source_trait_ref}"), + ); + source_trait_ref + } + }; + let source_trait = ImplSubject::Trait(source_trait_ref); let selcx = &mut SelectionContext::new(&infcx); let target_substs = infcx.fresh_substs_for_item(DUMMY_SP, target_impl); let (target_trait, obligations) = - util::impl_subject_and_oblig(selcx, param_env, target_impl, target_substs); + util::impl_subject_and_oblig(selcx, param_env, target_impl, target_substs, error_cause); // do the impls unify? If not, no specialization. let Ok(InferOk { obligations: more_obligations, .. }) = - infcx.at(&ObligationCause::dummy(), param_env, ).eq(DefineOpaqueTypes::No,source_trait, target_trait) + infcx.at(&ObligationCause::dummy(), param_env).eq(DefineOpaqueTypes::No, source_trait, target_trait) else { debug!( "fulfill_implication: {:?} does not unify with {:?}", diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs index 7b7e297c64b..82f3df40198 100644 --- a/compiler/rustc_trait_selection/src/traits/util.rs +++ b/compiler/rustc_trait_selection/src/traits/util.rs @@ -197,6 +197,7 @@ pub fn impl_subject_and_oblig<'a, 'tcx>( param_env: ty::ParamEnv<'tcx>, impl_def_id: DefId, impl_substs: SubstsRef<'tcx>, + cause: impl Fn(usize, Span) -> ObligationCause<'tcx>, ) -> (ImplSubject<'tcx>, impl Iterator<Item = PredicateObligation<'tcx>>) { let subject = selcx.tcx().impl_subject(impl_def_id); let subject = subject.subst(selcx.tcx(), impl_substs); @@ -208,8 +209,7 @@ pub fn impl_subject_and_oblig<'a, 'tcx>( let predicates = predicates.instantiate(selcx.tcx(), impl_substs); let InferOk { value: predicates, obligations: normalization_obligations2 } = selcx.infcx.at(&ObligationCause::dummy(), param_env).normalize(predicates); - let impl_obligations = - super::predicates_for_generics(|_, _| ObligationCause::dummy(), param_env, predicates); + let impl_obligations = super::predicates_for_generics(cause, param_env, predicates); let impl_obligations = impl_obligations .chain(normalization_obligations1.into_iter()) diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index 22710c7c059..086ab32b520 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -58,15 +58,8 @@ pub fn obligations<'tcx>( GenericArgKind::Lifetime(..) => return Some(Vec::new()), }; - let mut wf = WfPredicates { - tcx: infcx.tcx, - param_env, - body_id, - span, - out: vec![], - recursion_depth, - item: None, - }; + let mut wf = + WfPredicates { infcx, param_env, body_id, span, out: vec![], recursion_depth, item: None }; wf.compute(arg); debug!("wf::obligations({:?}, body_id={:?}) = {:?}", arg, body_id, wf.out); @@ -91,7 +84,7 @@ pub fn unnormalized_obligations<'tcx>( debug_assert_eq!(arg, infcx.resolve_vars_if_possible(arg)); let mut wf = WfPredicates { - tcx: infcx.tcx, + infcx, param_env, body_id: CRATE_DEF_ID, span: DUMMY_SP, @@ -116,7 +109,7 @@ pub fn trait_obligations<'tcx>( item: &'tcx hir::Item<'tcx>, ) -> Vec<traits::PredicateObligation<'tcx>> { let mut wf = WfPredicates { - tcx: infcx.tcx, + infcx, param_env, body_id, span, @@ -138,7 +131,7 @@ pub fn predicate_obligations<'tcx>( span: Span, ) -> Vec<traits::PredicateObligation<'tcx>> { let mut wf = WfPredicates { - tcx: infcx.tcx, + infcx, param_env, body_id, span, @@ -190,8 +183,8 @@ pub fn predicate_obligations<'tcx>( wf.normalize(infcx) } -struct WfPredicates<'tcx> { - tcx: TyCtxt<'tcx>, +struct WfPredicates<'a, 'tcx> { + infcx: &'a InferCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, body_id: LocalDefId, span: Span, @@ -290,9 +283,9 @@ fn extend_cause_with_original_assoc_item_obligation<'tcx>( } } -impl<'tcx> WfPredicates<'tcx> { +impl<'a, 'tcx> WfPredicates<'a, 'tcx> { fn tcx(&self) -> TyCtxt<'tcx> { - self.tcx + self.infcx.tcx } fn cause(&self, code: traits::ObligationCauseCode<'tcx>) -> traits::ObligationCause<'tcx> { @@ -325,7 +318,7 @@ impl<'tcx> WfPredicates<'tcx> { /// Pushes the obligations required for `trait_ref` to be WF into `self.out`. fn compute_trait_pred(&mut self, trait_pred: &ty::TraitPredicate<'tcx>, elaborate: Elaborate) { - let tcx = self.tcx; + let tcx = self.tcx(); let trait_ref = &trait_pred.trait_ref; // Negative trait predicates don't require supertraits to hold, just @@ -369,7 +362,6 @@ impl<'tcx> WfPredicates<'tcx> { self.out.extend(obligations); } - let tcx = self.tcx(); self.out.extend( trait_ref .substs @@ -436,13 +428,45 @@ impl<'tcx> WfPredicates<'tcx> { let obligations = self.nominal_obligations_without_const(data.def_id, data.substs); self.out.extend(obligations); + self.compute_projection_substs(data.substs); + } + + fn compute_inherent_projection(&mut self, data: ty::AliasTy<'tcx>) { + // An inherent projection is well-formed if + // + // (a) its predicates hold (*) + // (b) its substs are wf + // + // (*) The predicates of an inherent associated type include the + // predicates of the impl that it's contained in. + + if !data.self_ty().has_escaping_bound_vars() { + // FIXME(inherent_associated_types): Should this happen inside of a snapshot? + // FIXME(inherent_associated_types): This is incompatible with the new solver and lazy norm! + let substs = traits::project::compute_inherent_assoc_ty_substs( + &mut traits::SelectionContext::new(self.infcx), + self.param_env, + data, + self.cause(traits::WellFormed(None)), + self.recursion_depth, + &mut self.out, + ); + // Inherent projection types do not require const predicates. + let obligations = self.nominal_obligations_without_const(data.def_id, substs); + self.out.extend(obligations); + } + + self.compute_projection_substs(data.substs); + } + + fn compute_projection_substs(&mut self, substs: SubstsRef<'tcx>) { let tcx = self.tcx(); let cause = self.cause(traits::WellFormed(None)); let param_env = self.param_env; let depth = self.recursion_depth; self.out.extend( - data.substs + substs .iter() .filter(|arg| { matches!(arg.unpack(), GenericArgKind::Type(..) | GenericArgKind::Const(..)) @@ -464,9 +488,9 @@ impl<'tcx> WfPredicates<'tcx> { if !subty.has_escaping_bound_vars() { let cause = self.cause(cause); let trait_ref = - ty::TraitRef::from_lang_item(self.tcx, LangItem::Sized, cause.span, [subty]); + ty::TraitRef::from_lang_item(self.tcx(), LangItem::Sized, cause.span, [subty]); self.out.push(traits::Obligation::with_depth( - self.tcx, + self.tcx(), cause, self.recursion_depth, self.param_env, @@ -605,6 +629,10 @@ impl<'tcx> WfPredicates<'tcx> { walker.skip_current_subtree(); // Subtree handled by compute_projection. self.compute_projection(data); } + ty::Alias(ty::Inherent, data) => { + walker.skip_current_subtree(); // Subtree handled by compute_inherent_projection. + self.compute_inherent_projection(data); + } ty::Adt(def, substs) => { // WfNominalType @@ -697,7 +725,7 @@ impl<'tcx> WfPredicates<'tcx> { // All of the requirements on type parameters // have already been checked for `impl Trait` in // return position. We do need to check type-alias-impl-trait though. - if self.tcx.is_type_alias_impl_trait(def_id) { + if self.tcx().is_type_alias_impl_trait(def_id) { let obligations = self.nominal_obligations(def_id, substs); self.out.extend(obligations); } @@ -767,15 +795,15 @@ impl<'tcx> WfPredicates<'tcx> { substs: SubstsRef<'tcx>, remap_constness: bool, ) -> Vec<traits::PredicateObligation<'tcx>> { - let predicates = self.tcx.predicates_of(def_id); + let predicates = self.tcx().predicates_of(def_id); let mut origins = vec![def_id; predicates.predicates.len()]; let mut head = predicates; while let Some(parent) = head.parent { - head = self.tcx.predicates_of(parent); + head = self.tcx().predicates_of(parent); origins.extend(iter::repeat(parent).take(head.predicates.len())); } - let predicates = predicates.instantiate(self.tcx, substs); + let predicates = predicates.instantiate(self.tcx(), substs); trace!("{:#?}", predicates); debug_assert_eq!(predicates.predicates.len(), origins.len()); @@ -788,10 +816,10 @@ impl<'tcx> WfPredicates<'tcx> { }; let cause = self.cause(code); if remap_constness { - pred = pred.without_const(self.tcx); + pred = pred.without_const(self.tcx()); } traits::Obligation::with_depth( - self.tcx, + self.tcx(), cause, self.recursion_depth, self.param_env, @@ -856,7 +884,7 @@ impl<'tcx> WfPredicates<'tcx> { // Note: in fact we only permit builtin traits, not `Bar<'d>`, I // am looking forward to the future here. if !data.has_escaping_bound_vars() && !region.has_escaping_bound_vars() { - let implicit_bounds = object_region_bounds(self.tcx, data); + let implicit_bounds = object_region_bounds(self.tcx(), data); let explicit_bound = region; @@ -866,7 +894,7 @@ impl<'tcx> WfPredicates<'tcx> { let outlives = ty::Binder::dummy(ty::OutlivesPredicate(explicit_bound, implicit_bound)); self.out.push(traits::Obligation::with_depth( - self.tcx, + self.tcx(), cause, self.recursion_depth, self.param_env, |
