Skip to content

Commit 6fcbe33

Browse files
authored
Unrolled build for #137725
Rollup merge of #137725 - oli-obk:i-want-to-move-it-move-it, r=compiler-errors,traviscross Add `iter` macro See related discussion in https://rust-lang.zulipchat.com/#narrow/channel/481571-t-lang.2Fgen/topic/iter!.20macro/near/500784563 very little error case testing so far, but the success path works. There is also no `IterFn` trait yet, as T-lang didn't consider it something urgently needed I think we can implement it in follow-up PRs. r? lang for the tests, `@compiler-errors` for the impl
2 parents 59aa1e8 + 5fbdfc3 commit 6fcbe33

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+826
-61
lines changed

compiler/rustc_ast_lowering/src/expr.rs

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
use std::assert_matches::assert_matches;
21
use std::ops::ControlFlow;
32
use std::sync::Arc;
43

@@ -1199,11 +1198,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
11991198
let closure_def_id = self.local_def_id(closure_id);
12001199
let (binder_clause, generic_params) = self.lower_closure_binder(binder);
12011200

1202-
assert_matches!(
1203-
coroutine_kind,
1204-
CoroutineKind::Async { .. },
1205-
"only async closures are supported currently"
1206-
);
1201+
let coroutine_desugaring = match coroutine_kind {
1202+
CoroutineKind::Async { .. } => hir::CoroutineDesugaring::Async,
1203+
CoroutineKind::Gen { .. } => hir::CoroutineDesugaring::Gen,
1204+
CoroutineKind::AsyncGen { span, .. } => {
1205+
span_bug!(span, "only async closures and `iter!` closures are supported currently")
1206+
}
1207+
};
12071208

12081209
let body = self.with_new_scopes(fn_decl_span, |this| {
12091210
let inner_decl =
@@ -1247,7 +1248,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
12471248
// Lower this as a `CoroutineClosure`. That will ensure that HIR typeck
12481249
// knows that a `FnDecl` output type like `-> &str` actually means
12491250
// "coroutine that returns &str", rather than directly returning a `&str`.
1250-
kind: hir::ClosureKind::CoroutineClosure(hir::CoroutineDesugaring::Async),
1251+
kind: hir::ClosureKind::CoroutineClosure(coroutine_desugaring),
12511252
constness: hir::Constness::NotConst,
12521253
});
12531254
hir::ExprKind::Closure(c)

compiler/rustc_ast_passes/src/feature_gate.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -477,11 +477,12 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
477477
for span in spans {
478478
if (!visitor.features.coroutines() && !span.allows_unstable(sym::coroutines))
479479
&& (!visitor.features.gen_blocks() && !span.allows_unstable(sym::gen_blocks))
480+
&& (!visitor.features.yield_expr() && !span.allows_unstable(sym::yield_expr))
480481
{
481482
#[allow(rustc::untranslatable_diagnostic)]
482-
// Don't know which of the two features to include in the
483-
// error message, so I am arbitrarily picking one.
484-
feature_err(&visitor.sess, sym::coroutines, *span, "yield syntax is experimental")
483+
// Emit yield_expr as the error, since that will be sufficient. You can think of it
484+
// as coroutines and gen_blocks imply yield_expr.
485+
feature_err(&visitor.sess, sym::yield_expr, *span, "yield syntax is experimental")
485486
.emit();
486487
}
487488
}

compiler/rustc_borrowck/src/type_check/input_output.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
5252
assert_matches!(
5353
self.tcx().coroutine_kind(self.tcx().coroutine_for_closure(mir_def_id)),
5454
Some(hir::CoroutineKind::Desugared(
55-
hir::CoroutineDesugaring::Async,
55+
hir::CoroutineDesugaring::Async | hir::CoroutineDesugaring::Gen,
5656
hir::CoroutineSource::Closure
5757
)),
5858
"this needs to be modified if we're lowering non-async closures"
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
use rustc_ast::ptr::P;
2+
use rustc_ast::tokenstream::TokenStream;
3+
use rustc_ast::{CoroutineKind, DUMMY_NODE_ID, Expr, ast, token};
4+
use rustc_errors::PResult;
5+
use rustc_expand::base::{self, DummyResult, ExpandResult, ExtCtxt, MacroExpanderResult};
6+
use rustc_span::Span;
7+
8+
pub(crate) fn expand<'cx>(
9+
cx: &'cx mut ExtCtxt<'_>,
10+
sp: Span,
11+
tts: TokenStream,
12+
) -> MacroExpanderResult<'cx> {
13+
let closure = match parse_closure(cx, sp, tts) {
14+
Ok(parsed) => parsed,
15+
Err(err) => {
16+
return ExpandResult::Ready(DummyResult::any(sp, err.emit()));
17+
}
18+
};
19+
20+
ExpandResult::Ready(base::MacEager::expr(closure))
21+
}
22+
23+
fn parse_closure<'a>(
24+
cx: &mut ExtCtxt<'a>,
25+
span: Span,
26+
stream: TokenStream,
27+
) -> PResult<'a, P<Expr>> {
28+
let mut closure_parser = cx.new_parser_from_tts(stream);
29+
30+
let coroutine_kind = Some(CoroutineKind::Gen {
31+
span,
32+
closure_id: DUMMY_NODE_ID,
33+
return_impl_trait_id: DUMMY_NODE_ID,
34+
});
35+
36+
let mut closure = closure_parser.parse_expr()?;
37+
match &mut closure.kind {
38+
ast::ExprKind::Closure(c) => {
39+
if let Some(kind) = c.coroutine_kind {
40+
cx.dcx().span_err(kind.span(), "only plain closures allowed in `iter!`");
41+
}
42+
c.coroutine_kind = coroutine_kind;
43+
if closure_parser.token != token::Eof {
44+
closure_parser.unexpected()?;
45+
}
46+
Ok(closure)
47+
}
48+
_ => {
49+
cx.dcx().span_err(closure.span, "`iter!` body must be a closure");
50+
Err(closure_parser.unexpected().unwrap_err())
51+
}
52+
}
53+
}

compiler/rustc_builtin_macros/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ mod errors;
4747
mod format;
4848
mod format_foreign;
4949
mod global_allocator;
50+
mod iter;
5051
mod log_syntax;
5152
mod pattern_type;
5253
mod source_util;
@@ -95,6 +96,7 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) {
9596
include: source_util::expand_include,
9697
include_bytes: source_util::expand_include_bytes,
9798
include_str: source_util::expand_include_str,
99+
iter: iter::expand,
98100
line: source_util::expand_line,
99101
log_syntax: log_syntax::expand_log_syntax,
100102
module_path: source_util::expand_mod,

compiler/rustc_const_eval/src/check_consts/check.rs

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -589,12 +589,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
589589

590590
Rvalue::Aggregate(kind, ..) => {
591591
if let AggregateKind::Coroutine(def_id, ..) = kind.as_ref()
592-
&& let Some(
593-
coroutine_kind @ hir::CoroutineKind::Desugared(
594-
hir::CoroutineDesugaring::Async,
595-
_,
596-
),
597-
) = self.tcx.coroutine_kind(def_id)
592+
&& let Some(coroutine_kind) = self.tcx.coroutine_kind(def_id)
598593
{
599594
self.check_op(ops::Coroutine(coroutine_kind));
600595
}

compiler/rustc_const_eval/src/check_consts/ops.rs

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -486,24 +486,25 @@ impl<'tcx> NonConstOp<'tcx> for IntrinsicUnstable {
486486
pub(crate) struct Coroutine(pub hir::CoroutineKind);
487487
impl<'tcx> NonConstOp<'tcx> for Coroutine {
488488
fn status_in_item(&self, _: &ConstCx<'_, 'tcx>) -> Status {
489-
if let hir::CoroutineKind::Desugared(
490-
hir::CoroutineDesugaring::Async,
491-
hir::CoroutineSource::Block,
492-
) = self.0
493-
{
494-
Status::Unstable {
489+
match self.0 {
490+
hir::CoroutineKind::Desugared(
491+
hir::CoroutineDesugaring::Async,
492+
hir::CoroutineSource::Block,
493+
)
494+
// FIXME(coroutines): eventually we want to gate const coroutine coroutines behind a
495+
// different feature.
496+
| hir::CoroutineKind::Coroutine(_) => Status::Unstable {
495497
gate: sym::const_async_blocks,
496498
gate_already_checked: false,
497499
safe_to_expose_on_stable: false,
498500
is_function_call: false,
499-
}
500-
} else {
501-
Status::Forbidden
501+
},
502+
_ => Status::Forbidden,
502503
}
503504
}
504505

505506
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> {
506-
let msg = format!("{:#}s are not allowed in {}s", self.0, ccx.const_kind());
507+
let msg = format!("{} are not allowed in {}s", self.0.to_plural_string(), ccx.const_kind());
507508
if let Status::Unstable { gate, .. } = self.status_in_item(ccx) {
508509
ccx.tcx.sess.create_feature_err(errors::UnallowedOpInConstContext { span, msg }, gate)
509510
} else {

compiler/rustc_hir/src/hir.rs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2061,12 +2061,19 @@ impl CoroutineKind {
20612061
CoroutineKind::Coroutine(mov) => mov,
20622062
}
20632063
}
2064-
}
20652064

2066-
impl CoroutineKind {
20672065
pub fn is_fn_like(self) -> bool {
20682066
matches!(self, CoroutineKind::Desugared(_, CoroutineSource::Fn))
20692067
}
2068+
2069+
pub fn to_plural_string(&self) -> String {
2070+
match self {
2071+
CoroutineKind::Desugared(d, CoroutineSource::Fn) => format!("{d:#}fn bodies"),
2072+
CoroutineKind::Desugared(d, CoroutineSource::Block) => format!("{d:#}blocks"),
2073+
CoroutineKind::Desugared(d, CoroutineSource::Closure) => format!("{d:#}closure bodies"),
2074+
CoroutineKind::Coroutine(_) => "coroutines".to_string(),
2075+
}
2076+
}
20702077
}
20712078

20722079
impl fmt::Display for CoroutineKind {

compiler/rustc_hir_typeck/src/closure.rs

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -204,14 +204,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
204204
)
205205
}
206206
hir::ClosureKind::CoroutineClosure(kind) => {
207-
// async closures always return the type ascribed after the `->` (if present),
208-
// and yield `()`.
209207
let (bound_return_ty, bound_yield_ty) = match kind {
208+
hir::CoroutineDesugaring::Gen => {
209+
// `iter!` closures always return unit and yield the `Iterator::Item` type
210+
// that we have to infer.
211+
(tcx.types.unit, self.infcx.next_ty_var(expr_span))
212+
}
210213
hir::CoroutineDesugaring::Async => {
214+
// async closures always return the type ascribed after the `->` (if present),
215+
// and yield `()`.
211216
(bound_sig.skip_binder().output(), tcx.types.unit)
212217
}
213-
hir::CoroutineDesugaring::Gen | hir::CoroutineDesugaring::AsyncGen => {
214-
todo!("`gen` and `async gen` closures not supported yet")
218+
hir::CoroutineDesugaring::AsyncGen => {
219+
todo!("`async gen` closures not supported yet")
215220
}
216221
};
217222
// Compute all of the variables that will be used to populate the coroutine.
@@ -465,7 +470,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
465470

466471
if let Some(trait_def_id) = trait_def_id {
467472
let found_kind = match closure_kind {
468-
hir::ClosureKind::Closure => self.tcx.fn_trait_kind_from_def_id(trait_def_id),
473+
hir::ClosureKind::Closure
474+
// FIXME(iter_macro): Someday we'll probably want iterator closures instead of
475+
// just using Fn* for iterators.
476+
| hir::ClosureKind::CoroutineClosure(hir::CoroutineDesugaring::Gen) => {
477+
self.tcx.fn_trait_kind_from_def_id(trait_def_id)
478+
}
469479
hir::ClosureKind::CoroutineClosure(hir::CoroutineDesugaring::Async) => self
470480
.tcx
471481
.async_fn_trait_kind_from_def_id(trait_def_id)

compiler/rustc_parse/src/parser/stmt.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -713,7 +713,7 @@ impl<'a> Parser<'a> {
713713

714714
/// Parses the rest of a block expression or function body.
715715
/// Precondition: already parsed the '{'.
716-
pub(crate) fn parse_block_tail(
716+
pub fn parse_block_tail(
717717
&mut self,
718718
lo: Span,
719719
s: BlockCheckMode,

compiler/rustc_trait_selection/messages.ftl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,8 +72,6 @@ trait_selection_adjust_signature_remove_borrow = consider adjusting the signatur
7272
7373
trait_selection_ascribe_user_type_prove_predicate = ...so that the where clause holds
7474
75-
trait_selection_async_closure_not_fn = async closure does not implement `{$kind}` because it captures state from its environment
76-
7775
trait_selection_await_both_futures = consider `await`ing on both `Future`s
7876
trait_selection_await_future = consider `await`ing on the `Future`
7977
trait_selection_await_note = calling an async function returns a future
@@ -123,6 +121,8 @@ trait_selection_closure_kind_requirement = the requirement to implement `{$trait
123121
124122
trait_selection_compare_impl_item_obligation = ...so that the definition in impl matches the definition from the trait
125123
trait_selection_consider_specifying_length = consider specifying the actual array length
124+
trait_selection_coro_closure_not_fn = {$coro_kind}closure does not implement `{$kind}` because it captures state from its environment
125+
126126
trait_selection_data_flows = ...but data{$label_var1_exists ->
127127
[true] {" "}from `{$label_var1}`
128128
*[false] {""}

compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,7 @@ use super::{
4242
use crate::error_reporting::TypeErrCtxt;
4343
use crate::error_reporting::infer::TyCategory;
4444
use crate::error_reporting::traits::report_dyn_incompatibility;
45-
use crate::errors::{
46-
AsyncClosureNotFn, ClosureFnMutLabel, ClosureFnOnceLabel, ClosureKindMismatch,
47-
};
45+
use crate::errors::{ClosureFnMutLabel, ClosureFnOnceLabel, ClosureKindMismatch, CoroClosureNotFn};
4846
use crate::infer::{self, InferCtxt, InferCtxtExt as _};
4947
use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
5048
use crate::traits::{
@@ -886,9 +884,18 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
886884
// is unimplemented is because async closures don't implement `Fn`/`FnMut`
887885
// if they have captures.
888886
if has_self_borrows && expected_kind != ty::ClosureKind::FnOnce {
889-
let mut err = self.dcx().create_err(AsyncClosureNotFn {
887+
let coro_kind = match self
888+
.tcx
889+
.coroutine_kind(self.tcx.coroutine_for_closure(closure_def_id))
890+
.unwrap()
891+
{
892+
rustc_hir::CoroutineKind::Desugared(desugaring, _) => desugaring.to_string(),
893+
coro => coro.to_string(),
894+
};
895+
let mut err = self.dcx().create_err(CoroClosureNotFn {
890896
span: self.tcx.def_span(closure_def_id),
891897
kind: expected_kind.as_str(),
898+
coro_kind,
892899
});
893900
self.note_obligation_cause(&mut err, &obligation);
894901
return Some(err.emit());

compiler/rustc_trait_selection/src/errors.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -201,11 +201,12 @@ pub struct ClosureFnMutLabel {
201201
}
202202

203203
#[derive(Diagnostic)]
204-
#[diag(trait_selection_async_closure_not_fn)]
205-
pub(crate) struct AsyncClosureNotFn {
204+
#[diag(trait_selection_coro_closure_not_fn)]
205+
pub(crate) struct CoroClosureNotFn {
206206
#[primary_span]
207207
pub span: Span,
208208
pub kind: &'static str,
209+
pub coro_kind: String,
209210
}
210211

211212
#[derive(Diagnostic)]

compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use std::ops::ControlFlow;
1111
use hir::LangItem;
1212
use hir::def_id::DefId;
1313
use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
14-
use rustc_hir as hir;
14+
use rustc_hir::{self as hir, CoroutineDesugaring, CoroutineKind};
1515
use rustc_infer::traits::{Obligation, PolyTraitObligation, SelectionError};
1616
use rustc_middle::ty::fast_reject::DeepRejectCtxt;
1717
use rustc_middle::ty::{self, Ty, TypeVisitableExt, TypingMode, elaborate};
@@ -438,6 +438,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
438438
}
439439
}
440440

441+
#[instrument(level = "debug", skip(self, candidates))]
441442
fn assemble_async_closure_candidates(
442443
&mut self,
443444
obligation: &PolyTraitObligation<'tcx>,
@@ -446,15 +447,30 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
446447
let goal_kind =
447448
self.tcx().async_fn_trait_kind_from_def_id(obligation.predicate.def_id()).unwrap();
448449

450+
debug!("self_ty = {:?}", obligation.self_ty().skip_binder().kind());
449451
match *obligation.self_ty().skip_binder().kind() {
450-
ty::CoroutineClosure(_, args) => {
452+
ty::CoroutineClosure(def_id, args) => {
451453
if let Some(closure_kind) =
452454
args.as_coroutine_closure().kind_ty().to_opt_closure_kind()
453455
&& !closure_kind.extends(goal_kind)
454456
{
455457
return;
456458
}
457-
candidates.vec.push(AsyncClosureCandidate);
459+
460+
// Make sure this is actually an async closure.
461+
let Some(coroutine_kind) =
462+
self.tcx().coroutine_kind(self.tcx().coroutine_for_closure(def_id))
463+
else {
464+
bug!("coroutine with no kind");
465+
};
466+
467+
debug!(?coroutine_kind);
468+
match coroutine_kind {
469+
CoroutineKind::Desugared(CoroutineDesugaring::Async, _) => {
470+
candidates.vec.push(AsyncClosureCandidate);
471+
}
472+
_ => (),
473+
}
458474
}
459475
// Closures and fn pointers implement `AsyncFn*` if their return types
460476
// implement `Future`, which is checked later.

library/core/src/iter/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -420,6 +420,8 @@ pub use self::adapters::{Intersperse, IntersperseWith};
420420
issue = "42168"
421421
)]
422422
pub use self::range::Step;
423+
#[unstable(feature = "iter_macro", issue = "none", reason = "generators are unstable")]
424+
pub use self::sources::iter;
423425
#[stable(feature = "iter_empty", since = "1.2.0")]
424426
pub use self::sources::{Empty, empty};
425427
#[unstable(

library/core/src/iter/sources.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
mod empty;
22
mod from_coroutine;
33
mod from_fn;
4+
mod generator;
45
mod once;
56
mod once_with;
67
mod repeat;
@@ -18,6 +19,8 @@ pub use self::empty::{Empty, empty};
1819
pub use self::from_coroutine::{FromCoroutine, from_coroutine};
1920
#[stable(feature = "iter_from_fn", since = "1.34.0")]
2021
pub use self::from_fn::{FromFn, from_fn};
22+
#[unstable(feature = "iter_macro", issue = "none", reason = "generators are unstable")]
23+
pub use self::generator::iter;
2124
#[stable(feature = "iter_once", since = "1.2.0")]
2225
pub use self::once::{Once, once};
2326
#[stable(feature = "iter_once_with", since = "1.43.0")]

0 commit comments

Comments
 (0)