1919
2020use std::mem;
2121
22+ use rustc_hir::def_id::DefId;
2223use rustc_infer::infer::canonical::{Canonical, CanonicalVarKind, CanonicalVarValues};
2324use rustc_infer::infer::canonical::{OriginalQueryValues, QueryRegionConstraints, QueryResponse};
2425use rustc_infer::infer::{InferCtxt, InferOk, TyCtxtInferExt};
2526use rustc_infer::traits::query::NoSolution;
2627use rustc_infer::traits::Obligation;
2728use rustc_middle::infer::canonical::Certainty as OldCertainty;
2829use rustc_middle::ty::{self, Ty, TyCtxt};
29- use rustc_middle::ty::{RegionOutlivesPredicate, ToPredicate, TypeOutlivesPredicate};
30+ use rustc_middle::ty::{
31+ CoercePredicate, RegionOutlivesPredicate, SubtypePredicate, ToPredicate, TypeOutlivesPredicate,
32+ };
3033use rustc_span::DUMMY_SP;
3134
3235use crate::traits::ObligationCause;
@@ -87,6 +90,8 @@ pub enum Certainty {
8790}
8891
8992impl Certainty {
93+ pub const AMBIGUOUS: Certainty = Certainty::Maybe(MaybeCause::Ambiguity);
94+
9095 /// When proving multiple goals using **AND**, e.g. nested obligations for an impl,
9196 /// use this function to unify the certainty of these goals
9297 pub fn unify_and(self, other: Certainty) -> Certainty {
@@ -243,16 +248,28 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
243248 ty::PredicateKind::Clause(ty::Clause::RegionOutlives(predicate)) => {
244249 self.compute_region_outlives_goal(Goal { param_env, predicate })
245250 }
251+ ty::PredicateKind::Subtype(predicate) => {
252+ self.compute_subtype_goal(Goal { param_env, predicate })
253+ }
254+ ty::PredicateKind::Coerce(predicate) => {
255+ self.compute_coerce_goal(Goal { param_env, predicate })
256+ }
257+ ty::PredicateKind::ClosureKind(def_id, substs, kind) => self
258+ .compute_closure_kind_goal(Goal {
259+ param_env,
260+ predicate: (def_id, substs, kind),
261+ }),
262+ ty::PredicateKind::Ambiguous => self.make_canonical_response(Certainty::AMBIGUOUS),
246263 // FIXME: implement these predicates :)
247264 ty::PredicateKind::WellFormed(_)
248265 | ty::PredicateKind::ObjectSafe(_)
249- | ty::PredicateKind::ClosureKind(_, _, _)
250- | ty::PredicateKind::Subtype(_)
251- | ty::PredicateKind::Coerce(_)
252266 | ty::PredicateKind::ConstEvaluatable(_)
253- | ty::PredicateKind::ConstEquate(_, _)
254- | ty::PredicateKind::TypeWellFormedFromEnv(_)
255- | ty::PredicateKind::Ambiguous => self.make_canonical_response(Certainty::Yes),
267+ | ty::PredicateKind::ConstEquate(_, _) => {
268+ self.make_canonical_response(Certainty::Yes)
269+ }
270+ ty::PredicateKind::TypeWellFormedFromEnv(..) => {
271+ bug!("TypeWellFormedFromEnv is only used for Chalk")
272+ }
256273 }
257274 } else {
258275 let kind = self.infcx.replace_bound_vars_with_placeholders(kind);
@@ -275,6 +292,58 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
275292 ) -> QueryResult<'tcx> {
276293 self.make_canonical_response(Certainty::Yes)
277294 }
295+
296+ fn compute_coerce_goal(
297+ &mut self,
298+ goal: Goal<'tcx, CoercePredicate<'tcx>>,
299+ ) -> QueryResult<'tcx> {
300+ self.compute_subtype_goal(Goal {
301+ param_env: goal.param_env,
302+ predicate: SubtypePredicate {
303+ a_is_expected: false,
304+ a: goal.predicate.a,
305+ b: goal.predicate.b,
306+ },
307+ })
308+ }
309+
310+ fn compute_subtype_goal(
311+ &mut self,
312+ goal: Goal<'tcx, SubtypePredicate<'tcx>>,
313+ ) -> QueryResult<'tcx> {
314+ if goal.predicate.a.is_ty_var() && goal.predicate.b.is_ty_var() {
315+ // FIXME: Do we want to register a subtype relation between these vars?
316+ // That won't actually reflect in the query response, so it seems moot.
317+ self.make_canonical_response(Certainty::AMBIGUOUS)
318+ } else {
319+ self.infcx.probe(|_| {
320+ let InferOk { value: (), obligations } = self
321+ .infcx
322+ .at(&ObligationCause::dummy(), goal.param_env)
323+ .sub(goal.predicate.a, goal.predicate.b)?;
324+ self.evaluate_all_and_make_canonical_response(
325+ obligations.into_iter().map(|pred| pred.into()).collect(),
326+ )
327+ })
328+ }
329+ }
330+
331+ fn compute_closure_kind_goal(
332+ &mut self,
333+ goal: Goal<'tcx, (DefId, ty::SubstsRef<'tcx>, ty::ClosureKind)>,
334+ ) -> QueryResult<'tcx> {
335+ let (_, substs, expected_kind) = goal.predicate;
336+ let found_kind = substs.as_closure().kind_ty().to_opt_closure_kind();
337+
338+ let Some(found_kind) = found_kind else {
339+ return self.make_canonical_response(Certainty::AMBIGUOUS);
340+ };
341+ if found_kind.extends(expected_kind) {
342+ self.make_canonical_response(Certainty::Yes)
343+ } else {
344+ Err(NoSolution)
345+ }
346+ }
278347}
279348
280349impl<'tcx> EvalCtxt<'_, 'tcx> {
0 commit comments