Implement Generator and Future
This commit is contained in:
parent
8434b43a7f
commit
d600b94ebb
8 changed files with 259 additions and 1 deletions
|
@ -138,6 +138,16 @@ pub(super) trait GoalKind<'tcx>: TypeFoldable<'tcx> + Copy + Eq {
|
|||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> QueryResult<'tcx>;
|
||||
|
||||
fn consider_builtin_future_candidate(
|
||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> QueryResult<'tcx>;
|
||||
|
||||
fn consider_builtin_generator_candidate(
|
||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> QueryResult<'tcx>;
|
||||
}
|
||||
|
||||
impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||
|
@ -266,6 +276,10 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
|||
G::consider_builtin_tuple_candidate(self, goal)
|
||||
} else if lang_items.pointee_trait() == Some(trait_def_id) {
|
||||
G::consider_builtin_pointee_candidate(self, goal)
|
||||
} else if lang_items.future_trait() == Some(trait_def_id) {
|
||||
G::consider_builtin_future_candidate(self, goal)
|
||||
} else if lang_items.gen_trait() == Some(trait_def_id) {
|
||||
G::consider_builtin_generator_candidate(self, goal)
|
||||
} else {
|
||||
Err(NoSolution)
|
||||
};
|
||||
|
|
|
@ -16,7 +16,7 @@ use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
|
|||
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;
|
||||
|
||||
|
@ -482,6 +482,73 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
|
|||
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.
|
||||
|
|
|
@ -192,6 +192,50 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
|||
) -> QueryResult<'tcx> {
|
||||
ecx.make_canonical_response(Certainty::Yes)
|
||||
}
|
||||
|
||||
fn consider_builtin_future_candidate(
|
||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> QueryResult<'tcx> {
|
||||
let ty::Generator(def_id, _, _) = *goal.predicate.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);
|
||||
}
|
||||
|
||||
// Async generator unconditionally implement `Future`
|
||||
ecx.make_canonical_response(Certainty::Yes)
|
||||
}
|
||||
|
||||
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();
|
||||
Self::consider_assumption(
|
||||
ecx,
|
||||
goal,
|
||||
ty::Binder::dummy(
|
||||
tcx.mk_trait_ref(goal.predicate.def_id(), [self_ty, generator.resume_ty()]),
|
||||
)
|
||||
.to_predicate(tcx),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||
|
|
|
@ -173,6 +173,7 @@ pub(super) fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>(
|
|||
}
|
||||
}
|
||||
|
||||
// Returns a binder of the tupled inputs types and output type from a builtin callable type.
|
||||
pub(crate) fn extract_tupled_inputs_and_output_from_callable<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
self_ty: Ty<'tcx>,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue