From 5ff45dc89efdaabe903e5bff4dc1c170def7b325 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Mon, 22 Aug 2022 16:53:34 -0300 Subject: Move InferCtxtExt to rustc_trait_selection --- compiler/rustc_trait_selection/src/lib.rs | 1 + compiler/rustc_trait_selection/src/traits/mod.rs | 1 + .../src/traits/outlives_bounds.rs | 114 +++++++++++++++++++++ compiler/rustc_typeck/src/check/compare_method.rs | 2 +- compiler/rustc_typeck/src/check/wfcheck.rs | 2 +- .../src/impl_wf_check/min_specialization.rs | 2 +- compiler/rustc_typeck/src/outlives/mod.rs | 1 - .../rustc_typeck/src/outlives/outlives_bounds.rs | 114 --------------------- 8 files changed, 119 insertions(+), 118 deletions(-) create mode 100644 compiler/rustc_trait_selection/src/traits/outlives_bounds.rs delete mode 100644 compiler/rustc_typeck/src/outlives/outlives_bounds.rs (limited to 'compiler') diff --git a/compiler/rustc_trait_selection/src/lib.rs b/compiler/rustc_trait_selection/src/lib.rs index 9c252fcfe1c..ce48d4c99e9 100644 --- a/compiler/rustc_trait_selection/src/lib.rs +++ b/compiler/rustc_trait_selection/src/lib.rs @@ -20,6 +20,7 @@ #![feature(let_else)] #![feature(if_let_guard)] #![feature(never_type)] +#![feature(type_alias_impl_trait)] #![recursion_limit = "512"] // For rustdoc #[macro_use] diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 85ff6e23711..86471eeb070 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -13,6 +13,7 @@ mod fulfill; pub mod misc; mod object_safety; mod on_unimplemented; +pub mod outlives_bounds; mod project; pub mod query; pub(crate) mod relationships; diff --git a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs new file mode 100644 index 00000000000..a4b54018228 --- /dev/null +++ b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs @@ -0,0 +1,114 @@ +use crate::infer::InferCtxt; +use crate::traits::query::type_op::{self, TypeOp, TypeOpOutput}; +use crate::traits::query::NoSolution; +use crate::traits::{ObligationCause, TraitEngine, TraitEngineExt}; +use rustc_data_structures::fx::FxHashSet; +use rustc_hir as hir; +use rustc_hir::HirId; +use rustc_middle::ty::{self, ParamEnv, Ty}; + +pub use rustc_middle::traits::query::OutlivesBound; + +type Bounds<'a, 'tcx: 'a> = impl Iterator> + 'a; +pub trait InferCtxtExt<'a, 'tcx> { + fn implied_outlives_bounds( + &self, + param_env: ty::ParamEnv<'tcx>, + body_id: hir::HirId, + ty: Ty<'tcx>, + ) -> Vec>; + + fn implied_bounds_tys( + &'a self, + param_env: ty::ParamEnv<'tcx>, + body_id: hir::HirId, + tys: FxHashSet>, + ) -> Bounds<'a, 'tcx>; +} + +impl<'a, 'cx, 'tcx: 'a> InferCtxtExt<'a, 'tcx> for InferCtxt<'cx, 'tcx> { + /// Implied bounds are region relationships that we deduce + /// automatically. The idea is that (e.g.) a caller must check that a + /// function's argument types are well-formed immediately before + /// calling that fn, and hence the *callee* can assume that its + /// argument types are well-formed. This may imply certain relationships + /// between generic parameters. For example: + /// ``` + /// fn foo<'a,T>(x: &'a T) {} + /// ``` + /// can only be called with a `'a` and `T` such that `&'a T` is WF. + /// For `&'a T` to be WF, `T: 'a` must hold. So we can assume `T: 'a`. + /// + /// # Parameters + /// + /// - `param_env`, the where-clauses in scope + /// - `body_id`, the body-id to use when normalizing assoc types. + /// Note that this may cause outlives obligations to be injected + /// into the inference context with this body-id. + /// - `ty`, the type that we are supposed to assume is WF. + #[instrument(level = "debug", skip(self, param_env, body_id))] + fn implied_outlives_bounds( + &self, + param_env: ty::ParamEnv<'tcx>, + body_id: hir::HirId, + ty: Ty<'tcx>, + ) -> Vec> { + let span = self.tcx.hir().span(body_id); + let result = param_env + .and(type_op::implied_outlives_bounds::ImpliedOutlivesBounds { ty }) + .fully_perform(self); + let result = match result { + Ok(r) => r, + Err(NoSolution) => { + self.tcx.sess.delay_span_bug( + span, + "implied_outlives_bounds failed to solve all obligations", + ); + return vec![]; + } + }; + + let TypeOpOutput { output, constraints, .. } = result; + + if let Some(constraints) = constraints { + // Instantiation may have produced new inference variables and constraints on those + // variables. Process these constraints. + let mut fulfill_cx = >::new(self.tcx); + let cause = ObligationCause::misc(span, body_id); + for &constraint in &constraints.outlives { + let obligation = self.query_outlives_constraint_to_obligation( + constraint, + cause.clone(), + param_env, + ); + fulfill_cx.register_predicate_obligation(self, obligation); + } + if !constraints.member_constraints.is_empty() { + span_bug!(span, "{:#?}", constraints.member_constraints); + } + let errors = fulfill_cx.select_all_or_error(self); + if !errors.is_empty() { + self.tcx.sess.delay_span_bug( + span, + "implied_outlives_bounds failed to solve obligations from instantiation", + ); + } + }; + + output + } + + fn implied_bounds_tys( + &'a self, + param_env: ParamEnv<'tcx>, + body_id: HirId, + tys: FxHashSet>, + ) -> Bounds<'a, 'tcx> { + tys.into_iter() + .map(move |ty| { + let ty = self.resolve_vars_if_possible(ty); + self.implied_outlives_bounds(param_env, body_id, ty) + }) + .flatten() + } +} diff --git a/compiler/rustc_typeck/src/check/compare_method.rs b/compiler/rustc_typeck/src/check/compare_method.rs index dfef924f699..af5e5622fb3 100644 --- a/compiler/rustc_typeck/src/check/compare_method.rs +++ b/compiler/rustc_typeck/src/check/compare_method.rs @@ -1,6 +1,5 @@ use super::potentially_plural_count; use crate::errors::LifetimesOrBoundsMismatchOnTrait; -use crate::outlives::outlives_bounds::InferCtxtExt as _; use rustc_data_structures::fx::FxHashSet; use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticId, ErrorGuaranteed}; use rustc_hir as hir; @@ -17,6 +16,7 @@ use rustc_middle::ty::{self, DefIdTree}; use rustc_middle::ty::{GenericParamDefKind, ToPredicate, TyCtxt}; use rustc_span::Span; use rustc_trait_selection::traits::error_reporting::InferCtxtExt; +use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _; use rustc_trait_selection::traits::{ self, ObligationCause, ObligationCauseCode, ObligationCtxt, Reveal, }; diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs index e8243d666b6..ce42647c837 100644 --- a/compiler/rustc_typeck/src/check/wfcheck.rs +++ b/compiler/rustc_typeck/src/check/wfcheck.rs @@ -1,5 +1,4 @@ use crate::constrained_generic_params::{identify_constrained_generic_params, Parameter}; -use crate::outlives::outlives_bounds::InferCtxtExt as _; use rustc_ast as ast; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed}; @@ -22,6 +21,7 @@ use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_span::{Span, DUMMY_SP}; use rustc_trait_selection::autoderef::Autoderef; use rustc_trait_selection::traits::error_reporting::InferCtxtExt; +use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _; use rustc_trait_selection::traits::{ self, ObligationCause, ObligationCauseCode, ObligationCtxt, WellFormedLoc, diff --git a/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs b/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs index 6240024d49c..2741d9f776c 100644 --- a/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs +++ b/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs @@ -67,7 +67,6 @@ use crate::constrained_generic_params as cgp; use crate::errors::SubstsOnOverriddenImpl; -use crate::outlives::outlives_bounds::InferCtxtExt as _; use rustc_data_structures::fx::FxHashSet; use rustc_hir::def_id::{DefId, LocalDefId}; @@ -79,6 +78,7 @@ use rustc_middle::ty::trait_def::TraitSpecializationKind; use rustc_middle::ty::{self, TyCtxt, TypeVisitable}; use rustc_span::Span; use rustc_trait_selection::traits::error_reporting::InferCtxtExt; +use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _; use rustc_trait_selection::traits::{self, translate_substs, wf, ObligationCtxt}; pub(super) fn check_min_specialization(tcx: TyCtxt<'_>, impl_def_id: LocalDefId) { diff --git a/compiler/rustc_typeck/src/outlives/mod.rs b/compiler/rustc_typeck/src/outlives/mod.rs index 8fa65d51e3b..e50c267659e 100644 --- a/compiler/rustc_typeck/src/outlives/mod.rs +++ b/compiler/rustc_typeck/src/outlives/mod.rs @@ -9,7 +9,6 @@ use rustc_span::Span; mod explicit; mod implicit_infer; -pub(crate) mod outlives_bounds; /// Code to write unit test for outlives. pub mod test; mod utils; diff --git a/compiler/rustc_typeck/src/outlives/outlives_bounds.rs b/compiler/rustc_typeck/src/outlives/outlives_bounds.rs deleted file mode 100644 index 024e20d9223..00000000000 --- a/compiler/rustc_typeck/src/outlives/outlives_bounds.rs +++ /dev/null @@ -1,114 +0,0 @@ -use rustc_data_structures::fx::FxHashSet; -use rustc_hir as hir; -use rustc_hir::HirId; -use rustc_middle::ty::{self, ParamEnv, Ty}; -use rustc_trait_selection::infer::InferCtxt; -use rustc_trait_selection::traits::query::type_op::{self, TypeOp, TypeOpOutput}; -use rustc_trait_selection::traits::query::NoSolution; -use rustc_trait_selection::traits::{ObligationCause, TraitEngine, TraitEngineExt}; - -pub use rustc_middle::traits::query::OutlivesBound; - -type Bounds<'a, 'tcx: 'a> = impl Iterator> + 'a; -pub trait InferCtxtExt<'a, 'tcx> { - fn implied_outlives_bounds( - &self, - param_env: ty::ParamEnv<'tcx>, - body_id: hir::HirId, - ty: Ty<'tcx>, - ) -> Vec>; - - fn implied_bounds_tys( - &'a self, - param_env: ty::ParamEnv<'tcx>, - body_id: hir::HirId, - tys: FxHashSet>, - ) -> Bounds<'a, 'tcx>; -} - -impl<'a, 'cx, 'tcx: 'a> InferCtxtExt<'a, 'tcx> for InferCtxt<'cx, 'tcx> { - /// Implied bounds are region relationships that we deduce - /// automatically. The idea is that (e.g.) a caller must check that a - /// function's argument types are well-formed immediately before - /// calling that fn, and hence the *callee* can assume that its - /// argument types are well-formed. This may imply certain relationships - /// between generic parameters. For example: - /// ``` - /// fn foo<'a,T>(x: &'a T) {} - /// ``` - /// can only be called with a `'a` and `T` such that `&'a T` is WF. - /// For `&'a T` to be WF, `T: 'a` must hold. So we can assume `T: 'a`. - /// - /// # Parameters - /// - /// - `param_env`, the where-clauses in scope - /// - `body_id`, the body-id to use when normalizing assoc types. - /// Note that this may cause outlives obligations to be injected - /// into the inference context with this body-id. - /// - `ty`, the type that we are supposed to assume is WF. - #[instrument(level = "debug", skip(self, param_env, body_id))] - fn implied_outlives_bounds( - &self, - param_env: ty::ParamEnv<'tcx>, - body_id: hir::HirId, - ty: Ty<'tcx>, - ) -> Vec> { - let span = self.tcx.hir().span(body_id); - let result = param_env - .and(type_op::implied_outlives_bounds::ImpliedOutlivesBounds { ty }) - .fully_perform(self); - let result = match result { - Ok(r) => r, - Err(NoSolution) => { - self.tcx.sess.delay_span_bug( - span, - "implied_outlives_bounds failed to solve all obligations", - ); - return vec![]; - } - }; - - let TypeOpOutput { output, constraints, .. } = result; - - if let Some(constraints) = constraints { - // Instantiation may have produced new inference variables and constraints on those - // variables. Process these constraints. - let mut fulfill_cx = >::new(self.tcx); - let cause = ObligationCause::misc(span, body_id); - for &constraint in &constraints.outlives { - let obligation = self.query_outlives_constraint_to_obligation( - constraint, - cause.clone(), - param_env, - ); - fulfill_cx.register_predicate_obligation(self, obligation); - } - if !constraints.member_constraints.is_empty() { - span_bug!(span, "{:#?}", constraints.member_constraints); - } - let errors = fulfill_cx.select_all_or_error(self); - if !errors.is_empty() { - self.tcx.sess.delay_span_bug( - span, - "implied_outlives_bounds failed to solve obligations from instantiation", - ); - } - }; - - output - } - - fn implied_bounds_tys( - &'a self, - param_env: ParamEnv<'tcx>, - body_id: HirId, - tys: FxHashSet>, - ) -> Bounds<'a, 'tcx> { - tys.into_iter() - .map(move |ty| { - let ty = self.resolve_vars_if_possible(ty); - self.implied_outlives_bounds(param_env, body_id, ty) - }) - .flatten() - } -} -- cgit 1.4.1-3-g733a5