From 82b52056fe99705b4234c5781eada2bd7ae6042e Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 10 Feb 2023 02:10:42 +0000 Subject: [PATCH 1/2] Check that built-in callable types validate their output type is `Sized` (in new solver) --- .../src/solve/assembly.rs | 12 +++++++++ .../src/solve/project_goals.rs | 22 ++++++++++------ .../src/solve/trait_goals.rs | 25 +++++++++++++------ .../builtin-fn-must-return-sized.rs | 17 +++++++++++++ .../builtin-fn-must-return-sized.stderr | 18 +++++++++++++ 5 files changed, 80 insertions(+), 14 deletions(-) create mode 100644 tests/ui/traits/new-solver/builtin-fn-must-return-sized.rs create mode 100644 tests/ui/traits/new-solver/builtin-fn-must-return-sized.stderr diff --git a/compiler/rustc_trait_selection/src/solve/assembly.rs b/compiler/rustc_trait_selection/src/solve/assembly.rs index 126ec60b3d6..a9e0c5509a5 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly.rs @@ -96,10 +96,22 @@ pub(super) trait GoalKind<'tcx>: TypeFoldable<'tcx> + Copy + Eq { impl_def_id: DefId, ) -> QueryResult<'tcx>; + // Consider a predicate we know holds (`assumption`) against a goal we're trying to prove. fn consider_assumption( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, assumption: ty::Predicate<'tcx>, + ) -> QueryResult<'tcx> { + Self::consider_assumption_with_certainty(ecx, goal, assumption, Certainty::Yes) + } + + // Consider a predicate we know holds (`assumption`) against a goal, unifying with + // the `assumption_certainty` if it satisfies the goal. + fn consider_assumption_with_certainty( + ecx: &mut EvalCtxt<'_, 'tcx>, + goal: Goal<'tcx, Self>, + assumption: ty::Predicate<'tcx>, + assumption_certainty: Certainty, ) -> QueryResult<'tcx>; // A type implements an `auto trait` if its components do as well. These components diff --git a/compiler/rustc_trait_selection/src/solve/project_goals.rs b/compiler/rustc_trait_selection/src/solve/project_goals.rs index 883342148f4..adf8a1690c8 100644 --- a/compiler/rustc_trait_selection/src/solve/project_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/project_goals.rs @@ -260,10 +260,11 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { }) } - fn consider_assumption( + fn consider_assumption_with_certainty( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, assumption: ty::Predicate<'tcx>, + assumption_certainty: Certainty, ) -> QueryResult<'tcx> { if let Some(poly_projection_pred) = assumption.to_opt_poly_projection_pred() && poly_projection_pred.projection_def_id() == goal.predicate.def_id() @@ -280,7 +281,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { ecx.eq_term_and_make_canonical_response( goal, - subst_certainty, + subst_certainty.unify_and(assumption_certainty), assumption_projection_pred.term, ) }) @@ -329,22 +330,29 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { goal: Goal<'tcx, Self>, goal_kind: ty::ClosureKind, ) -> QueryResult<'tcx> { + let tcx = ecx.tcx(); if let Some(tupled_inputs_and_output) = structural_traits::extract_tupled_inputs_and_output_from_callable( - ecx.tcx(), + tcx, goal.predicate.self_ty(), goal_kind, )? { + // A built-in `Fn` trait needs to check that its output is `Sized` + // (FIXME: technically we only need to check this if the type is a fn ptr...) + let output_is_sized_pred = tupled_inputs_and_output + .map_bound(|(_, output)| tcx.at(DUMMY_SP).mk_trait_ref(LangItem::Sized, [output])); + let (_, output_is_sized_certainty) = + ecx.evaluate_goal(goal.with(tcx, output_is_sized_pred))?; + let pred = tupled_inputs_and_output .map_bound(|(inputs, output)| ty::ProjectionPredicate { - projection_ty: ecx - .tcx() + projection_ty: tcx .mk_alias_ty(goal.predicate.def_id(), [goal.predicate.self_ty(), inputs]), term: output.into(), }) - .to_predicate(ecx.tcx()); - Self::consider_assumption(ecx, goal, pred) + .to_predicate(tcx); + Self::consider_assumption_with_certainty(ecx, goal, pred, output_is_sized_certainty) } else { ecx.make_canonical_response(Certainty::AMBIGUOUS) } diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs index d12e5f797fb..dd47a5ae150 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs @@ -6,6 +6,7 @@ use super::assembly; use super::infcx_ext::InferCtxtExt; use super::{CanonicalResponse, Certainty, EvalCtxt, Goal, QueryResult}; use rustc_hir::def_id::DefId; +use rustc_hir::LangItem; use rustc_infer::infer::InferCtxt; use rustc_infer::traits::query::NoSolution; use rustc_infer::traits::util::supertraits; @@ -61,10 +62,11 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { }) } - fn consider_assumption( + fn consider_assumption_with_certainty( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, assumption: ty::Predicate<'tcx>, + assumption_certainty: Certainty, ) -> QueryResult<'tcx> { if let Some(poly_trait_pred) = assumption.to_opt_poly_trait_pred() && poly_trait_pred.def_id() == goal.predicate.def_id() @@ -78,7 +80,9 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { goal.predicate.trait_ref, assumption_trait_pred.trait_ref, )?; - ecx.evaluate_all_and_make_canonical_response(nested_goals) + ecx.evaluate_all(nested_goals).and_then(|certainty| { + ecx.make_canonical_response(certainty.unify_and(assumption_certainty)) + }) }) } else { Err(NoSolution) @@ -173,20 +177,27 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { goal: Goal<'tcx, Self>, goal_kind: ty::ClosureKind, ) -> QueryResult<'tcx> { + let tcx = ecx.tcx(); if let Some(tupled_inputs_and_output) = structural_traits::extract_tupled_inputs_and_output_from_callable( - ecx.tcx(), + tcx, goal.predicate.self_ty(), goal_kind, )? { + // A built-in `Fn` trait needs to check that its output is `Sized` + // (FIXME: technically we only need to check this if the type is a fn ptr...) + let output_is_sized_pred = tupled_inputs_and_output + .map_bound(|(_, output)| tcx.at(DUMMY_SP).mk_trait_ref(LangItem::Sized, [output])); + let (_, output_is_sized_certainty) = + ecx.evaluate_goal(goal.with(tcx, output_is_sized_pred))?; + let pred = tupled_inputs_and_output .map_bound(|(inputs, _)| { - ecx.tcx() - .mk_trait_ref(goal.predicate.def_id(), [goal.predicate.self_ty(), inputs]) + tcx.mk_trait_ref(goal.predicate.def_id(), [goal.predicate.self_ty(), inputs]) }) - .to_predicate(ecx.tcx()); - Self::consider_assumption(ecx, goal, pred) + .to_predicate(tcx); + Self::consider_assumption_with_certainty(ecx, goal, pred, output_is_sized_certainty) } else { ecx.make_canonical_response(Certainty::AMBIGUOUS) } diff --git a/tests/ui/traits/new-solver/builtin-fn-must-return-sized.rs b/tests/ui/traits/new-solver/builtin-fn-must-return-sized.rs new file mode 100644 index 00000000000..ba473653ecf --- /dev/null +++ b/tests/ui/traits/new-solver/builtin-fn-must-return-sized.rs @@ -0,0 +1,17 @@ +// compile-flags: -Ztrait-solver=next + +#![feature(fn_traits)] +#![feature(unboxed_closures)] +#![feature(tuple_trait)] + +use std::ops::Fn; +use std::marker::Tuple; + +fn foo, T: Tuple>(f: Option, t: T) { + let y = (f.unwrap()).call(t); +} + +fn main() { + foo:: str, _>(None, ()); + //~^ expected a `Fn<_>` closure, found `fn() -> str` +} diff --git a/tests/ui/traits/new-solver/builtin-fn-must-return-sized.stderr b/tests/ui/traits/new-solver/builtin-fn-must-return-sized.stderr new file mode 100644 index 00000000000..f7551739b13 --- /dev/null +++ b/tests/ui/traits/new-solver/builtin-fn-must-return-sized.stderr @@ -0,0 +1,18 @@ +error[E0277]: expected a `Fn<_>` closure, found `fn() -> str` + --> $DIR/builtin-fn-must-return-sized.rs:15:27 + | +LL | foo:: str, _>(None, ()); + | --------------------- ^^^^ expected an `Fn<_>` closure, found `fn() -> str` + | | + | required by a bound introduced by this call + | + = help: the trait `Fn<_>` is not implemented for `fn() -> str` +note: required by a bound in `foo` + --> $DIR/builtin-fn-must-return-sized.rs:10:11 + | +LL | fn foo, T: Tuple>(f: Option, t: T) { + | ^^^^^ required by this bound in `foo` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. From 6402c98621ab620a16adac072abc10779cf60573 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 16 Feb 2023 03:04:08 +0000 Subject: [PATCH 2/2] Add consider_implied_clause --- .../src/solve/assembly.rs | 34 ++---- .../src/solve/project_goals.rs | 115 +++++++++--------- .../src/solve/trait_goals.rs | 50 ++++---- 3 files changed, 97 insertions(+), 102 deletions(-) diff --git a/compiler/rustc_trait_selection/src/solve/assembly.rs b/compiler/rustc_trait_selection/src/solve/assembly.rs index a9e0c5509a5..841169ac78d 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly.rs @@ -90,30 +90,22 @@ pub(super) trait GoalKind<'tcx>: TypeFoldable<'tcx> + Copy + Eq { fn trait_def_id(self, tcx: TyCtxt<'tcx>) -> DefId; + // Consider a clause, which consists of a "assumption" and some "requirements", + // to satisfy a goal. If the requirements hold, then attempt to satisfy our + // goal by equating it with the assumption. + fn consider_implied_clause( + ecx: &mut EvalCtxt<'_, 'tcx>, + goal: Goal<'tcx, Self>, + assumption: ty::Predicate<'tcx>, + requirements: impl IntoIterator>>, + ) -> QueryResult<'tcx>; + fn consider_impl_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, impl_def_id: DefId, ) -> QueryResult<'tcx>; - // Consider a predicate we know holds (`assumption`) against a goal we're trying to prove. - fn consider_assumption( - ecx: &mut EvalCtxt<'_, 'tcx>, - goal: Goal<'tcx, Self>, - assumption: ty::Predicate<'tcx>, - ) -> QueryResult<'tcx> { - Self::consider_assumption_with_certainty(ecx, goal, assumption, Certainty::Yes) - } - - // Consider a predicate we know holds (`assumption`) against a goal, unifying with - // the `assumption_certainty` if it satisfies the goal. - fn consider_assumption_with_certainty( - ecx: &mut EvalCtxt<'_, 'tcx>, - goal: Goal<'tcx, Self>, - assumption: ty::Predicate<'tcx>, - assumption_certainty: Certainty, - ) -> QueryResult<'tcx>; - // A type implements an `auto trait` if its components do as well. These components // are given by built-in rules from [`instantiate_constituent_tys_for_auto_trait`]. fn consider_auto_trait_candidate( @@ -367,7 +359,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { candidates: &mut Vec>, ) { for (i, assumption) in goal.param_env.caller_bounds().iter().enumerate() { - match G::consider_assumption(self, goal, assumption) { + match G::consider_implied_clause(self, goal, assumption, []) { Ok(result) => { candidates.push(Candidate { source: CandidateSource::ParamEnv(i), result }) } @@ -414,7 +406,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { for assumption in self.tcx().item_bounds(alias_ty.def_id).subst(self.tcx(), alias_ty.substs) { - match G::consider_assumption(self, goal, assumption) { + match G::consider_implied_clause(self, goal, assumption, []) { Ok(result) => { candidates.push(Candidate { source: CandidateSource::AliasBound, result }) } @@ -464,7 +456,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { for assumption in elaborate_predicates(tcx, bounds.iter().map(|bound| bound.with_self_ty(tcx, self_ty))) { - match G::consider_assumption(self, goal, assumption.predicate) { + match G::consider_implied_clause(self, goal, assumption.predicate, []) { Ok(result) => { candidates.push(Candidate { source: CandidateSource::BuiltinImpl, result }) } diff --git a/compiler/rustc_trait_selection/src/solve/project_goals.rs b/compiler/rustc_trait_selection/src/solve/project_goals.rs index adf8a1690c8..48153b465b7 100644 --- a/compiler/rustc_trait_selection/src/solve/project_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/project_goals.rs @@ -168,6 +168,37 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { self.trait_def_id(tcx) } + fn consider_implied_clause( + ecx: &mut EvalCtxt<'_, 'tcx>, + goal: Goal<'tcx, Self>, + assumption: ty::Predicate<'tcx>, + requirements: impl IntoIterator>>, + ) -> QueryResult<'tcx> { + 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_binder_with_infer(poly_projection_pred); + let mut nested_goals = ecx.infcx.eq( + goal.param_env, + goal.predicate.projection_ty, + assumption_projection_pred.projection_ty, + )?; + nested_goals.extend(requirements); + let subst_certainty = ecx.evaluate_all(nested_goals)?; + + ecx.eq_term_and_make_canonical_response( + goal, + subst_certainty, + assumption_projection_pred.term, + ) + }) + } else { + Err(NoSolution) + } + } + fn consider_impl_candidate( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, ProjectionPredicate<'tcx>>, @@ -260,36 +291,6 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { }) } - fn consider_assumption_with_certainty( - ecx: &mut EvalCtxt<'_, 'tcx>, - goal: Goal<'tcx, Self>, - assumption: ty::Predicate<'tcx>, - assumption_certainty: Certainty, - ) -> QueryResult<'tcx> { - 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_binder_with_infer(poly_projection_pred); - let nested_goals = ecx.infcx.eq( - goal.param_env, - goal.predicate.projection_ty, - assumption_projection_pred.projection_ty, - )?; - let subst_certainty = ecx.evaluate_all(nested_goals)?; - - ecx.eq_term_and_make_canonical_response( - goal, - subst_certainty.unify_and(assumption_certainty), - assumption_projection_pred.term, - ) - }) - } else { - Err(NoSolution) - } - } - fn consider_auto_trait_candidate( _ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, @@ -331,31 +332,27 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { goal_kind: ty::ClosureKind, ) -> QueryResult<'tcx> { let tcx = ecx.tcx(); - if let Some(tupled_inputs_and_output) = - structural_traits::extract_tupled_inputs_and_output_from_callable( - tcx, - goal.predicate.self_ty(), - goal_kind, - )? - { - // A built-in `Fn` trait needs to check that its output is `Sized` - // (FIXME: technically we only need to check this if the type is a fn ptr...) - let output_is_sized_pred = tupled_inputs_and_output - .map_bound(|(_, output)| tcx.at(DUMMY_SP).mk_trait_ref(LangItem::Sized, [output])); - let (_, output_is_sized_certainty) = - ecx.evaluate_goal(goal.with(tcx, output_is_sized_pred))?; + let Some(tupled_inputs_and_output) = + structural_traits::extract_tupled_inputs_and_output_from_callable( + tcx, + goal.predicate.self_ty(), + goal_kind, + )? else { + return ecx.make_canonical_response(Certainty::AMBIGUOUS); + }; + let output_is_sized_pred = tupled_inputs_and_output + .map_bound(|(_, output)| tcx.at(DUMMY_SP).mk_trait_ref(LangItem::Sized, [output])); - let pred = tupled_inputs_and_output - .map_bound(|(inputs, output)| ty::ProjectionPredicate { - projection_ty: tcx - .mk_alias_ty(goal.predicate.def_id(), [goal.predicate.self_ty(), inputs]), - term: output.into(), - }) - .to_predicate(tcx); - Self::consider_assumption_with_certainty(ecx, goal, pred, output_is_sized_certainty) - } else { - ecx.make_canonical_response(Certainty::AMBIGUOUS) - } + let pred = tupled_inputs_and_output + .map_bound(|(inputs, output)| ty::ProjectionPredicate { + projection_ty: tcx + .mk_alias_ty(goal.predicate.def_id(), [goal.predicate.self_ty(), inputs]), + term: output.into(), + }) + .to_predicate(tcx); + // A built-in `Fn` impl only holds if the output is sized. + // (FIXME: technically we only need to check this if the type is a fn ptr...) + Self::consider_implied_clause(ecx, goal, pred, [goal.with(tcx, output_is_sized_pred)]) } fn consider_builtin_tuple_candidate( @@ -474,7 +471,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { let term = substs.as_generator().return_ty().into(); - Self::consider_assumption( + Self::consider_implied_clause( ecx, goal, ty::Binder::dummy(ty::ProjectionPredicate { @@ -482,6 +479,9 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { term, }) .to_predicate(tcx), + // Technically, we need to check that the future type is Sized, + // but that's already proven by the generator being WF. + [], ) } @@ -511,7 +511,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { bug!("unexpected associated item `<{self_ty} as Generator>::{name}`") }; - Self::consider_assumption( + Self::consider_implied_clause( ecx, goal, ty::Binder::dummy(ty::ProjectionPredicate { @@ -521,6 +521,9 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { term, }) .to_predicate(tcx), + // Technically, we need to check that the future type is Sized, + // but that's already proven by the generator being WF. + [], ) } diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs index dd47a5ae150..f2f25ef850a 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs @@ -62,11 +62,11 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { }) } - fn consider_assumption_with_certainty( + fn consider_implied_clause( ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, assumption: ty::Predicate<'tcx>, - assumption_certainty: Certainty, + requirements: impl IntoIterator>>, ) -> QueryResult<'tcx> { if let Some(poly_trait_pred) = assumption.to_opt_poly_trait_pred() && poly_trait_pred.def_id() == goal.predicate.def_id() @@ -75,14 +75,13 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { ecx.infcx.probe(|_| { let assumption_trait_pred = ecx.infcx.instantiate_binder_with_infer(poly_trait_pred); - let nested_goals = ecx.infcx.eq( + let mut nested_goals = ecx.infcx.eq( goal.param_env, goal.predicate.trait_ref, assumption_trait_pred.trait_ref, )?; - ecx.evaluate_all(nested_goals).and_then(|certainty| { - ecx.make_canonical_response(certainty.unify_and(assumption_certainty)) - }) + nested_goals.extend(requirements); + ecx.evaluate_all_and_make_canonical_response(nested_goals) }) } else { Err(NoSolution) @@ -178,29 +177,25 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { goal_kind: ty::ClosureKind, ) -> QueryResult<'tcx> { let tcx = ecx.tcx(); - if let Some(tupled_inputs_and_output) = + let Some(tupled_inputs_and_output) = structural_traits::extract_tupled_inputs_and_output_from_callable( tcx, goal.predicate.self_ty(), goal_kind, - )? - { - // A built-in `Fn` trait needs to check that its output is `Sized` - // (FIXME: technically we only need to check this if the type is a fn ptr...) - let output_is_sized_pred = tupled_inputs_and_output - .map_bound(|(_, output)| tcx.at(DUMMY_SP).mk_trait_ref(LangItem::Sized, [output])); - let (_, output_is_sized_certainty) = - ecx.evaluate_goal(goal.with(tcx, output_is_sized_pred))?; + )? else { + return ecx.make_canonical_response(Certainty::AMBIGUOUS); + }; + let output_is_sized_pred = tupled_inputs_and_output + .map_bound(|(_, output)| tcx.at(DUMMY_SP).mk_trait_ref(LangItem::Sized, [output])); - let pred = tupled_inputs_and_output - .map_bound(|(inputs, _)| { - tcx.mk_trait_ref(goal.predicate.def_id(), [goal.predicate.self_ty(), inputs]) - }) - .to_predicate(tcx); - Self::consider_assumption_with_certainty(ecx, goal, pred, output_is_sized_certainty) - } else { - ecx.make_canonical_response(Certainty::AMBIGUOUS) - } + let pred = tupled_inputs_and_output + .map_bound(|(inputs, _)| { + tcx.mk_trait_ref(goal.predicate.def_id(), [goal.predicate.self_ty(), inputs]) + }) + .to_predicate(tcx); + // A built-in `Fn` impl only holds if the output is sized. + // (FIXME: technically we only need to check this if the type is a fn ptr...) + Self::consider_implied_clause(ecx, goal, pred, [goal.with(tcx, output_is_sized_pred)]) } fn consider_builtin_tuple_candidate( @@ -236,6 +231,8 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { } // Async generator unconditionally implement `Future` + // Technically, we need to check that the future output type is Sized, + // but that's already proven by the generator being WF. ecx.make_canonical_response(Certainty::Yes) } @@ -255,13 +252,16 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { } let generator = substs.as_generator(); - Self::consider_assumption( + Self::consider_implied_clause( ecx, goal, ty::Binder::dummy( tcx.mk_trait_ref(goal.predicate.def_id(), [self_ty, generator.resume_ty()]), ) .to_predicate(tcx), + // Technically, we need to check that the generator types are Sized, + // but that's already proven by the generator being WF. + [], ) }