1
Fork 0

Move InferCtxtExt to rustc_trait_selection

This commit is contained in:
Santiago Pastorino 2022-08-22 16:53:34 -03:00
parent 1cff564203
commit 5ff45dc89e
No known key found for this signature in database
GPG key ID: 8131A24E0C79EFAF
7 changed files with 9 additions and 8 deletions

View file

@ -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]

View file

@ -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;

View file

@ -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<Item = OutlivesBound<'tcx>> + 'a;
pub trait InferCtxtExt<'a, 'tcx> {
fn implied_outlives_bounds(
&self,
param_env: ty::ParamEnv<'tcx>,
body_id: hir::HirId,
ty: Ty<'tcx>,
) -> Vec<OutlivesBound<'tcx>>;
fn implied_bounds_tys(
&'a self,
param_env: ty::ParamEnv<'tcx>,
body_id: hir::HirId,
tys: FxHashSet<Ty<'tcx>>,
) -> 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<OutlivesBound<'tcx>> {
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 = <dyn TraitEngine<'tcx>>::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<Ty<'tcx>>,
) -> 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()
}
}