]> git.lizzy.rs Git - rust.git/blobdiff - compiler/rustc_trait_selection/src/solve/project_goals.rs
Test drop_tracking_mir before querying generator.
[rust.git] / compiler / rustc_trait_selection / src / solve / project_goals.rs
index e5072d8e2d15216adfb84e40a508470ddaaaef8d..1961344e8385f18e9aa938369dae9c4c4cdfdd2a 100644 (file)
@@ -16,7 +16,7 @@
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_middle::ty::{ProjectionPredicate, TypeSuperVisitable, TypeVisitor};
 use rustc_middle::ty::{ToPredicate, TypeVisitable};
-use rustc_span::DUMMY_SP;
+use rustc_span::{sym, DUMMY_SP};
 use std::iter;
 use std::ops::ControlFlow;
 
@@ -28,8 +28,8 @@ pub(super) fn compute_projection_goal(
         // To only compute normalization once for each projection we only
         // normalize if the expected term is an unconstrained inference variable.
         //
-        // E.g. for `<T as Trait>::Assoc = u32` we recursively compute the goal
-        // `exists<U> <T as Trait>::Assoc = U` and then take the resulting type for
+        // E.g. for `<T as Trait>::Assoc == u32` we recursively compute the goal
+        // `exists<U> <T as Trait>::Assoc == U` and then take the resulting type for
         // `U` and equate it with `u32`. This means that we don't need a separate
         // projection cache in the solver.
         if self.term_is_fully_unconstrained(goal) {
@@ -93,24 +93,24 @@ impl<'tcx> TypeVisitor<'tcx> for ContainsTerm<'tcx> {
             fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
                 if t.needs_infer() {
                     if ty::Term::from(t) == self.term {
-                        ControlFlow::BREAK
+                        ControlFlow::Break(())
                     } else {
                         t.super_visit_with(self)
                     }
                 } else {
-                    ControlFlow::CONTINUE
+                    ControlFlow::Continue(())
                 }
             }
 
             fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
                 if c.needs_infer() {
                     if ty::Term::from(c) == self.term {
-                        ControlFlow::BREAK
+                        ControlFlow::Break(())
                     } else {
                         c.super_visit_with(self)
                     }
                 } else {
-                    ControlFlow::CONTINUE
+                    ControlFlow::Continue(())
                 }
             }
         }
@@ -296,7 +296,9 @@ fn consider_assumption(
         goal: Goal<'tcx, Self>,
         assumption: ty::Predicate<'tcx>,
     ) -> QueryResult<'tcx> {
-        if let Some(poly_projection_pred) = assumption.to_opt_poly_projection_pred() {
+        if let Some(poly_projection_pred) = assumption.to_opt_poly_projection_pred()
+            && poly_projection_pred.projection_def_id() == goal.predicate.def_id()
+        {
             ecx.infcx.probe(|_| {
                 let assumption_projection_pred =
                     ecx.infcx.instantiate_bound_vars_with_infer(poly_projection_pred);
@@ -414,6 +416,7 @@ fn consider_builtin_pointee_candidate(
                 | ty::Infer(ty::IntVar(..) | ty::FloatVar(..))
                 | ty::Generator(..)
                 | ty::GeneratorWitness(..)
+                | ty::GeneratorWitnessMIR(..)
                 | ty::Never
                 | ty::Foreign(..) => tcx.types.unit,
 
@@ -427,7 +430,7 @@ fn consider_builtin_pointee_candidate(
                         .subst(tcx, &[ty::GenericArg::from(goal.predicate.self_ty())])
                 }
 
-                ty::Infer(ty::TyVar(..)) | ty::Alias(_, _) | ty::Param(_) | ty::Placeholder(..) => {
+                ty::Alias(_, _) | ty::Param(_) | ty::Placeholder(..) => {
                     // FIXME(ptr_metadata): It would also be possible to return a `Ok(Ambig)` with no constraints.
                     let sized_predicate = ty::Binder::dummy(tcx.at(DUMMY_SP).mk_trait_ref(
                         LangItem::Sized,
@@ -470,7 +473,9 @@ fn consider_builtin_pointee_candidate(
                     }
                 },
 
-                ty::Infer(ty::FreshTy(..) | ty::FreshIntTy(..) | ty::FreshFloatTy(..))
+                ty::Infer(
+                    ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_),
+                )
                 | ty::Bound(..) => bug!(
                     "unexpected self ty `{:?}` when normalizing `<T as Pointee>::Metadata`",
                     goal.predicate.self_ty()
@@ -482,6 +487,73 @@ fn consider_builtin_pointee_candidate(
             ecx.evaluate_all_and_make_canonical_response(nested_goals)
         })
     }
+
+    fn consider_builtin_future_candidate(
+        ecx: &mut EvalCtxt<'_, 'tcx>,
+        goal: Goal<'tcx, Self>,
+    ) -> QueryResult<'tcx> {
+        let self_ty = goal.predicate.self_ty();
+        let ty::Generator(def_id, substs, _) = *self_ty.kind() else {
+            return Err(NoSolution);
+        };
+
+        // Generators are not futures unless they come from `async` desugaring
+        let tcx = ecx.tcx();
+        if !tcx.generator_is_async(def_id) {
+            return Err(NoSolution);
+        }
+
+        let term = substs.as_generator().return_ty().into();
+
+        Self::consider_assumption(
+            ecx,
+            goal,
+            ty::Binder::dummy(ty::ProjectionPredicate {
+                projection_ty: ecx.tcx().mk_alias_ty(goal.predicate.def_id(), [self_ty]),
+                term,
+            })
+            .to_predicate(tcx),
+        )
+    }
+
+    fn consider_builtin_generator_candidate(
+        ecx: &mut EvalCtxt<'_, 'tcx>,
+        goal: Goal<'tcx, Self>,
+    ) -> QueryResult<'tcx> {
+        let self_ty = goal.predicate.self_ty();
+        let ty::Generator(def_id, substs, _) = *self_ty.kind() else {
+            return Err(NoSolution);
+        };
+
+        // `async`-desugared generators do not implement the generator trait
+        let tcx = ecx.tcx();
+        if tcx.generator_is_async(def_id) {
+            return Err(NoSolution);
+        }
+
+        let generator = substs.as_generator();
+
+        let name = tcx.associated_item(goal.predicate.def_id()).name;
+        let term = if name == sym::Return {
+            generator.return_ty().into()
+        } else if name == sym::Yield {
+            generator.yield_ty().into()
+        } else {
+            bug!("unexpected associated item `<{self_ty} as Generator>::{name}`")
+        };
+
+        Self::consider_assumption(
+            ecx,
+            goal,
+            ty::Binder::dummy(ty::ProjectionPredicate {
+                projection_ty: ecx
+                    .tcx()
+                    .mk_alias_ty(goal.predicate.def_id(), [self_ty, generator.resume_ty()]),
+                term,
+            })
+            .to_predicate(tcx),
+        )
+    }
 }
 
 /// This behavior is also implemented in `rustc_ty_utils` and in the old `project` code.