mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-22 06:44:35 +00:00
Implement FusedIterator
for gen
block
This commit is contained in:
parent
03994e498d
commit
ae4c5c891e
@ -214,6 +214,7 @@ language_item_table! {
|
|||||||
FnOnceOutput, sym::fn_once_output, fn_once_output, Target::AssocTy, GenericRequirement::None;
|
FnOnceOutput, sym::fn_once_output, fn_once_output, Target::AssocTy, GenericRequirement::None;
|
||||||
|
|
||||||
Iterator, sym::iterator, iterator_trait, Target::Trait, GenericRequirement::Exact(0);
|
Iterator, sym::iterator, iterator_trait, Target::Trait, GenericRequirement::Exact(0);
|
||||||
|
FusedIterator, sym::fused_iterator, fused_iterator_trait, Target::Trait, GenericRequirement::Exact(0);
|
||||||
Future, sym::future_trait, future_trait, Target::Trait, GenericRequirement::Exact(0);
|
Future, sym::future_trait, future_trait, Target::Trait, GenericRequirement::Exact(0);
|
||||||
AsyncIterator, sym::async_iterator, async_iterator_trait, Target::Trait, GenericRequirement::Exact(0);
|
AsyncIterator, sym::async_iterator, async_iterator_trait, Target::Trait, GenericRequirement::Exact(0);
|
||||||
|
|
||||||
|
@ -207,6 +207,7 @@ symbols! {
|
|||||||
FromResidual,
|
FromResidual,
|
||||||
FsOpenOptions,
|
FsOpenOptions,
|
||||||
FsPermissions,
|
FsPermissions,
|
||||||
|
FusedIterator,
|
||||||
Future,
|
Future,
|
||||||
FutureOutput,
|
FutureOutput,
|
||||||
GlobalAlloc,
|
GlobalAlloc,
|
||||||
@ -885,6 +886,7 @@ symbols! {
|
|||||||
fsub_algebraic,
|
fsub_algebraic,
|
||||||
fsub_fast,
|
fsub_fast,
|
||||||
fundamental,
|
fundamental,
|
||||||
|
fused_iterator,
|
||||||
future,
|
future,
|
||||||
future_trait,
|
future_trait,
|
||||||
gdb_script_file,
|
gdb_script_file,
|
||||||
|
@ -215,6 +215,13 @@ pub(super) trait GoalKind<'tcx>:
|
|||||||
goal: Goal<'tcx, Self>,
|
goal: Goal<'tcx, Self>,
|
||||||
) -> QueryResult<'tcx>;
|
) -> QueryResult<'tcx>;
|
||||||
|
|
||||||
|
/// A coroutine (that comes from a `gen` desugaring) is known to implement
|
||||||
|
/// `FusedIterator`
|
||||||
|
fn consider_builtin_fused_iterator_candidate(
|
||||||
|
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||||
|
goal: Goal<'tcx, Self>,
|
||||||
|
) -> QueryResult<'tcx>;
|
||||||
|
|
||||||
fn consider_builtin_async_iterator_candidate(
|
fn consider_builtin_async_iterator_candidate(
|
||||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||||
goal: Goal<'tcx, Self>,
|
goal: Goal<'tcx, Self>,
|
||||||
@ -497,6 +504,8 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
|||||||
G::consider_builtin_future_candidate(self, goal)
|
G::consider_builtin_future_candidate(self, goal)
|
||||||
} else if lang_items.iterator_trait() == Some(trait_def_id) {
|
} else if lang_items.iterator_trait() == Some(trait_def_id) {
|
||||||
G::consider_builtin_iterator_candidate(self, goal)
|
G::consider_builtin_iterator_candidate(self, goal)
|
||||||
|
} else if lang_items.fused_iterator_trait() == Some(trait_def_id) {
|
||||||
|
G::consider_builtin_fused_iterator_candidate(self, goal)
|
||||||
} else if lang_items.async_iterator_trait() == Some(trait_def_id) {
|
} else if lang_items.async_iterator_trait() == Some(trait_def_id) {
|
||||||
G::consider_builtin_async_iterator_candidate(self, goal)
|
G::consider_builtin_async_iterator_candidate(self, goal)
|
||||||
} else if lang_items.coroutine_trait() == Some(trait_def_id) {
|
} else if lang_items.coroutine_trait() == Some(trait_def_id) {
|
||||||
|
@ -647,6 +647,13 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn consider_builtin_fused_iterator_candidate(
|
||||||
|
_ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||||
|
goal: Goal<'tcx, Self>,
|
||||||
|
) -> QueryResult<'tcx> {
|
||||||
|
bug!("`FusedIterator` does not have an associated type: {:?}", goal);
|
||||||
|
}
|
||||||
|
|
||||||
fn consider_builtin_async_iterator_candidate(
|
fn consider_builtin_async_iterator_candidate(
|
||||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||||
goal: Goal<'tcx, Self>,
|
goal: Goal<'tcx, Self>,
|
||||||
|
@ -456,6 +456,28 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
|||||||
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn consider_builtin_fused_iterator_candidate(
|
||||||
|
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||||
|
goal: Goal<'tcx, Self>,
|
||||||
|
) -> QueryResult<'tcx> {
|
||||||
|
if goal.predicate.polarity != ty::ImplPolarity::Positive {
|
||||||
|
return Err(NoSolution);
|
||||||
|
}
|
||||||
|
|
||||||
|
let ty::Coroutine(def_id, _) = *goal.predicate.self_ty().kind() else {
|
||||||
|
return Err(NoSolution);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Coroutines are not iterators unless they come from `gen` desugaring
|
||||||
|
let tcx = ecx.tcx();
|
||||||
|
if !tcx.coroutine_is_gen(def_id) {
|
||||||
|
return Err(NoSolution);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gen coroutines unconditionally implement `FusedIterator`
|
||||||
|
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
|
||||||
|
}
|
||||||
|
|
||||||
fn consider_builtin_async_iterator_candidate(
|
fn consider_builtin_async_iterator_candidate(
|
||||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||||
goal: Goal<'tcx, Self>,
|
goal: Goal<'tcx, Self>,
|
||||||
|
@ -118,6 +118,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||||||
self.assemble_future_candidates(obligation, &mut candidates);
|
self.assemble_future_candidates(obligation, &mut candidates);
|
||||||
} else if lang_items.iterator_trait() == Some(def_id) {
|
} else if lang_items.iterator_trait() == Some(def_id) {
|
||||||
self.assemble_iterator_candidates(obligation, &mut candidates);
|
self.assemble_iterator_candidates(obligation, &mut candidates);
|
||||||
|
} else if lang_items.fused_iterator_trait() == Some(def_id) {
|
||||||
|
self.assemble_fused_iterator_candidates(obligation, &mut candidates);
|
||||||
} else if lang_items.async_iterator_trait() == Some(def_id) {
|
} else if lang_items.async_iterator_trait() == Some(def_id) {
|
||||||
self.assemble_async_iterator_candidates(obligation, &mut candidates);
|
self.assemble_async_iterator_candidates(obligation, &mut candidates);
|
||||||
} else if lang_items.async_fn_kind_helper() == Some(def_id) {
|
} else if lang_items.async_fn_kind_helper() == Some(def_id) {
|
||||||
@ -302,14 +304,31 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||||||
candidates: &mut SelectionCandidateSet<'tcx>,
|
candidates: &mut SelectionCandidateSet<'tcx>,
|
||||||
) {
|
) {
|
||||||
let self_ty = obligation.self_ty().skip_binder();
|
let self_ty = obligation.self_ty().skip_binder();
|
||||||
if let ty::Coroutine(did, ..) = self_ty.kind() {
|
// gen constructs get lowered to a special kind of coroutine that
|
||||||
// gen constructs get lowered to a special kind of coroutine that
|
// should directly `impl Iterator`.
|
||||||
// should directly `impl Iterator`.
|
if let ty::Coroutine(did, ..) = self_ty.kind()
|
||||||
if self.tcx().coroutine_is_gen(*did) {
|
&& self.tcx().coroutine_is_gen(*did)
|
||||||
debug!(?self_ty, ?obligation, "assemble_iterator_candidates",);
|
{
|
||||||
|
debug!(?self_ty, ?obligation, "assemble_iterator_candidates",);
|
||||||
|
|
||||||
candidates.vec.push(IteratorCandidate);
|
candidates.vec.push(IteratorCandidate);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn assemble_fused_iterator_candidates(
|
||||||
|
&mut self,
|
||||||
|
obligation: &PolyTraitObligation<'tcx>,
|
||||||
|
candidates: &mut SelectionCandidateSet<'tcx>,
|
||||||
|
) {
|
||||||
|
let self_ty = obligation.self_ty().skip_binder();
|
||||||
|
// gen constructs get lowered to a special kind of coroutine that
|
||||||
|
// should directly `impl FusedIterator`.
|
||||||
|
if let ty::Coroutine(did, ..) = self_ty.kind()
|
||||||
|
&& self.tcx().coroutine_is_gen(*did)
|
||||||
|
{
|
||||||
|
debug!(?self_ty, ?obligation, "assemble_fused_iterator_candidates",);
|
||||||
|
|
||||||
|
candidates.vec.push(BuiltinCandidate { has_nested: false });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -267,6 +267,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||||||
self.copy_clone_conditions(obligation)
|
self.copy_clone_conditions(obligation)
|
||||||
} else if Some(trait_def) == lang_items.clone_trait() {
|
} else if Some(trait_def) == lang_items.clone_trait() {
|
||||||
self.copy_clone_conditions(obligation)
|
self.copy_clone_conditions(obligation)
|
||||||
|
} else if Some(trait_def) == lang_items.fused_iterator_trait() {
|
||||||
|
self.fused_iterator_conditions(obligation)
|
||||||
} else {
|
} else {
|
||||||
bug!("unexpected builtin trait {:?}", trait_def)
|
bug!("unexpected builtin trait {:?}", trait_def)
|
||||||
};
|
};
|
||||||
|
@ -2259,6 +2259,20 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn fused_iterator_conditions(
|
||||||
|
&mut self,
|
||||||
|
obligation: &PolyTraitObligation<'tcx>,
|
||||||
|
) -> BuiltinImplConditions<'tcx> {
|
||||||
|
let self_ty = self.infcx.shallow_resolve(obligation.self_ty().skip_binder());
|
||||||
|
if let ty::Coroutine(did, ..) = *self_ty.kind()
|
||||||
|
&& self.tcx().coroutine_is_gen(did)
|
||||||
|
{
|
||||||
|
BuiltinImplConditions::Where(ty::Binder::dummy(Vec::new()))
|
||||||
|
} else {
|
||||||
|
BuiltinImplConditions::None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// For default impls, we need to break apart a type into its
|
/// For default impls, we need to break apart a type into its
|
||||||
/// "constituent types" -- meaning, the types that it contains.
|
/// "constituent types" -- meaning, the types that it contains.
|
||||||
///
|
///
|
||||||
|
@ -28,6 +28,7 @@ pub unsafe trait TrustedFused {}
|
|||||||
#[rustc_unsafe_specialization_marker]
|
#[rustc_unsafe_specialization_marker]
|
||||||
// FIXME: this should be a #[marker] and have another blanket impl for T: TrustedFused
|
// FIXME: this should be a #[marker] and have another blanket impl for T: TrustedFused
|
||||||
// but that ICEs iter::Fuse specializations.
|
// but that ICEs iter::Fuse specializations.
|
||||||
|
#[cfg_attr(not(bootstrap), lang = "fused_iterator")]
|
||||||
pub trait FusedIterator: Iterator {}
|
pub trait FusedIterator: Iterator {}
|
||||||
|
|
||||||
#[stable(feature = "fused", since = "1.26.0")]
|
#[stable(feature = "fused", since = "1.26.0")]
|
||||||
|
21
tests/ui/coroutine/gen_block_is_fused_iter.rs
Normal file
21
tests/ui/coroutine/gen_block_is_fused_iter.rs
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
//@ revisions: next old
|
||||||
|
//@compile-flags: --edition 2024 -Zunstable-options
|
||||||
|
//@[next] compile-flags: -Znext-solver
|
||||||
|
//@ check-pass
|
||||||
|
#![feature(gen_blocks)]
|
||||||
|
|
||||||
|
use std::iter::FusedIterator;
|
||||||
|
|
||||||
|
fn foo() -> impl FusedIterator {
|
||||||
|
gen { yield 42 }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bar() -> impl FusedIterator<Item = u16> {
|
||||||
|
gen { yield 42 }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn baz() -> impl FusedIterator + Iterator<Item = i64> {
|
||||||
|
gen { yield 42 }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
Loading…
Reference in New Issue
Block a user