]> git.lizzy.rs Git - rust.git/blobdiff - src/librustc_trait_selection/traits/fulfill.rs
directly contain `PredicateAtom` in `PredicateKind::ForAll`
[rust.git] / src / librustc_trait_selection / traits / fulfill.rs
index c09eebc22c09d004b2ded2abfa7a02f731aded64..c73ed986317c9a7ea551d0c3782ea1b0963ecfd5 100644 (file)
@@ -3,10 +3,11 @@
 use rustc_data_structures::obligation_forest::{DoCompleted, Error, ForestObligation};
 use rustc_data_structures::obligation_forest::{ObligationForest, ObligationProcessor};
 use rustc_errors::ErrorReported;
-use rustc_infer::traits::{TraitEngine, TraitEngineExt as _};
+use rustc_infer::traits::{PolyTraitObligation, TraitEngine, TraitEngineExt as _};
 use rustc_middle::mir::interpret::ErrorHandled;
 use rustc_middle::ty::error::ExpectedFound;
-use rustc_middle::ty::{self, Binder, Const, ToPredicate, Ty, TypeFoldable};
+use rustc_middle::ty::ToPredicate;
+use rustc_middle::ty::{self, Binder, Const, Ty, TypeFoldable};
 use std::marker::PhantomData;
 
 use super::project;
@@ -20,6 +21,7 @@
 use super::{ObligationCause, PredicateObligation};
 
 use crate::traits::error_reporting::InferCtxtExt as _;
+use crate::traits::project::PolyProjectionObligation;
 use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
 
 impl<'tcx> ForestObligation for PendingPredicateObligation<'tcx> {
@@ -317,179 +319,159 @@ fn process_obligation(
 
         let infcx = self.selcx.infcx();
 
-        match obligation.predicate.kint(infcx.tcx) {
-            ty::PredicateKint::ForAll(binder) => {
-                let (pred, _) = infcx.replace_bound_vars_with_placeholders(binder);
-                ProcessResult::Changed(mk_pending(vec![
-                    obligation.with(pred.to_predicate(infcx.tcx)),
-                ]))
-            }
-            ty::PredicateKint::Trait(ref data, _) => {
-                let trait_obligation = obligation.with(Binder::dummy(*data));
-
-                if obligation.predicate.is_global() {
-                    // no type variables present, can use evaluation for better caching.
-                    // FIXME: consider caching errors too.
-                    if infcx.predicate_must_hold_considering_regions(&obligation) {
-                        debug!(
-                            "selecting trait `{:?}` at depth {} evaluated to holds",
-                            data, obligation.recursion_depth
-                        );
-                        return ProcessResult::Changed(vec![]);
+        match obligation.predicate.kind() {
+            ty::PredicateKind::ForAll(binder) => match binder.skip_binder().kind() {
+                ty::PredicateKind::ForAll(_) => bug!("unexpected forall"),
+                // Evaluation will discard candidates using the leak check.
+                // This means we need to pass it the bound version of our
+                // predicate.
+                &ty::PredicateKind::Atom(atom) => match atom {
+                    ty::PredicateAtom::Trait(trait_ref, _constness) => {
+                        let trait_obligation = obligation.with(Binder::bind(trait_ref));
+
+                        self.process_trait_obligation(
+                            obligation,
+                            trait_obligation,
+                            &mut pending_obligation.stalled_on,
+                        )
                     }
-                }
+                    ty::PredicateAtom::Projection(projection) => {
+                        let project_obligation = obligation.with(Binder::bind(projection));
 
-                match self.selcx.select(&trait_obligation) {
-                    Ok(Some(impl_source)) => {
-                        debug!(
-                            "selecting trait `{:?}` at depth {} yielded Ok(Some)",
-                            data, obligation.recursion_depth
-                        );
-                        ProcessResult::Changed(mk_pending(impl_source.nested_obligations()))
+                        self.process_projection_obligation(
+                            project_obligation,
+                            &mut pending_obligation.stalled_on,
+                        )
                     }
-                    Ok(None) => {
-                        debug!(
-                            "selecting trait `{:?}` at depth {} yielded Ok(None)",
-                            data, obligation.recursion_depth
-                        );
-
-                        // This is a bit subtle: for the most part, the
-                        // only reason we can fail to make progress on
-                        // trait selection is because we don't have enough
-                        // information about the types in the trait.
-                        pending_obligation.stalled_on =
-                            trait_ref_infer_vars(self.selcx, data.trait_ref);
-
-                        debug!(
-                            "process_predicate: pending obligation {:?} now stalled on {:?}",
-                            infcx.resolve_vars_if_possible(obligation),
-                            pending_obligation.stalled_on
-                        );
-
-                        ProcessResult::Unchanged
+                    ty::PredicateAtom::RegionOutlives(_)
+                    | ty::PredicateAtom::TypeOutlives(_)
+                    | ty::PredicateAtom::WellFormed(_)
+                    | ty::PredicateAtom::ObjectSafe(_)
+                    | ty::PredicateAtom::ClosureKind(..)
+                    | ty::PredicateAtom::Subtype(_)
+                    | ty::PredicateAtom::ConstEvaluatable(..)
+                    | ty::PredicateAtom::ConstEquate(..) => {
+                        let (pred, _) = infcx.replace_bound_vars_with_placeholders(binder);
+                        ProcessResult::Changed(mk_pending(vec![obligation.with(pred)]))
                     }
-                    Err(selection_err) => {
-                        info!(
-                            "selecting trait `{:?}` at depth {} yielded Err",
-                            data, obligation.recursion_depth
-                        );
+                },
+            },
+            &ty::PredicateKind::Atom(atom) => match atom {
+                ty::PredicateAtom::Trait(ref data, _) => {
+                    let trait_obligation = obligation.with(Binder::dummy(*data));
+
+                    self.process_trait_obligation(
+                        obligation,
+                        trait_obligation,
+                        &mut pending_obligation.stalled_on,
+                    )
+                }
 
-                        ProcessResult::Error(CodeSelectionError(selection_err))
+                ty::PredicateAtom::RegionOutlives(data) => {
+                    match infcx.region_outlives_predicate(&obligation.cause, Binder::dummy(data)) {
+                        Ok(()) => ProcessResult::Changed(vec![]),
+                        Err(_) => ProcessResult::Error(CodeSelectionError(Unimplemented)),
                     }
                 }
-            }
 
-            &ty::PredicateKint::RegionOutlives(data) => {
-                match infcx.region_outlives_predicate(&obligation.cause, Binder::dummy(data)) {
-                    Ok(()) => ProcessResult::Changed(vec![]),
-                    Err(_) => ProcessResult::Error(CodeSelectionError(Unimplemented)),
+                ty::PredicateAtom::TypeOutlives(ty::OutlivesPredicate(t_a, r_b)) => {
+                    if self.register_region_obligations {
+                        self.selcx.infcx().register_region_obligation_with_cause(
+                            t_a,
+                            r_b,
+                            &obligation.cause,
+                        );
+                    }
+                    ProcessResult::Changed(vec![])
                 }
-            }
 
-            ty::PredicateKint::TypeOutlives(ty::OutlivesPredicate(t_a, r_b)) => {
-                if self.register_region_obligations {
-                    self.selcx.infcx().register_region_obligation_with_cause(
-                        t_a,
-                        r_b,
-                        &obligation.cause,
-                    );
-                }
-                ProcessResult::Changed(vec![])
-            }
+                ty::PredicateAtom::Projection(ref data) => {
+                    let project_obligation = obligation.with(Binder::dummy(*data));
 
-            ty::PredicateKint::Projection(ref data) => {
-                let project_obligation = obligation.with(Binder::dummy(*data));
-                match project::poly_project_and_unify_type(self.selcx, &project_obligation) {
-                    Ok(None) => {
-                        pending_obligation.stalled_on = trait_ref_infer_vars(
-                            self.selcx,
-                            data.projection_ty.trait_ref(infcx.tcx),
-                        );
-                        ProcessResult::Unchanged
-                    }
-                    Ok(Some(os)) => ProcessResult::Changed(mk_pending(os)),
-                    Err(e) => ProcessResult::Error(CodeProjectionError(e)),
+                    self.process_projection_obligation(
+                        project_obligation,
+                        &mut pending_obligation.stalled_on,
+                    )
                 }
-            }
 
-            &ty::PredicateKint::ObjectSafe(trait_def_id) => {
-                if !self.selcx.tcx().is_object_safe(trait_def_id) {
-                    ProcessResult::Error(CodeSelectionError(Unimplemented))
-                } else {
-                    ProcessResult::Changed(vec![])
+                ty::PredicateAtom::ObjectSafe(trait_def_id) => {
+                    if !self.selcx.tcx().is_object_safe(trait_def_id) {
+                        ProcessResult::Error(CodeSelectionError(Unimplemented))
+                    } else {
+                        ProcessResult::Changed(vec![])
+                    }
                 }
-            }
 
-            &ty::PredicateKint::ClosureKind(_, closure_substs, kind) => {
-                match self.selcx.infcx().closure_kind(closure_substs) {
-                    Some(closure_kind) => {
-                        if closure_kind.extends(kind) {
-                            ProcessResult::Changed(vec![])
-                        } else {
-                            ProcessResult::Error(CodeSelectionError(Unimplemented))
+                ty::PredicateAtom::ClosureKind(_, closure_substs, kind) => {
+                    match self.selcx.infcx().closure_kind(closure_substs) {
+                        Some(closure_kind) => {
+                            if closure_kind.extends(kind) {
+                                ProcessResult::Changed(vec![])
+                            } else {
+                                ProcessResult::Error(CodeSelectionError(Unimplemented))
+                            }
                         }
+                        None => ProcessResult::Unchanged,
                     }
-                    None => ProcessResult::Unchanged,
                 }
-            }
 
-            &ty::PredicateKint::WellFormed(arg) => {
-                match wf::obligations(
-                    self.selcx.infcx(),
-                    obligation.param_env,
-                    obligation.cause.body_id,
-                    arg,
-                    obligation.cause.span,
-                ) {
-                    None => {
-                        pending_obligation.stalled_on =
-                            vec![TyOrConstInferVar::maybe_from_generic_arg(arg).unwrap()];
-                        ProcessResult::Unchanged
+                ty::PredicateAtom::WellFormed(arg) => {
+                    match wf::obligations(
+                        self.selcx.infcx(),
+                        obligation.param_env,
+                        obligation.cause.body_id,
+                        arg,
+                        obligation.cause.span,
+                    ) {
+                        None => {
+                            pending_obligation.stalled_on =
+                                vec![TyOrConstInferVar::maybe_from_generic_arg(arg).unwrap()];
+                            ProcessResult::Unchanged
+                        }
+                        Some(os) => ProcessResult::Changed(mk_pending(os)),
                     }
-                    Some(os) => ProcessResult::Changed(mk_pending(os)),
                 }
-            }
 
-            &ty::PredicateKint::Subtype(subtype) => {
-                match self.selcx.infcx().subtype_predicate(
-                    &obligation.cause,
-                    obligation.param_env,
-                    Binder::dummy(subtype),
-                ) {
-                    None => {
-                        // None means that both are unresolved.
-                        pending_obligation.stalled_on = vec![
-                            TyOrConstInferVar::maybe_from_ty(subtype.a).unwrap(),
-                            TyOrConstInferVar::maybe_from_ty(subtype.b).unwrap(),
-                        ];
-                        ProcessResult::Unchanged
-                    }
-                    Some(Ok(ok)) => ProcessResult::Changed(mk_pending(ok.obligations)),
-                    Some(Err(err)) => {
-                        let expected_found =
-                            ExpectedFound::new(subtype.a_is_expected, subtype.a, subtype.b);
-                        ProcessResult::Error(FulfillmentErrorCode::CodeSubtypeError(
-                            expected_found,
-                            err,
-                        ))
+                ty::PredicateAtom::Subtype(subtype) => {
+                    match self.selcx.infcx().subtype_predicate(
+                        &obligation.cause,
+                        obligation.param_env,
+                        Binder::dummy(subtype),
+                    ) {
+                        None => {
+                            // None means that both are unresolved.
+                            pending_obligation.stalled_on = vec![
+                                TyOrConstInferVar::maybe_from_ty(subtype.a).unwrap(),
+                                TyOrConstInferVar::maybe_from_ty(subtype.b).unwrap(),
+                            ];
+                            ProcessResult::Unchanged
+                        }
+                        Some(Ok(ok)) => ProcessResult::Changed(mk_pending(ok.obligations)),
+                        Some(Err(err)) => {
+                            let expected_found =
+                                ExpectedFound::new(subtype.a_is_expected, subtype.a, subtype.b);
+                            ProcessResult::Error(FulfillmentErrorCode::CodeSubtypeError(
+                                expected_found,
+                                err,
+                            ))
+                        }
                     }
                 }
-            }
 
-            &ty::PredicateKint::ConstEvaluatable(def_id, substs) => {
-                match self.selcx.infcx().const_eval_resolve(
-                    obligation.param_env,
-                    def_id,
-                    substs,
-                    None,
-                    Some(obligation.cause.span),
-                ) {
-                    Ok(_) => ProcessResult::Changed(vec![]),
-                    Err(err) => ProcessResult::Error(CodeSelectionError(ConstEvalFailure(err))),
+                ty::PredicateAtom::ConstEvaluatable(def_id, substs) => {
+                    match self.selcx.infcx().const_eval_resolve(
+                        obligation.param_env,
+                        def_id,
+                        substs,
+                        None,
+                        Some(obligation.cause.span),
+                    ) {
+                        Ok(_) => ProcessResult::Changed(vec![]),
+                        Err(err) => ProcessResult::Error(CodeSelectionError(ConstEvalFailure(err))),
+                    }
                 }
-            }
 
-            ty::PredicateKint::ConstEquate(c1, c2) => {
+            ty::PredicateAtom::ConstEquate(c1, c2) => {
                 debug!("equating consts: c1={:?} c2={:?}", c1, c2);
 
                 let stalled_on = &mut pending_obligation.stalled_on;
@@ -513,43 +495,46 @@ fn process_obligation(
                                 );
                                 Err(ErrorHandled::TooGeneric)
                             }
-                            Err(err) => Err(err),
+                        } else {
+                            Ok(c)
                         }
-                    } else {
-                        Ok(c)
-                    }
-                };
-
-                match (evaluate(c1), evaluate(c2)) {
-                    (Ok(c1), Ok(c2)) => {
-                        match self
-                            .selcx
-                            .infcx()
-                            .at(&obligation.cause, obligation.param_env)
-                            .eq(c1, c2)
-                        {
-                            Ok(_) => ProcessResult::Changed(vec![]),
-                            Err(err) => {
-                                ProcessResult::Error(FulfillmentErrorCode::CodeConstEquateError(
-                                    ExpectedFound::new(true, c1, c2),
-                                    err,
-                                ))
+                    };
+
+                    match (evaluate(c1), evaluate(c2)) {
+                        (Ok(c1), Ok(c2)) => {
+                            match self
+                                .selcx
+                                .infcx()
+                                .at(&obligation.cause, obligation.param_env)
+                                .eq(c1, c2)
+                            {
+                                Ok(_) => ProcessResult::Changed(vec![]),
+                                Err(err) => ProcessResult::Error(
+                                    FulfillmentErrorCode::CodeConstEquateError(
+                                        ExpectedFound::new(true, c1, c2),
+                                        err,
+                                    ),
+                                ),
                             }
                         }
-                    }
-                    (Err(ErrorHandled::Reported(ErrorReported)), _)
-                    | (_, Err(ErrorHandled::Reported(ErrorReported))) => ProcessResult::Error(
-                        CodeSelectionError(ConstEvalFailure(ErrorHandled::Reported(ErrorReported))),
-                    ),
-                    (Err(ErrorHandled::Linted), _) | (_, Err(ErrorHandled::Linted)) => span_bug!(
-                        obligation.cause.span(self.selcx.tcx()),
-                        "ConstEquate: const_eval_resolve returned an unexpected error"
-                    ),
-                    (Err(ErrorHandled::TooGeneric), _) | (_, Err(ErrorHandled::TooGeneric)) => {
-                        ProcessResult::Unchanged
+                        (Err(ErrorHandled::Reported(ErrorReported)), _)
+                        | (_, Err(ErrorHandled::Reported(ErrorReported))) => {
+                            ProcessResult::Error(CodeSelectionError(ConstEvalFailure(
+                                ErrorHandled::Reported(ErrorReported),
+                            )))
+                        }
+                        (Err(ErrorHandled::Linted), _) | (_, Err(ErrorHandled::Linted)) => {
+                            span_bug!(
+                                obligation.cause.span(self.selcx.tcx()),
+                                "ConstEquate: const_eval_resolve returned an unexpected error"
+                            )
+                        }
+                        (Err(ErrorHandled::TooGeneric), _) | (_, Err(ErrorHandled::TooGeneric)) => {
+                            ProcessResult::Unchanged
+                        }
                     }
                 }
-            }
+            },
         }
     }
 
@@ -569,14 +554,96 @@ fn process_backedge<'c, I>(
     }
 }
 
+impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> {
+    fn process_trait_obligation(
+        &mut self,
+        obligation: &PredicateObligation<'tcx>,
+        trait_obligation: PolyTraitObligation<'tcx>,
+        stalled_on: &mut Vec<TyOrConstInferVar<'tcx>>,
+    ) -> ProcessResult<PendingPredicateObligation<'tcx>, FulfillmentErrorCode<'tcx>> {
+        let infcx = self.selcx.infcx();
+        if obligation.predicate.is_global() {
+            // no type variables present, can use evaluation for better caching.
+            // FIXME: consider caching errors too.
+            if infcx.predicate_must_hold_considering_regions(obligation) {
+                debug!(
+                    "selecting trait `{:?}` at depth {} evaluated to holds",
+                    obligation.predicate, obligation.recursion_depth
+                );
+                return ProcessResult::Changed(vec![]);
+            }
+        }
+
+        match self.selcx.select(&trait_obligation) {
+            Ok(Some(impl_source)) => {
+                debug!(
+                    "selecting trait `{:?}` at depth {} yielded Ok(Some)",
+                    trait_obligation.predicate, obligation.recursion_depth
+                );
+                ProcessResult::Changed(mk_pending(impl_source.nested_obligations()))
+            }
+            Ok(None) => {
+                debug!(
+                    "selecting trait `{:?}` at depth {} yielded Ok(None)",
+                    trait_obligation.predicate, obligation.recursion_depth
+                );
+
+                // This is a bit subtle: for the most part, the
+                // only reason we can fail to make progress on
+                // trait selection is because we don't have enough
+                // information about the types in the trait.
+                *stalled_on = trait_ref_infer_vars(
+                    self.selcx,
+                    trait_obligation.predicate.map_bound(|pred| pred.trait_ref),
+                );
+
+                debug!(
+                    "process_predicate: pending obligation {:?} now stalled on {:?}",
+                    infcx.resolve_vars_if_possible(obligation),
+                    stalled_on
+                );
+
+                ProcessResult::Unchanged
+            }
+            Err(selection_err) => {
+                info!(
+                    "selecting trait `{:?}` at depth {} yielded Err",
+                    trait_obligation.predicate, obligation.recursion_depth
+                );
+
+                ProcessResult::Error(CodeSelectionError(selection_err))
+            }
+        }
+    }
+
+    fn process_projection_obligation(
+        &mut self,
+        project_obligation: PolyProjectionObligation<'tcx>,
+        stalled_on: &mut Vec<TyOrConstInferVar<'tcx>>,
+    ) -> ProcessResult<PendingPredicateObligation<'tcx>, FulfillmentErrorCode<'tcx>> {
+        match project::poly_project_and_unify_type(self.selcx, &project_obligation) {
+            Ok(None) => {
+                *stalled_on = trait_ref_infer_vars(
+                    self.selcx,
+                    project_obligation.predicate.to_poly_trait_ref(self.selcx.tcx()),
+                );
+                ProcessResult::Unchanged
+            }
+            Ok(Some(os)) => ProcessResult::Changed(mk_pending(os)),
+            Err(e) => ProcessResult::Error(CodeProjectionError(e)),
+        }
+    }
+}
+
 /// Returns the set of inference variables contained in a trait ref.
 fn trait_ref_infer_vars<'a, 'tcx>(
     selcx: &mut SelectionContext<'a, 'tcx>,
-    trait_ref: ty::TraitRef<'tcx>,
+    trait_ref: ty::PolyTraitRef<'tcx>,
 ) -> Vec<TyOrConstInferVar<'tcx>> {
     selcx
         .infcx()
         .resolve_vars_if_possible(&trait_ref)
+        .skip_binder()
         .substs
         .iter()
         // FIXME(eddyb) try using `skip_current_subtree` to skip everything that