Skip to content

Commit d67db00

Browse files
committed
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.
1 parent b01a257 commit d67db00

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`.
@@ -261,8 +260,7 @@ pub fn lower_crate(
261260
current_hir_id_owner: vec![(CRATE_DEF_INDEX, 0)],
262261
item_local_id_counters: Default::default(),
263262
node_id_to_hir_id: IndexVec::new(),
264-
is_generator: false,
265-
is_async_body: false,
263+
generator_kind: None,
266264
current_item: None,
267265
lifetimes_to_define: Vec::new(),
268266
is_collecting_in_band_lifetimes: false,
@@ -790,18 +788,49 @@ impl<'a> LoweringContext<'a> {
790788
})
791789
}
792790

793-
fn record_body(&mut self, arguments: HirVec<hir::Arg>, value: hir::Expr) -> hir::BodyId {
794-
if self.is_generator && self.is_async_body {
795-
span_err!(
796-
self.sess,
797-
value.span,
798-
E0727,
799-
"`async` generators are not yet supported",
800-
);
801-
self.sess.abort_if_errors();
791+
fn generator_movability_for_fn(
792+
&mut self,
793+
decl: &ast::FnDecl,
794+
fn_decl_span: Span,
795+
generator_kind: Option<hir::GeneratorKind>,
796+
movability: Movability,
797+
) -> Option<hir::GeneratorMovability> {
798+
match generator_kind {
799+
Some(hir::GeneratorKind::Gen) => {
800+
if !decl.inputs.is_empty() {
801+
span_err!(
802+
self.sess,
803+
fn_decl_span,
804+
E0628,
805+
"generators cannot have explicit arguments"
806+
);
807+
self.sess.abort_if_errors();
808+
}
809+
Some(match movability {
810+
Movability::Movable => hir::GeneratorMovability::Movable,
811+
Movability::Static => hir::GeneratorMovability::Static,
812+
})
813+
},
814+
Some(hir::GeneratorKind::Async) => {
815+
bug!("non-`async` closure body turned `async` during lowering");
816+
},
817+
None => {
818+
if movability == Movability::Static {
819+
span_err!(
820+
self.sess,
821+
fn_decl_span,
822+
E0697,
823+
"closures cannot be static"
824+
);
825+
}
826+
None
827+
},
802828
}
829+
}
830+
831+
fn record_body(&mut self, arguments: HirVec<hir::Arg>, value: hir::Expr) -> hir::BodyId {
803832
let body = hir::Body {
804-
is_generator: self.is_generator || self.is_async_body,
833+
generator_kind: self.generator_kind,
805834
arguments,
806835
value,
807836
};
@@ -1142,7 +1171,7 @@ impl<'a> LoweringContext<'a> {
11421171
};
11431172
let decl = self.lower_fn_decl(&ast_decl, None, /* impl trait allowed */ false, None);
11441173
let body_id = self.lower_fn_body(&ast_decl, |this| {
1145-
this.is_async_body = true;
1174+
this.generator_kind = Some(hir::GeneratorKind::Async);
11461175
body(this)
11471176
});
11481177
let generator = hir::Expr {
@@ -1167,12 +1196,10 @@ impl<'a> LoweringContext<'a> {
11671196
&mut self,
11681197
f: impl FnOnce(&mut LoweringContext<'_>) -> (HirVec<hir::Arg>, hir::Expr),
11691198
) -> hir::BodyId {
1170-
let prev_is_generator = mem::replace(&mut self.is_generator, false);
1171-
let prev_is_async_body = mem::replace(&mut self.is_async_body, false);
1199+
let prev_gen_kind = self.generator_kind.take();
11721200
let (arguments, result) = f(self);
11731201
let body_id = self.record_body(arguments, result);
1174-
self.is_generator = prev_is_generator;
1175-
self.is_async_body = prev_is_async_body;
1202+
self.generator_kind = prev_gen_kind;
11761203
body_id
11771204
}
11781205

@@ -4475,37 +4502,18 @@ impl<'a> LoweringContext<'a> {
44754502

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

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

46884710
ExprKind::Err => hir::ExprKind::Err,
@@ -5754,19 +5776,23 @@ impl<'a> LoweringContext<'a> {
57545776
// yield ();
57555777
// }
57565778
// }
5757-
if !self.is_async_body {
5758-
let mut err = struct_span_err!(
5759-
self.sess,
5760-
await_span,
5761-
E0728,
5762-
"`await` is only allowed inside `async` functions and blocks"
5763-
);
5764-
err.span_label(await_span, "only allowed inside `async` functions and blocks");
5765-
if let Some(item_sp) = self.current_item {
5766-
err.span_label(item_sp, "this is not `async`");
5779+
match self.generator_kind {
5780+
Some(hir::GeneratorKind::Async) => {},
5781+
Some(hir::GeneratorKind::Gen) |
5782+
None => {
5783+
let mut err = struct_span_err!(
5784+
self.sess,
5785+
await_span,
5786+
E0728,
5787+
"`await` is only allowed inside `async` functions and blocks"
5788+
);
5789+
err.span_label(await_span, "only allowed inside `async` functions and blocks");
5790+
if let Some(item_sp) = self.current_item {
5791+
err.span_label(item_sp, "this is not `async`");
5792+
}
5793+
err.emit();
5794+
return hir::ExprKind::Err;
57675795
}
5768-
err.emit();
5769-
return hir::ExprKind::Err;
57705796
}
57715797
let span = self.mark_span_with_reason(
57725798
CompilerDesugaringKind::Await,
@@ -5864,7 +5890,7 @@ impl<'a> LoweringContext<'a> {
58645890
let unit = self.expr_unit(span);
58655891
let yield_expr = P(self.expr(
58665892
span,
5867-
hir::ExprKind::Yield(P(unit)),
5893+
hir::ExprKind::Yield(P(unit), hir::YieldSource::Await),
58685894
ThinVec::new(),
58695895
));
58705896
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)