Return the canonicalized query from type ops

This commit is contained in:
Matthew Jasper 2021-03-06 11:12:25 +00:00 committed by Rémy Rakic
parent 842f0590db
commit 4421dd17fa
6 changed files with 53 additions and 39 deletions

View File

@ -11,6 +11,7 @@ use rustc_middle::ty::{self, RegionVid, Ty, TyCtxt};
use rustc_span::DUMMY_SP;
use rustc_trait_selection::traits::query::type_op::{self, TypeOp};
use std::rc::Rc;
use type_op::TypeOpOutput;
use crate::borrow_check::{
nll::ToRegionVid,
@ -255,7 +256,7 @@ impl UniversalRegionRelationsBuilder<'cx, 'tcx> {
let constraint_sets: Vec<_> = unnormalized_input_output_tys
.flat_map(|ty| {
debug!("build: input_or_output={:?}", ty);
let (ty, constraints1) = self
let TypeOpOutput { output: ty, constraints: constraints1, .. } = self
.param_env
.and(type_op::normalize::Normalize::new(ty))
.fully_perform(self.infcx)
@ -264,7 +265,11 @@ impl UniversalRegionRelationsBuilder<'cx, 'tcx> {
.tcx
.sess
.delay_span_bug(DUMMY_SP, &format!("failed to normalize {:?}", ty));
(self.infcx.tcx.ty_error(), None)
TypeOpOutput {
output: self.infcx.tcx.ty_error(),
constraints: None,
canonicalized_query: None,
}
});
let constraints2 = self.add_implied_bounds(ty);
normalized_inputs_and_output.push(ty);
@ -317,7 +322,7 @@ impl UniversalRegionRelationsBuilder<'cx, 'tcx> {
/// from this local.
fn add_implied_bounds(&mut self, ty: Ty<'tcx>) -> Option<Rc<QueryRegionConstraints<'tcx>>> {
debug!("add_implied_bounds(ty={:?})", ty);
let (bounds, constraints) = self
let TypeOpOutput { output: bounds, constraints, .. } = self
.param_env
.and(type_op::implied_outlives_bounds::ImpliedOutlivesBounds { ty })
.fully_perform(self.infcx)

View File

@ -5,7 +5,7 @@ use rustc_middle::mir::{BasicBlock, Body, ConstraintCategory, Local, Location};
use rustc_middle::ty::{Ty, TypeFoldable};
use rustc_trait_selection::traits::query::dropck_outlives::DropckOutlivesResult;
use rustc_trait_selection::traits::query::type_op::outlives::DropckOutlives;
use rustc_trait_selection::traits::query::type_op::TypeOp;
use rustc_trait_selection::traits::query::type_op::{TypeOp, TypeOpOutput};
use std::rc::Rc;
use crate::dataflow::impls::MaybeInitializedPlaces;
@ -519,9 +519,9 @@ impl LivenessContext<'_, '_, '_, 'tcx> {
debug!("compute_drop_data(dropped_ty={:?})", dropped_ty,);
let param_env = typeck.param_env;
let (dropck_result, region_constraint_data) =
let TypeOpOutput { output, constraints, .. } =
param_env.and(DropckOutlives::new(dropped_ty)).fully_perform(typeck.infcx).unwrap();
DropData { dropck_result, region_constraint_data }
DropData { dropck_result: output, region_constraint_data: constraints }
}
}

View File

@ -40,6 +40,7 @@ use rustc_trait_selection::traits::query::type_op;
use rustc_trait_selection::traits::query::type_op::custom::CustomTypeOp;
use rustc_trait_selection::traits::query::{Fallible, NoSolution};
use rustc_trait_selection::traits::{self, ObligationCause, PredicateObligations};
use type_op::TypeOpOutput;
use crate::dataflow::impls::MaybeInitializedPlaces;
use crate::dataflow::move_paths::MoveData;
@ -1113,13 +1114,13 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
category: ConstraintCategory,
op: impl type_op::TypeOp<'tcx, Output = R>,
) -> Fallible<R> {
let (r, opt_data) = op.fully_perform(self.infcx)?;
let TypeOpOutput { output, constraints, .. } = op.fully_perform(self.infcx)?;
if let Some(data) = &opt_data {
if let Some(data) = &constraints {
self.push_region_constraints(locations, category, data);
}
Ok(r)
Ok(output)
}
fn push_region_constraints(

View File

@ -1,13 +1,13 @@
use crate::infer::{InferCtxt, InferOk};
use crate::traits::query::Fallible;
use std::fmt;
use crate::infer::canonical::query_response;
use crate::infer::canonical::QueryRegionConstraints;
use crate::infer::{InferCtxt, InferOk};
use crate::traits::engine::TraitEngineExt as _;
use crate::traits::query::type_op::TypeOpOutput;
use crate::traits::query::Fallible;
use crate::traits::{ObligationCause, TraitEngine};
use rustc_infer::traits::TraitEngineExt as _;
use rustc_span::source_map::DUMMY_SP;
use std::fmt;
use std::rc::Rc;
pub struct CustomTypeOp<F, G> {
@ -35,10 +35,7 @@ where
/// Processes the operation and all resulting obligations,
/// returning the final result along with any region constraints
/// (they will be given over to the NLL region solver).
fn fully_perform(
self,
infcx: &InferCtxt<'_, 'tcx>,
) -> Fallible<(Self::Output, Option<Rc<QueryRegionConstraints<'tcx>>>)> {
fn fully_perform(self, infcx: &InferCtxt<'_, 'tcx>) -> Fallible<TypeOpOutput<'tcx, Self>> {
if cfg!(debug_assertions) {
info!("fully_perform({:?})", self);
}
@ -58,10 +55,10 @@ where
/// Executes `op` and then scrapes out all the "old style" region
/// constraints that result, creating query-region-constraints.
fn scrape_region_constraints<'tcx, R>(
fn scrape_region_constraints<'tcx, Op: super::TypeOp<'tcx, Output = R>, R>(
infcx: &InferCtxt<'_, 'tcx>,
op: impl FnOnce() -> Fallible<InferOk<'tcx, R>>,
) -> Fallible<(R, Option<Rc<QueryRegionConstraints<'tcx>>>)> {
) -> Fallible<TypeOpOutput<'tcx, Op>> {
let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx);
let dummy_body_id = ObligationCause::dummy().body_id;
@ -101,8 +98,12 @@ fn scrape_region_constraints<'tcx, R>(
);
if region_constraints.is_empty() {
Ok((value, None))
Ok(TypeOpOutput { output: value, constraints: None, canonicalized_query: None })
} else {
Ok((value, Some(Rc::new(region_constraints))))
Ok(TypeOpOutput {
output: value,
constraints: Some(Rc::new(region_constraints)),
canonicalized_query: None,
})
}
}

View File

@ -3,7 +3,7 @@ use crate::traits::query::outlives_bounds::OutlivesBound;
use crate::traits::query::Fallible;
use rustc_middle::ty::{ParamEnvAnd, Ty, TyCtxt};
#[derive(Clone, Debug, HashStable, TypeFoldable, Lift)]
#[derive(Copy, Clone, Debug, HashStable, TypeFoldable, Lift)]
pub struct ImpliedOutlivesBounds<'tcx> {
pub ty: Ty<'tcx>,
}

View File

@ -4,6 +4,7 @@ use crate::infer::canonical::{
use crate::infer::{InferCtxt, InferOk};
use crate::traits::query::Fallible;
use crate::traits::ObligationCause;
use rustc_infer::infer::canonical::Canonical;
use rustc_middle::ty::fold::TypeFoldable;
use rustc_middle::ty::{ParamEnvAnd, TyCtxt};
use std::fmt;
@ -30,10 +31,18 @@ pub trait TypeOp<'tcx>: Sized + fmt::Debug {
/// Processes the operation and all resulting obligations,
/// returning the final result along with any region constraints
/// (they will be given over to the NLL region solver).
fn fully_perform(
self,
infcx: &InferCtxt<'_, 'tcx>,
) -> Fallible<(Self::Output, Option<Rc<QueryRegionConstraints<'tcx>>>)>;
fn fully_perform(self, infcx: &InferCtxt<'_, 'tcx>) -> Fallible<TypeOpOutput<'tcx, Self>>;
}
/// The output from performing a type op
pub struct TypeOpOutput<'tcx, Op: TypeOp<'tcx>> {
/// The output from the type op.
pub output: Op::Output,
/// Any region constraints from performing the type op.
pub constraints: Option<Rc<QueryRegionConstraints<'tcx>>>,
/// The canonicalized form of the query.
/// This for error reporting to be able to rerun the query.
pub canonicalized_query: Option<Canonical<'tcx, Op>>,
}
/// "Query type ops" are type ops that are implemented using a
@ -45,7 +54,7 @@ pub trait TypeOp<'tcx>: Sized + fmt::Debug {
/// which produces the resulting query region constraints.
///
/// [c]: https://rust-lang.github.io/chalk/book/canonical_queries/canonicalization.html
pub trait QueryTypeOp<'tcx>: fmt::Debug + Sized + TypeFoldable<'tcx> + 'tcx {
pub trait QueryTypeOp<'tcx>: fmt::Debug + Copy + TypeFoldable<'tcx> + 'tcx {
type QueryResponse: TypeFoldable<'tcx>;
/// Give query the option for a simple fast path that never
@ -71,9 +80,9 @@ pub trait QueryTypeOp<'tcx>: fmt::Debug + Sized + TypeFoldable<'tcx> + 'tcx {
query_key: ParamEnvAnd<'tcx, Self>,
infcx: &InferCtxt<'_, 'tcx>,
output_query_region_constraints: &mut QueryRegionConstraints<'tcx>,
) -> Fallible<Self::QueryResponse> {
) -> Fallible<(Self::QueryResponse, Option<Canonical<'tcx, ParamEnvAnd<'tcx, Self>>>)> {
if let Some(result) = QueryTypeOp::try_fast_path(infcx.tcx, &query_key) {
return Ok(result);
return Ok((result, None));
}
// FIXME(#33684) -- We need to use
@ -101,14 +110,14 @@ pub trait QueryTypeOp<'tcx>: fmt::Debug + Sized + TypeFoldable<'tcx> + 'tcx {
// create obligations. In that case, we have to go
// fulfill them. We do this via a (recursive) query.
for obligation in obligations {
let () = ProvePredicate::fully_perform_into(
let ((), _) = ProvePredicate::fully_perform_into(
obligation.param_env.and(ProvePredicate::new(obligation.predicate)),
infcx,
output_query_region_constraints,
)?;
}
Ok(value)
Ok((value, Some(canonical_self)))
}
}
@ -118,18 +127,16 @@ where
{
type Output = Q::QueryResponse;
fn fully_perform(
self,
infcx: &InferCtxt<'_, 'tcx>,
) -> Fallible<(Self::Output, Option<Rc<QueryRegionConstraints<'tcx>>>)> {
fn fully_perform(self, infcx: &InferCtxt<'_, 'tcx>) -> Fallible<TypeOpOutput<'tcx, Self>> {
let mut region_constraints = QueryRegionConstraints::default();
let r = Q::fully_perform_into(self, infcx, &mut region_constraints)?;
let (output, canonicalized_query) =
Q::fully_perform_into(self, infcx, &mut region_constraints)?;
// Promote the final query-region-constraints into a
// (optional) ref-counted vector:
let opt_qrc =
let region_constraints =
if region_constraints.is_empty() { None } else { Some(Rc::new(region_constraints)) };
Ok((r, opt_qrc))
Ok(TypeOpOutput { output, constraints: region_constraints, canonicalized_query })
}
}