Skip to content

Commit fde341a

Browse files
authored
Rollup merge of #61941 - cramertj:no-more-yield-errors, r=centril
Preserve generator and yield source for error messages Previously, error messages after HIR lowering all referred to generators and yield, regardless of whether the original source was a generator or an async/await body. This change tracks the kind of each generator and yield source in order to provide appropriately tailored error messages. Fixes #60615.
2 parents 9b7b47c + d67db00 commit fde341a

File tree

18 files changed

+222
-129
lines changed

18 files changed

+222
-129
lines changed

src/librustc/cfg/construct.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -330,7 +330,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
330330
hir::ExprKind::DropTemps(ref e) |
331331
hir::ExprKind::Unary(_, ref e) |
332332
hir::ExprKind::Field(ref e, _) |
333-
hir::ExprKind::Yield(ref e) |
333+
hir::ExprKind::Yield(ref e, _) |
334334
hir::ExprKind::Repeat(ref e, _) => {
335335
self.straightline(expr, pred, Some(&**e).into_iter())
336336
}

src/librustc/hir/intravisit.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1089,7 +1089,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) {
10891089
visitor.visit_expr(expr)
10901090
}
10911091
}
1092-
ExprKind::Yield(ref subexpression) => {
1092+
ExprKind::Yield(ref subexpression, _) => {
10931093
visitor.visit_expr(subexpression);
10941094
}
10951095
ExprKind::Lit(_) | ExprKind::Err => {}

src/librustc/hir/lowering.rs

+87-61
Original file line numberDiff line numberDiff line change
@@ -95,8 +95,7 @@ pub struct LoweringContext<'a> {
9595

9696
modules: BTreeMap<NodeId, hir::ModuleItems>,
9797

98-
is_generator: bool,
99-
is_async_body: bool,
98+
generator_kind: Option<hir::GeneratorKind>,
10099

101100
/// Used to get the current `fn`'s def span to point to when using `await`
102101
/// outside of an `async fn`.
@@ -264,8 +263,7 @@ pub fn lower_crate(
264263
current_hir_id_owner: vec![(CRATE_DEF_INDEX, 0)],
265264
item_local_id_counters: Default::default(),
266265
node_id_to_hir_id: IndexVec::new(),
267-
is_generator: false,
268-
is_async_body: false,
266+
generator_kind: None,
269267
current_item: None,
270268
lifetimes_to_define: Vec::new(),
271269
is_collecting_in_band_lifetimes: false,
@@ -795,18 +793,49 @@ impl<'a> LoweringContext<'a> {
795793
})
796794
}
797795

798-
fn record_body(&mut self, arguments: HirVec<hir::Arg>, value: hir::Expr) -> hir::BodyId {
799-
if self.is_generator && self.is_async_body {
800-
span_err!(
801-
self.sess,
802-
value.span,
803-
E0727,
804-
"`async` generators are not yet supported",
805-
);
806-
self.sess.abort_if_errors();
796+
fn generator_movability_for_fn(
797+
&mut self,
798+
decl: &ast::FnDecl,
799+
fn_decl_span: Span,
800+
generator_kind: Option<hir::GeneratorKind>,
801+
movability: Movability,
802+
) -> Option<hir::GeneratorMovability> {
803+
match generator_kind {
804+
Some(hir::GeneratorKind::Gen) => {
805+
if !decl.inputs.is_empty() {
806+
span_err!(
807+
self.sess,
808+
fn_decl_span,
809+
E0628,
810+
"generators cannot have explicit arguments"
811+
);
812+
self.sess.abort_if_errors();
813+
}
814+
Some(match movability {
815+
Movability::Movable => hir::GeneratorMovability::Movable,
816+
Movability::Static => hir::GeneratorMovability::Static,
817+
})
818+
},
819+
Some(hir::GeneratorKind::Async) => {
820+
bug!("non-`async` closure body turned `async` during lowering");
821+
},
822+
None => {
823+
if movability == Movability::Static {
824+
span_err!(
825+
self.sess,
826+
fn_decl_span,
827+
E0697,
828+
"closures cannot be static"
829+
);
830+
}
831+
None
832+
},
807833
}
834+
}
835+
836+
fn record_body(&mut self, arguments: HirVec<hir::Arg>, value: hir::Expr) -> hir::BodyId {
808837
let body = hir::Body {
809-
is_generator: self.is_generator || self.is_async_body,
838+
generator_kind: self.generator_kind,
810839
arguments,
811840
value,
812841
};
@@ -1143,7 +1172,7 @@ impl<'a> LoweringContext<'a> {
11431172
};
11441173
let decl = self.lower_fn_decl(&ast_decl, None, /* impl trait allowed */ false, None);
11451174
let body_id = self.lower_fn_body(&ast_decl, |this| {
1146-
this.is_async_body = true;
1175+
this.generator_kind = Some(hir::GeneratorKind::Async);
11471176
body(this)
11481177
});
11491178
let generator = hir::Expr {
@@ -1168,12 +1197,10 @@ impl<'a> LoweringContext<'a> {
11681197
&mut self,
11691198
f: impl FnOnce(&mut LoweringContext<'_>) -> (HirVec<hir::Arg>, hir::Expr),
11701199
) -> hir::BodyId {
1171-
let prev_is_generator = mem::replace(&mut self.is_generator, false);
1172-
let prev_is_async_body = mem::replace(&mut self.is_async_body, false);
1200+
let prev_gen_kind = self.generator_kind.take();
11731201
let (arguments, result) = f(self);
11741202
let body_id = self.record_body(arguments, result);
1175-
self.is_generator = prev_is_generator;
1176-
self.is_async_body = prev_is_async_body;
1203+
self.generator_kind = prev_gen_kind;
11771204
body_id
11781205
}
11791206

@@ -4476,37 +4503,18 @@ impl<'a> LoweringContext<'a> {
44764503

44774504
self.with_new_scopes(|this| {
44784505
this.current_item = Some(fn_decl_span);
4479-
let mut is_generator = false;
4506+
let mut generator_kind = None;
44804507
let body_id = this.lower_fn_body(decl, |this| {
44814508
let e = this.lower_expr(body);
4482-
is_generator = this.is_generator;
4509+
generator_kind = this.generator_kind;
44834510
e
44844511
});
4485-
let generator_option = if is_generator {
4486-
if !decl.inputs.is_empty() {
4487-
span_err!(
4488-
this.sess,
4489-
fn_decl_span,
4490-
E0628,
4491-
"generators cannot have explicit arguments"
4492-
);
4493-
this.sess.abort_if_errors();
4494-
}
4495-
Some(match movability {
4496-
Movability::Movable => hir::GeneratorMovability::Movable,
4497-
Movability::Static => hir::GeneratorMovability::Static,
4498-
})
4499-
} else {
4500-
if movability == Movability::Static {
4501-
span_err!(
4502-
this.sess,
4503-
fn_decl_span,
4504-
E0697,
4505-
"closures cannot be static"
4506-
);
4507-
}
4508-
None
4509-
};
4512+
let generator_option = this.generator_movability_for_fn(
4513+
&decl,
4514+
fn_decl_span,
4515+
generator_kind,
4516+
movability,
4517+
);
45104518
hir::ExprKind::Closure(
45114519
this.lower_capture_clause(capture_clause),
45124520
fn_decl,
@@ -4678,12 +4686,26 @@ impl<'a> LoweringContext<'a> {
46784686
}
46794687

46804688
ExprKind::Yield(ref opt_expr) => {
4681-
self.is_generator = true;
4689+
match self.generator_kind {
4690+
Some(hir::GeneratorKind::Gen) => {},
4691+
Some(hir::GeneratorKind::Async) => {
4692+
span_err!(
4693+
self.sess,
4694+
e.span,
4695+
E0727,
4696+
"`async` generators are not yet supported",
4697+
);
4698+
self.sess.abort_if_errors();
4699+
},
4700+
None => {
4701+
self.generator_kind = Some(hir::GeneratorKind::Gen);
4702+
}
4703+
}
46824704
let expr = opt_expr
46834705
.as_ref()
46844706
.map(|x| self.lower_expr(x))
46854707
.unwrap_or_else(|| self.expr_unit(e.span));
4686-
hir::ExprKind::Yield(P(expr))
4708+
hir::ExprKind::Yield(P(expr), hir::YieldSource::Yield)
46874709
}
46884710

46894711
ExprKind::Err => hir::ExprKind::Err,
@@ -5755,19 +5777,23 @@ impl<'a> LoweringContext<'a> {
57555777
// yield ();
57565778
// }
57575779
// }
5758-
if !self.is_async_body {
5759-
let mut err = struct_span_err!(
5760-
self.sess,
5761-
await_span,
5762-
E0728,
5763-
"`await` is only allowed inside `async` functions and blocks"
5764-
);
5765-
err.span_label(await_span, "only allowed inside `async` functions and blocks");
5766-
if let Some(item_sp) = self.current_item {
5767-
err.span_label(item_sp, "this is not `async`");
5780+
match self.generator_kind {
5781+
Some(hir::GeneratorKind::Async) => {},
5782+
Some(hir::GeneratorKind::Gen) |
5783+
None => {
5784+
let mut err = struct_span_err!(
5785+
self.sess,
5786+
await_span,
5787+
E0728,
5788+
"`await` is only allowed inside `async` functions and blocks"
5789+
);
5790+
err.span_label(await_span, "only allowed inside `async` functions and blocks");
5791+
if let Some(item_sp) = self.current_item {
5792+
err.span_label(item_sp, "this is not `async`");
5793+
}
5794+
err.emit();
5795+
return hir::ExprKind::Err;
57685796
}
5769-
err.emit();
5770-
return hir::ExprKind::Err;
57715797
}
57725798
let span = self.mark_span_with_reason(
57735799
CompilerDesugaringKind::Await,
@@ -5865,7 +5891,7 @@ impl<'a> LoweringContext<'a> {
58655891
let unit = self.expr_unit(span);
58665892
let yield_expr = P(self.expr(
58675893
span,
5868-
hir::ExprKind::Yield(P(unit)),
5894+
hir::ExprKind::Yield(P(unit), hir::YieldSource::Await),
58695895
ThinVec::new(),
58705896
));
58715897
self.stmt(span, hir::StmtKind::Expr(yield_expr))

src/librustc/hir/mod.rs

+56-16
Original file line numberDiff line numberDiff line change
@@ -1306,15 +1306,15 @@ pub struct BodyId {
13061306
///
13071307
/// - an `arguments` array containing the `(x, y)` pattern
13081308
/// - a `value` containing the `x + y` expression (maybe wrapped in a block)
1309-
/// - `is_generator` would be false
1309+
/// - `generator_kind` would be `None`
13101310
///
13111311
/// All bodies have an **owner**, which can be accessed via the HIR
13121312
/// map using `body_owner_def_id()`.
13131313
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
13141314
pub struct Body {
13151315
pub arguments: HirVec<Arg>,
13161316
pub value: Expr,
1317-
pub is_generator: bool,
1317+
pub generator_kind: Option<GeneratorKind>,
13181318
}
13191319

13201320
impl Body {
@@ -1325,6 +1325,26 @@ impl Body {
13251325
}
13261326
}
13271327

1328+
/// The type of source expression that caused this generator to be created.
1329+
// Not `IsAsync` because we want to eventually add support for `AsyncGen`
1330+
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, HashStable,
1331+
RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
1332+
pub enum GeneratorKind {
1333+
/// An `async` block or function.
1334+
Async,
1335+
/// A generator literal created via a `yield` inside a closure.
1336+
Gen,
1337+
}
1338+
1339+
impl fmt::Display for GeneratorKind {
1340+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1341+
f.write_str(match self {
1342+
GeneratorKind::Async => "`async` object",
1343+
GeneratorKind::Gen => "generator",
1344+
})
1345+
}
1346+
}
1347+
13281348
#[derive(Copy, Clone, Debug)]
13291349
pub enum BodyOwnerKind {
13301350
/// Functions and methods.
@@ -1531,8 +1551,8 @@ pub enum ExprKind {
15311551
///
15321552
/// The final span is the span of the argument block `|...|`.
15331553
///
1534-
/// This may also be a generator literal, indicated by the final boolean,
1535-
/// in that case there is an `GeneratorClause`.
1554+
/// This may also be a generator literal or an `async block` as indicated by the
1555+
/// `Option<GeneratorMovability>`.
15361556
Closure(CaptureClause, P<FnDecl>, BodyId, Span, Option<GeneratorMovability>),
15371557
/// A block (e.g., `'label: { ... }`).
15381558
Block(P<Block>, Option<Label>),
@@ -1576,7 +1596,7 @@ pub enum ExprKind {
15761596
Repeat(P<Expr>, AnonConst),
15771597

15781598
/// A suspension point for generators (i.e., `yield <expr>`).
1579-
Yield(P<Expr>),
1599+
Yield(P<Expr>, YieldSource),
15801600

15811601
/// A placeholder for an expression that wasn't syntactically well formed in some way.
15821602
Err,
@@ -1668,12 +1688,12 @@ pub enum LoopIdError {
16681688

16691689
impl fmt::Display for LoopIdError {
16701690
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1671-
fmt::Display::fmt(match *self {
1691+
f.write_str(match self {
16721692
LoopIdError::OutsideLoopScope => "not inside loop scope",
16731693
LoopIdError::UnlabeledCfInWhileCondition =>
16741694
"unlabeled control flow (break or continue) in while condition",
16751695
LoopIdError::UnresolvedLabel => "label not found",
1676-
}, f)
1696+
})
16771697
}
16781698
}
16791699

@@ -1687,13 +1707,34 @@ pub struct Destination {
16871707
pub target_id: Result<HirId, LoopIdError>,
16881708
}
16891709

1710+
/// Whether a generator contains self-references, causing it to be `!Unpin`.
16901711
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, HashStable,
16911712
RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
16921713
pub enum GeneratorMovability {
1714+
/// May contain self-references, `!Unpin`.
16931715
Static,
1716+
/// Must not contain self-references, `Unpin`.
16941717
Movable,
16951718
}
16961719

1720+
/// The yield kind that caused an `ExprKind::Yield`.
1721+
#[derive(Debug, Copy, Clone, RustcEncodable, RustcDecodable, HashStable)]
1722+
pub enum YieldSource {
1723+
/// An `<expr>.await`.
1724+
Await,
1725+
/// A plain `yield`.
1726+
Yield,
1727+
}
1728+
1729+
impl fmt::Display for YieldSource {
1730+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1731+
f.write_str(match self {
1732+
YieldSource::Await => "`await`",
1733+
YieldSource::Yield => "`yield`",
1734+
})
1735+
}
1736+
}
1737+
16971738
#[derive(Clone, RustcEncodable, RustcDecodable, Debug, Copy, HashStable)]
16981739
pub enum CaptureClause {
16991740
CaptureByValue,
@@ -2058,11 +2099,10 @@ impl Defaultness {
20582099

20592100
impl fmt::Display for Unsafety {
20602101
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2061-
fmt::Display::fmt(match *self {
2062-
Unsafety::Normal => "normal",
2063-
Unsafety::Unsafe => "unsafe",
2064-
},
2065-
f)
2102+
f.write_str(match self {
2103+
Unsafety::Normal => "normal",
2104+
Unsafety::Unsafe => "unsafe",
2105+
})
20662106
}
20672107
}
20682108

@@ -2076,10 +2116,10 @@ pub enum ImplPolarity {
20762116

20772117
impl fmt::Debug for ImplPolarity {
20782118
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2079-
match *self {
2080-
ImplPolarity::Positive => "positive".fmt(f),
2081-
ImplPolarity::Negative => "negative".fmt(f),
2082-
}
2119+
f.write_str(match self {
2120+
ImplPolarity::Positive => "positive",
2121+
ImplPolarity::Negative => "negative",
2122+
})
20832123
}
20842124
}
20852125

src/librustc/hir/print.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1501,7 +1501,7 @@ impl<'a> State<'a> {
15011501

15021502
self.pclose()?;
15031503
}
1504-
hir::ExprKind::Yield(ref expr) => {
1504+
hir::ExprKind::Yield(ref expr, _) => {
15051505
self.word_space("yield")?;
15061506
self.print_expr_maybe_paren(&expr, parser::PREC_JUMP)?;
15071507
}

0 commit comments

Comments
 (0)