diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 852780fccace9..8e684b7ac239b 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -1274,29 +1274,14 @@ pub fn normalize_inherent_projection<'a, 'b, '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" - ), - ); - } - } - - let substs = alias_ty.rebase_substs_onto_impl(impl_substs, tcx); + 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); @@ -1343,6 +1328,41 @@ pub fn normalize_inherent_projection<'a, 'b, 'tcx>( 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>, +) -> 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/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index e5edceda94446..086ab32b52007 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> { 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> { 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,8 +629,9 @@ impl<'tcx> WfPredicates<'tcx> { walker.skip_current_subtree(); // Subtree handled by compute_projection. self.compute_projection(data); } - ty::Alias(ty::Inherent, _) => { - // WF if their substs are WF. + ty::Alias(ty::Inherent, data) => { + walker.skip_current_subtree(); // Subtree handled by compute_inherent_projection. + self.compute_inherent_projection(data); } ty::Adt(def, substs) => { @@ -700,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); } @@ -770,15 +795,15 @@ impl<'tcx> WfPredicates<'tcx> { substs: SubstsRef<'tcx>, remap_constness: bool, ) -> Vec> { - 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()); @@ -791,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, @@ -859,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; @@ -869,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,