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;
/// 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
/// 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
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
// 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)))
}
}
{
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 })
}
}