Skip to content

Commit 7f90b66

Browse files
committed
Make gen blocks implement the Iterator trait
1 parent 81cc1f5 commit 7f90b66

File tree

24 files changed

+296
-21
lines changed

24 files changed

+296
-21
lines changed

compiler/rustc_ast_lowering/src/expr.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -322,7 +322,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
322322
e.id,
323323
None,
324324
e.span,
325-
hir::AsyncGeneratorKind::Block,
325+
hir::AsyncCoroutineKind::Block,
326326
|this| this.with_new_scopes(|this| this.lower_block_expr(block)),
327327
),
328328
ExprKind::Yield(opt_expr) => self.lower_expr_yield(e.span, opt_expr.as_deref()),
@@ -686,7 +686,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
686686
span: Span,
687687
// We re-use the async enum, because we have the same cases.
688688
// FIXME(oli-obk): rename the enum.
689-
gen_kind: hir::AsyncGeneratorKind,
689+
gen_kind: hir::AsyncCoroutineKind,
690690
body: impl FnOnce(&mut Self) -> hir::Expr<'hir>,
691691
) -> hir::ExprKind<'hir> {
692692
let output = hir::FnRetTy::DefaultReturn(self.lower_span(span));
@@ -701,7 +701,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
701701
});
702702

703703
let body = self.lower_body(move |this| {
704-
this.generator_kind = Some(hir::GeneratorKind::Iter(gen_kind));
704+
this.coroutine_kind = Some(hir::CoroutineKind::Gen(gen_kind));
705705

706706
let res = body(this);
707707
(&[], res)

compiler/rustc_hir/src/lang_items.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,7 @@ language_item_table! {
210210

211211
FnOnceOutput, sym::fn_once_output, fn_once_output, Target::AssocTy, GenericRequirement::None;
212212

213+
Iterator, sym::iterator, iterator_trait, Target::Trait, GenericRequirement::Exact(0);
213214
Future, sym::future_trait, future_trait, Target::Trait, GenericRequirement::Exact(0);
214215
CoroutineState, sym::coroutine_state, gen_state, Target::Enum, GenericRequirement::None;
215216
Coroutine, sym::coroutine, gen_trait, Target::Trait, GenericRequirement::Minimum(1);

compiler/rustc_hir_typeck/src/check.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,15 +59,15 @@ pub(super) fn check_fn<'a, 'tcx>(
5959
&& can_be_coroutine.is_some()
6060
{
6161
let yield_ty = match kind {
62-
hir::GeneratorKind::Gen(..) | hir::CoroutineKind::Coroutine => {
62+
hir::CoroutineKind::Gen(..) | hir::CoroutineKind::Coroutine => {
6363
let yield_ty = fcx.next_ty_var(TypeVariableOrigin {
6464
kind: TypeVariableOriginKind::TypeInference,
6565
span,
6666
});
6767
fcx.require_type_is_sized(yield_ty, span, traits::SizedYieldType);
6868
yield_ty
6969
}
70-
hir::GeneratorKind::Async(..) => Ty::new_unit(tcx),
70+
hir::CoroutineKind::Async(..) => Ty::new_unit(tcx),
7171
};
7272

7373
// Resume type defaults to `()` if the coroutine has no argument.

compiler/rustc_hir_typeck/src/closure.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -652,6 +652,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
652652
},
653653
)
654654
}
655+
Some(hir::CoroutineKind::Gen(hir::AsyncCoroutineKind::Fn)) => todo!(),
655656

656657
_ => astconv.ty_infer(None, decl.output.span()),
657658
},

compiler/rustc_middle/src/traits/select.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,10 @@ pub enum SelectionCandidate<'tcx> {
144144
/// generated for an async construct.
145145
FutureCandidate,
146146

147+
/// Implementation of an `Iterator` trait by one of the generator types
148+
/// generated for a gen construct.
149+
IteratorCandidate,
150+
147151
/// Implementation of a `Fn`-family trait by one of the anonymous
148152
/// types generated for a fn pointer type (e.g., `fn(int) -> int`)
149153
FnPointerCandidate {

compiler/rustc_middle/src/ty/context.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -766,6 +766,11 @@ impl<'tcx> TyCtxt<'tcx> {
766766
matches!(self.coroutine_kind(def_id), Some(hir::CoroutineKind::Async(_)))
767767
}
768768

769+
/// Returns `true` if the node pointed to by `def_id` is a coroutine for a gen construct.
770+
pub fn coroutine_is_gen(self, def_id: DefId) -> bool {
771+
matches!(self.coroutine_kind(def_id), Some(hir::CoroutineKind::Gen(_)))
772+
}
773+
769774
pub fn stability(self) -> &'tcx stability::Index {
770775
self.stability_index(())
771776
}

compiler/rustc_span/src/symbol.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,7 @@ symbols! {
226226
IpAddr,
227227
IrTyKind,
228228
Is,
229+
Item,
229230
ItemContext,
230231
IterEmpty,
231232
IterOnce,
@@ -911,6 +912,7 @@ symbols! {
911912
iter,
912913
iter_mut,
913914
iter_repeat,
915+
iterator,
914916
iterator_collect_fn,
915917
kcfi,
916918
keyword,

compiler/rustc_trait_selection/src/solve/assembly/mod.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,15 @@ pub(super) trait GoalKind<'tcx>:
199199
goal: Goal<'tcx, Self>,
200200
) -> QueryResult<'tcx>;
201201

202-
/// A coroutine (that doesn't come from an `async` desugaring) is known to
202+
/// A coroutine (that comes from an `gen` desugaring) is known to implement
203+
/// `Iterator<Item = O>`, where `O` is given by the generator's yield type
204+
/// that was computed during type-checking.
205+
fn consider_builtin_iterator_candidate(
206+
ecx: &mut EvalCtxt<'_, 'tcx>,
207+
goal: Goal<'tcx, Self>,
208+
) -> QueryResult<'tcx>;
209+
210+
/// A coroutine (that doesn't come from an `async` or `gen` desugaring) is known to
203211
/// implement `Coroutine<R, Yield = Y, Return = O>`, given the resume, yield,
204212
/// and return types of the coroutine computed during type-checking.
205213
fn consider_builtin_coroutine_candidate(
@@ -552,6 +560,8 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
552560
G::consider_builtin_pointee_candidate(self, goal)
553561
} else if lang_items.future_trait() == Some(trait_def_id) {
554562
G::consider_builtin_future_candidate(self, goal)
563+
} else if lang_items.iterator_trait() == Some(trait_def_id) {
564+
G::consider_builtin_iterator_candidate(self, goal)
555565
} else if lang_items.gen_trait() == Some(trait_def_id) {
556566
G::consider_builtin_coroutine_candidate(self, goal)
557567
} else if lang_items.discriminant_kind_trait() == Some(trait_def_id) {

compiler/rustc_trait_selection/src/solve/project_goals/mod.rs

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -485,6 +485,37 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
485485
)
486486
}
487487

488+
fn consider_builtin_iterator_candidate(
489+
ecx: &mut EvalCtxt<'_, 'tcx>,
490+
goal: Goal<'tcx, Self>,
491+
) -> QueryResult<'tcx> {
492+
let self_ty = goal.predicate.self_ty();
493+
let ty::Coroutine(def_id, args, _) = *self_ty.kind() else {
494+
return Err(NoSolution);
495+
};
496+
497+
// Generators are not Iterators unless they come from `gen` desugaring
498+
let tcx = ecx.tcx();
499+
if !tcx.coroutine_is_gen(def_id) {
500+
return Err(NoSolution);
501+
}
502+
503+
let term = args.as_coroutine().yield_ty().into();
504+
505+
Self::consider_implied_clause(
506+
ecx,
507+
goal,
508+
ty::ProjectionPredicate {
509+
projection_ty: ty::AliasTy::new(ecx.tcx(), goal.predicate.def_id(), [self_ty]),
510+
term,
511+
}
512+
.to_predicate(tcx),
513+
// Technically, we need to check that the iterator type is Sized,
514+
// but that's already proven by the generator being WF.
515+
[],
516+
)
517+
}
518+
488519
fn consider_builtin_coroutine_candidate(
489520
ecx: &mut EvalCtxt<'_, 'tcx>,
490521
goal: Goal<'tcx, Self>,
@@ -496,7 +527,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
496527

497528
// `async`-desugared coroutines do not implement the coroutine trait
498529
let tcx = ecx.tcx();
499-
if tcx.coroutine_is_async(def_id) {
530+
if tcx.coroutine_is_async(def_id) || tcx.coroutine_is_gen(def_id) {
500531
return Err(NoSolution);
501532
}
502533

@@ -523,7 +554,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
523554
term,
524555
}
525556
.to_predicate(tcx),
526-
// Technically, we need to check that the future type is Sized,
557+
// Technically, we need to check that the coroutine type is Sized,
527558
// but that's already proven by the coroutine being WF.
528559
[],
529560
)

compiler/rustc_trait_selection/src/solve/trait_goals.rs

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -335,6 +335,30 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
335335
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
336336
}
337337

338+
fn consider_builtin_iterator_candidate(
339+
ecx: &mut EvalCtxt<'_, 'tcx>,
340+
goal: Goal<'tcx, Self>,
341+
) -> QueryResult<'tcx> {
342+
if goal.predicate.polarity != ty::ImplPolarity::Positive {
343+
return Err(NoSolution);
344+
}
345+
346+
let ty::Coroutine(def_id, _, _) = *goal.predicate.self_ty().kind() else {
347+
return Err(NoSolution);
348+
};
349+
350+
// Coroutines are not iterators unless they come from `gen` desugaring
351+
let tcx = ecx.tcx();
352+
if !tcx.coroutine_is_gen(def_id) {
353+
return Err(NoSolution);
354+
}
355+
356+
// Gen coroutines unconditionally implement `Iterator`
357+
// Technically, we need to check that the iterator output type is Sized,
358+
// but that's already proven by the coroutines being WF.
359+
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
360+
}
361+
338362
fn consider_builtin_coroutine_candidate(
339363
ecx: &mut EvalCtxt<'_, 'tcx>,
340364
goal: Goal<'tcx, Self>,
@@ -350,7 +374,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
350374

351375
// `async`-desugared coroutines do not implement the coroutine trait
352376
let tcx = ecx.tcx();
353-
if tcx.coroutine_is_async(def_id) {
377+
if tcx.coroutine_is_async(def_id) || tcx.coroutine_is_gen(def_id) {
354378
return Err(NoSolution);
355379
}
356380

0 commit comments

Comments
 (0)