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.
This commit is contained in:
commit
fde341a4ef
18 changed files with 221 additions and 128 deletions
|
|
@ -330,7 +330,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
|
|||
hir::ExprKind::DropTemps(ref e) |
|
||||
hir::ExprKind::Unary(_, ref e) |
|
||||
hir::ExprKind::Field(ref e, _) |
|
||||
hir::ExprKind::Yield(ref e) |
|
||||
hir::ExprKind::Yield(ref e, _) |
|
||||
hir::ExprKind::Repeat(ref e, _) => {
|
||||
self.straightline(expr, pred, Some(&**e).into_iter())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1089,7 +1089,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) {
|
|||
visitor.visit_expr(expr)
|
||||
}
|
||||
}
|
||||
ExprKind::Yield(ref subexpression) => {
|
||||
ExprKind::Yield(ref subexpression, _) => {
|
||||
visitor.visit_expr(subexpression);
|
||||
}
|
||||
ExprKind::Lit(_) | ExprKind::Err => {}
|
||||
|
|
|
|||
|
|
@ -95,8 +95,7 @@ pub struct LoweringContext<'a> {
|
|||
|
||||
modules: BTreeMap<NodeId, hir::ModuleItems>,
|
||||
|
||||
is_generator: bool,
|
||||
is_async_body: bool,
|
||||
generator_kind: Option<hir::GeneratorKind>,
|
||||
|
||||
/// Used to get the current `fn`'s def span to point to when using `await`
|
||||
/// outside of an `async fn`.
|
||||
|
|
@ -264,8 +263,7 @@ pub fn lower_crate(
|
|||
current_hir_id_owner: vec![(CRATE_DEF_INDEX, 0)],
|
||||
item_local_id_counters: Default::default(),
|
||||
node_id_to_hir_id: IndexVec::new(),
|
||||
is_generator: false,
|
||||
is_async_body: false,
|
||||
generator_kind: None,
|
||||
current_item: None,
|
||||
lifetimes_to_define: Vec::new(),
|
||||
is_collecting_in_band_lifetimes: false,
|
||||
|
|
@ -795,18 +793,49 @@ impl<'a> LoweringContext<'a> {
|
|||
})
|
||||
}
|
||||
|
||||
fn record_body(&mut self, arguments: HirVec<hir::Arg>, value: hir::Expr) -> hir::BodyId {
|
||||
if self.is_generator && self.is_async_body {
|
||||
span_err!(
|
||||
self.sess,
|
||||
value.span,
|
||||
E0727,
|
||||
"`async` generators are not yet supported",
|
||||
);
|
||||
self.sess.abort_if_errors();
|
||||
fn generator_movability_for_fn(
|
||||
&mut self,
|
||||
decl: &ast::FnDecl,
|
||||
fn_decl_span: Span,
|
||||
generator_kind: Option<hir::GeneratorKind>,
|
||||
movability: Movability,
|
||||
) -> Option<hir::GeneratorMovability> {
|
||||
match generator_kind {
|
||||
Some(hir::GeneratorKind::Gen) => {
|
||||
if !decl.inputs.is_empty() {
|
||||
span_err!(
|
||||
self.sess,
|
||||
fn_decl_span,
|
||||
E0628,
|
||||
"generators cannot have explicit arguments"
|
||||
);
|
||||
self.sess.abort_if_errors();
|
||||
}
|
||||
Some(match movability {
|
||||
Movability::Movable => hir::GeneratorMovability::Movable,
|
||||
Movability::Static => hir::GeneratorMovability::Static,
|
||||
})
|
||||
},
|
||||
Some(hir::GeneratorKind::Async) => {
|
||||
bug!("non-`async` closure body turned `async` during lowering");
|
||||
},
|
||||
None => {
|
||||
if movability == Movability::Static {
|
||||
span_err!(
|
||||
self.sess,
|
||||
fn_decl_span,
|
||||
E0697,
|
||||
"closures cannot be static"
|
||||
);
|
||||
}
|
||||
None
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn record_body(&mut self, arguments: HirVec<hir::Arg>, value: hir::Expr) -> hir::BodyId {
|
||||
let body = hir::Body {
|
||||
is_generator: self.is_generator || self.is_async_body,
|
||||
generator_kind: self.generator_kind,
|
||||
arguments,
|
||||
value,
|
||||
};
|
||||
|
|
@ -1143,7 +1172,7 @@ impl<'a> LoweringContext<'a> {
|
|||
};
|
||||
let decl = self.lower_fn_decl(&ast_decl, None, /* impl trait allowed */ false, None);
|
||||
let body_id = self.lower_fn_body(&ast_decl, |this| {
|
||||
this.is_async_body = true;
|
||||
this.generator_kind = Some(hir::GeneratorKind::Async);
|
||||
body(this)
|
||||
});
|
||||
let generator = hir::Expr {
|
||||
|
|
@ -1168,12 +1197,10 @@ impl<'a> LoweringContext<'a> {
|
|||
&mut self,
|
||||
f: impl FnOnce(&mut LoweringContext<'_>) -> (HirVec<hir::Arg>, hir::Expr),
|
||||
) -> hir::BodyId {
|
||||
let prev_is_generator = mem::replace(&mut self.is_generator, false);
|
||||
let prev_is_async_body = mem::replace(&mut self.is_async_body, false);
|
||||
let prev_gen_kind = self.generator_kind.take();
|
||||
let (arguments, result) = f(self);
|
||||
let body_id = self.record_body(arguments, result);
|
||||
self.is_generator = prev_is_generator;
|
||||
self.is_async_body = prev_is_async_body;
|
||||
self.generator_kind = prev_gen_kind;
|
||||
body_id
|
||||
}
|
||||
|
||||
|
|
@ -4476,37 +4503,18 @@ impl<'a> LoweringContext<'a> {
|
|||
|
||||
self.with_new_scopes(|this| {
|
||||
this.current_item = Some(fn_decl_span);
|
||||
let mut is_generator = false;
|
||||
let mut generator_kind = None;
|
||||
let body_id = this.lower_fn_body(decl, |this| {
|
||||
let e = this.lower_expr(body);
|
||||
is_generator = this.is_generator;
|
||||
generator_kind = this.generator_kind;
|
||||
e
|
||||
});
|
||||
let generator_option = if is_generator {
|
||||
if !decl.inputs.is_empty() {
|
||||
span_err!(
|
||||
this.sess,
|
||||
fn_decl_span,
|
||||
E0628,
|
||||
"generators cannot have explicit arguments"
|
||||
);
|
||||
this.sess.abort_if_errors();
|
||||
}
|
||||
Some(match movability {
|
||||
Movability::Movable => hir::GeneratorMovability::Movable,
|
||||
Movability::Static => hir::GeneratorMovability::Static,
|
||||
})
|
||||
} else {
|
||||
if movability == Movability::Static {
|
||||
span_err!(
|
||||
this.sess,
|
||||
fn_decl_span,
|
||||
E0697,
|
||||
"closures cannot be static"
|
||||
);
|
||||
}
|
||||
None
|
||||
};
|
||||
let generator_option = this.generator_movability_for_fn(
|
||||
&decl,
|
||||
fn_decl_span,
|
||||
generator_kind,
|
||||
movability,
|
||||
);
|
||||
hir::ExprKind::Closure(
|
||||
this.lower_capture_clause(capture_clause),
|
||||
fn_decl,
|
||||
|
|
@ -4678,12 +4686,26 @@ impl<'a> LoweringContext<'a> {
|
|||
}
|
||||
|
||||
ExprKind::Yield(ref opt_expr) => {
|
||||
self.is_generator = true;
|
||||
match self.generator_kind {
|
||||
Some(hir::GeneratorKind::Gen) => {},
|
||||
Some(hir::GeneratorKind::Async) => {
|
||||
span_err!(
|
||||
self.sess,
|
||||
e.span,
|
||||
E0727,
|
||||
"`async` generators are not yet supported",
|
||||
);
|
||||
self.sess.abort_if_errors();
|
||||
},
|
||||
None => {
|
||||
self.generator_kind = Some(hir::GeneratorKind::Gen);
|
||||
}
|
||||
}
|
||||
let expr = opt_expr
|
||||
.as_ref()
|
||||
.map(|x| self.lower_expr(x))
|
||||
.unwrap_or_else(|| self.expr_unit(e.span));
|
||||
hir::ExprKind::Yield(P(expr))
|
||||
hir::ExprKind::Yield(P(expr), hir::YieldSource::Yield)
|
||||
}
|
||||
|
||||
ExprKind::Err => hir::ExprKind::Err,
|
||||
|
|
@ -5755,19 +5777,23 @@ impl<'a> LoweringContext<'a> {
|
|||
// yield ();
|
||||
// }
|
||||
// }
|
||||
if !self.is_async_body {
|
||||
let mut err = struct_span_err!(
|
||||
self.sess,
|
||||
await_span,
|
||||
E0728,
|
||||
"`await` is only allowed inside `async` functions and blocks"
|
||||
);
|
||||
err.span_label(await_span, "only allowed inside `async` functions and blocks");
|
||||
if let Some(item_sp) = self.current_item {
|
||||
err.span_label(item_sp, "this is not `async`");
|
||||
match self.generator_kind {
|
||||
Some(hir::GeneratorKind::Async) => {},
|
||||
Some(hir::GeneratorKind::Gen) |
|
||||
None => {
|
||||
let mut err = struct_span_err!(
|
||||
self.sess,
|
||||
await_span,
|
||||
E0728,
|
||||
"`await` is only allowed inside `async` functions and blocks"
|
||||
);
|
||||
err.span_label(await_span, "only allowed inside `async` functions and blocks");
|
||||
if let Some(item_sp) = self.current_item {
|
||||
err.span_label(item_sp, "this is not `async`");
|
||||
}
|
||||
err.emit();
|
||||
return hir::ExprKind::Err;
|
||||
}
|
||||
err.emit();
|
||||
return hir::ExprKind::Err;
|
||||
}
|
||||
let span = self.mark_span_with_reason(
|
||||
CompilerDesugaringKind::Await,
|
||||
|
|
@ -5865,7 +5891,7 @@ impl<'a> LoweringContext<'a> {
|
|||
let unit = self.expr_unit(span);
|
||||
let yield_expr = P(self.expr(
|
||||
span,
|
||||
hir::ExprKind::Yield(P(unit)),
|
||||
hir::ExprKind::Yield(P(unit), hir::YieldSource::Await),
|
||||
ThinVec::new(),
|
||||
));
|
||||
self.stmt(span, hir::StmtKind::Expr(yield_expr))
|
||||
|
|
|
|||
|
|
@ -1306,7 +1306,7 @@ pub struct BodyId {
|
|||
///
|
||||
/// - an `arguments` array containing the `(x, y)` pattern
|
||||
/// - a `value` containing the `x + y` expression (maybe wrapped in a block)
|
||||
/// - `is_generator` would be false
|
||||
/// - `generator_kind` would be `None`
|
||||
///
|
||||
/// All bodies have an **owner**, which can be accessed via the HIR
|
||||
/// map using `body_owner_def_id()`.
|
||||
|
|
@ -1314,7 +1314,7 @@ pub struct BodyId {
|
|||
pub struct Body {
|
||||
pub arguments: HirVec<Arg>,
|
||||
pub value: Expr,
|
||||
pub is_generator: bool,
|
||||
pub generator_kind: Option<GeneratorKind>,
|
||||
}
|
||||
|
||||
impl Body {
|
||||
|
|
@ -1325,6 +1325,26 @@ impl Body {
|
|||
}
|
||||
}
|
||||
|
||||
/// The type of source expression that caused this generator to be created.
|
||||
// Not `IsAsync` because we want to eventually add support for `AsyncGen`
|
||||
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, HashStable,
|
||||
RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
|
||||
pub enum GeneratorKind {
|
||||
/// An `async` block or function.
|
||||
Async,
|
||||
/// A generator literal created via a `yield` inside a closure.
|
||||
Gen,
|
||||
}
|
||||
|
||||
impl fmt::Display for GeneratorKind {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.write_str(match self {
|
||||
GeneratorKind::Async => "`async` object",
|
||||
GeneratorKind::Gen => "generator",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub enum BodyOwnerKind {
|
||||
/// Functions and methods.
|
||||
|
|
@ -1531,8 +1551,8 @@ pub enum ExprKind {
|
|||
///
|
||||
/// The final span is the span of the argument block `|...|`.
|
||||
///
|
||||
/// This may also be a generator literal, indicated by the final boolean,
|
||||
/// in that case there is an `GeneratorClause`.
|
||||
/// This may also be a generator literal or an `async block` as indicated by the
|
||||
/// `Option<GeneratorMovability>`.
|
||||
Closure(CaptureClause, P<FnDecl>, BodyId, Span, Option<GeneratorMovability>),
|
||||
/// A block (e.g., `'label: { ... }`).
|
||||
Block(P<Block>, Option<Label>),
|
||||
|
|
@ -1576,7 +1596,7 @@ pub enum ExprKind {
|
|||
Repeat(P<Expr>, AnonConst),
|
||||
|
||||
/// A suspension point for generators (i.e., `yield <expr>`).
|
||||
Yield(P<Expr>),
|
||||
Yield(P<Expr>, YieldSource),
|
||||
|
||||
/// A placeholder for an expression that wasn't syntactically well formed in some way.
|
||||
Err,
|
||||
|
|
@ -1668,12 +1688,12 @@ pub enum LoopIdError {
|
|||
|
||||
impl fmt::Display for LoopIdError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
fmt::Display::fmt(match *self {
|
||||
f.write_str(match self {
|
||||
LoopIdError::OutsideLoopScope => "not inside loop scope",
|
||||
LoopIdError::UnlabeledCfInWhileCondition =>
|
||||
"unlabeled control flow (break or continue) in while condition",
|
||||
LoopIdError::UnresolvedLabel => "label not found",
|
||||
}, f)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1687,13 +1707,34 @@ pub struct Destination {
|
|||
pub target_id: Result<HirId, LoopIdError>,
|
||||
}
|
||||
|
||||
/// Whether a generator contains self-references, causing it to be `!Unpin`.
|
||||
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, HashStable,
|
||||
RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
|
||||
pub enum GeneratorMovability {
|
||||
/// May contain self-references, `!Unpin`.
|
||||
Static,
|
||||
/// Must not contain self-references, `Unpin`.
|
||||
Movable,
|
||||
}
|
||||
|
||||
/// The yield kind that caused an `ExprKind::Yield`.
|
||||
#[derive(Debug, Copy, Clone, RustcEncodable, RustcDecodable, HashStable)]
|
||||
pub enum YieldSource {
|
||||
/// An `<expr>.await`.
|
||||
Await,
|
||||
/// A plain `yield`.
|
||||
Yield,
|
||||
}
|
||||
|
||||
impl fmt::Display for YieldSource {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.write_str(match self {
|
||||
YieldSource::Await => "`await`",
|
||||
YieldSource::Yield => "`yield`",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, RustcEncodable, RustcDecodable, Debug, Copy, HashStable)]
|
||||
pub enum CaptureClause {
|
||||
CaptureByValue,
|
||||
|
|
@ -2058,11 +2099,10 @@ impl Defaultness {
|
|||
|
||||
impl fmt::Display for Unsafety {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
fmt::Display::fmt(match *self {
|
||||
Unsafety::Normal => "normal",
|
||||
Unsafety::Unsafe => "unsafe",
|
||||
},
|
||||
f)
|
||||
f.write_str(match self {
|
||||
Unsafety::Normal => "normal",
|
||||
Unsafety::Unsafe => "unsafe",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2076,10 +2116,10 @@ pub enum ImplPolarity {
|
|||
|
||||
impl fmt::Debug for ImplPolarity {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match *self {
|
||||
ImplPolarity::Positive => "positive".fmt(f),
|
||||
ImplPolarity::Negative => "negative".fmt(f),
|
||||
}
|
||||
f.write_str(match self {
|
||||
ImplPolarity::Positive => "positive",
|
||||
ImplPolarity::Negative => "negative",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1501,7 +1501,7 @@ impl<'a> State<'a> {
|
|||
|
||||
self.pclose()?;
|
||||
}
|
||||
hir::ExprKind::Yield(ref expr) => {
|
||||
hir::ExprKind::Yield(ref expr, _) => {
|
||||
self.word_space("yield")?;
|
||||
self.print_expr_maybe_paren(&expr, parser::PREC_JUMP)?;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -335,15 +335,15 @@ impl<'a> HashStable<StableHashingContext<'a>> for hir::Body {
|
|||
hcx: &mut StableHashingContext<'a>,
|
||||
hasher: &mut StableHasher<W>) {
|
||||
let hir::Body {
|
||||
ref arguments,
|
||||
ref value,
|
||||
is_generator,
|
||||
} = *self;
|
||||
arguments,
|
||||
value,
|
||||
generator_kind,
|
||||
} = self;
|
||||
|
||||
hcx.with_node_id_hashing_mode(NodeIdHashingMode::Ignore, |hcx| {
|
||||
arguments.hash_stable(hcx, hasher);
|
||||
value.hash_stable(hcx, hasher);
|
||||
is_generator.hash_stable(hcx, hasher);
|
||||
generator_kind.hash_stable(hcx, hasher);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -227,16 +227,15 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
|
||||
pub fn need_type_info_err_in_generator(
|
||||
&self,
|
||||
kind: hir::GeneratorKind,
|
||||
span: Span,
|
||||
ty: Ty<'tcx>,
|
||||
) -> DiagnosticBuilder<'tcx> {
|
||||
let ty = self.resolve_vars_if_possible(&ty);
|
||||
let name = self.extract_type_name(&ty, None);
|
||||
|
||||
let mut err = struct_span_err!(self.tcx.sess,
|
||||
span,
|
||||
E0698,
|
||||
"type inside generator must be known in this context");
|
||||
let mut err = struct_span_err!(
|
||||
self.tcx.sess, span, E0698, "type inside {} must be known in this context", kind,
|
||||
);
|
||||
err.span_label(span, InferCtxt::missing_type_msg(&name));
|
||||
err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -546,7 +546,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
|
|||
self.consume_expr(&base);
|
||||
}
|
||||
|
||||
hir::ExprKind::Yield(ref value) => {
|
||||
hir::ExprKind::Yield(ref value, _) => {
|
||||
self.consume_expr(&value);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1218,7 +1218,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
|
|||
hir::ExprKind::Type(ref e, _) |
|
||||
hir::ExprKind::DropTemps(ref e) |
|
||||
hir::ExprKind::Unary(_, ref e) |
|
||||
hir::ExprKind::Yield(ref e) |
|
||||
hir::ExprKind::Yield(ref e, _) |
|
||||
hir::ExprKind::Repeat(ref e, _) => {
|
||||
self.propagate_through_expr(&e, succ)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -331,7 +331,7 @@ pub struct ScopeTree {
|
|||
/// The reason is that semantically, until the `box` expression returns,
|
||||
/// the values are still owned by their containing expressions. So
|
||||
/// we'll see that `&x`.
|
||||
yield_in_scope: FxHashMap<Scope, (Span, usize)>,
|
||||
yield_in_scope: FxHashMap<Scope, YieldData>,
|
||||
|
||||
/// The number of visit_expr and visit_pat calls done in the body.
|
||||
/// Used to sanity check visit_expr/visit_pat call count when
|
||||
|
|
@ -339,6 +339,15 @@ pub struct ScopeTree {
|
|||
body_expr_count: FxHashMap<hir::BodyId, usize>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, RustcEncodable, RustcDecodable, HashStable)]
|
||||
pub struct YieldData {
|
||||
/// `Span` of the yield.
|
||||
pub span: Span,
|
||||
/// The number of expressions and patterns appearing before the `yield` in the body + 1.
|
||||
pub expr_and_pat_count: usize,
|
||||
pub source: hir::YieldSource,
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct Context {
|
||||
/// the root of the current region tree. This is typically the id
|
||||
|
|
@ -695,7 +704,7 @@ impl<'tcx> ScopeTree {
|
|||
/// returns `Some((span, expr_count))` with the span of a yield we found and
|
||||
/// the number of expressions and patterns appearing before the `yield` in the body + 1.
|
||||
/// If there a are multiple yields in a scope, the one with the highest number is returned.
|
||||
pub fn yield_in_scope(&self, scope: Scope) -> Option<(Span, usize)> {
|
||||
pub fn yield_in_scope(&self, scope: Scope) -> Option<YieldData> {
|
||||
self.yield_in_scope.get(&scope).cloned()
|
||||
}
|
||||
|
||||
|
|
@ -706,14 +715,14 @@ impl<'tcx> ScopeTree {
|
|||
scope: Scope,
|
||||
expr_hir_id: hir::HirId,
|
||||
body: &'tcx hir::Body) -> Option<Span> {
|
||||
self.yield_in_scope(scope).and_then(|(span, count)| {
|
||||
self.yield_in_scope(scope).and_then(|YieldData { span, expr_and_pat_count, .. }| {
|
||||
let mut visitor = ExprLocatorVisitor {
|
||||
hir_id: expr_hir_id,
|
||||
result: None,
|
||||
expr_and_pat_count: 0,
|
||||
};
|
||||
visitor.visit_body(body);
|
||||
if count >= visitor.result.unwrap() {
|
||||
if expr_and_pat_count >= visitor.result.unwrap() {
|
||||
Some(span)
|
||||
} else {
|
||||
None
|
||||
|
|
@ -953,12 +962,16 @@ fn resolve_expr<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, expr: &'tcx h
|
|||
|
||||
debug!("resolve_expr post-increment {}, expr = {:?}", visitor.expr_and_pat_count, expr);
|
||||
|
||||
if let hir::ExprKind::Yield(..) = expr.node {
|
||||
if let hir::ExprKind::Yield(_, source) = &expr.node {
|
||||
// Mark this expr's scope and all parent scopes as containing `yield`.
|
||||
let mut scope = Scope { id: expr.hir_id.local_id, data: ScopeData::Node };
|
||||
loop {
|
||||
visitor.scope_tree.yield_in_scope.insert(scope,
|
||||
(expr.span, visitor.expr_and_pat_count));
|
||||
let data = YieldData {
|
||||
span: expr.span,
|
||||
expr_and_pat_count: visitor.expr_and_pat_count,
|
||||
source: *source,
|
||||
};
|
||||
visitor.scope_tree.yield_in_scope.insert(scope, data);
|
||||
|
||||
// Keep traversing up while we can.
|
||||
match visitor.scope_tree.parent_map.get(&scope) {
|
||||
|
|
@ -1302,7 +1315,7 @@ impl<'tcx> Visitor<'tcx> for RegionResolutionVisitor<'tcx> {
|
|||
resolve_local(self, None, Some(&body.value));
|
||||
}
|
||||
|
||||
if body.is_generator {
|
||||
if body.generator_kind.is_some() {
|
||||
self.scope_tree.body_expr_count.insert(body_id, self.expr_and_pat_count);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -126,7 +126,7 @@ pub fn mir_build<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> Body<'tcx> {
|
|||
|
||||
let arguments = implicit_argument.into_iter().chain(explicit_arguments);
|
||||
|
||||
let (yield_ty, return_ty) = if body.is_generator {
|
||||
let (yield_ty, return_ty) = if body.generator_kind.is_some() {
|
||||
let gen_sig = match ty.sty {
|
||||
ty::Generator(gen_def_id, gen_substs, ..) =>
|
||||
gen_substs.sig(gen_def_id, tcx),
|
||||
|
|
@ -590,7 +590,7 @@ where
|
|||
return_ty_span,
|
||||
upvar_debuginfo,
|
||||
upvar_mutbls,
|
||||
body.is_generator);
|
||||
body.generator_kind.is_some());
|
||||
|
||||
let call_site_scope = region::Scope {
|
||||
id: body.value.hir_id.local_id,
|
||||
|
|
|
|||
|
|
@ -763,7 +763,7 @@ fn make_mirror_unadjusted<'a, 'tcx>(
|
|||
hir::ExprKind::Array(ref fields) => ExprKind::Array { fields: fields.to_ref() },
|
||||
hir::ExprKind::Tup(ref fields) => ExprKind::Tuple { fields: fields.to_ref() },
|
||||
|
||||
hir::ExprKind::Yield(ref v) => ExprKind::Yield { value: v.to_ref() },
|
||||
hir::ExprKind::Yield(ref v, _) => ExprKind::Yield { value: v.to_ref() },
|
||||
hir::ExprKind::Err => unreachable!(),
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -545,7 +545,7 @@ fn check_expr_kind<'a, 'tcx>(
|
|||
}
|
||||
|
||||
// Generator expressions
|
||||
hir::ExprKind::Yield(ref expr) => {
|
||||
hir::ExprKind::Yield(ref expr, _) => {
|
||||
let _ = v.check_expr(&expr);
|
||||
NotPromotable
|
||||
}
|
||||
|
|
|
|||
|
|
@ -295,7 +295,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
ExprKind::Index(ref base, ref idx) => {
|
||||
self.check_expr_index(base, idx, needs, expr)
|
||||
}
|
||||
ExprKind::Yield(ref value) => {
|
||||
ExprKind::Yield(ref value, _) => {
|
||||
self.check_expr_yield(value, expr)
|
||||
}
|
||||
hir::ExprKind::Err => {
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
use rustc::hir::def_id::DefId;
|
||||
use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
|
||||
use rustc::hir::{self, Pat, PatKind, Expr};
|
||||
use rustc::middle::region;
|
||||
use rustc::middle::region::{self, YieldData};
|
||||
use rustc::ty::{self, Ty};
|
||||
use syntax_pos::Span;
|
||||
use super::FnCtxt;
|
||||
|
|
@ -17,6 +17,7 @@ struct InteriorVisitor<'a, 'tcx> {
|
|||
types: FxHashMap<Ty<'tcx>, usize>,
|
||||
region_scope_tree: &'tcx region::ScopeTree,
|
||||
expr_count: usize,
|
||||
kind: hir::GeneratorKind,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> {
|
||||
|
|
@ -27,8 +28,8 @@ impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> {
|
|||
source_span: Span) {
|
||||
use syntax_pos::DUMMY_SP;
|
||||
|
||||
let live_across_yield = scope.map_or(Some(DUMMY_SP), |s| {
|
||||
self.region_scope_tree.yield_in_scope(s).and_then(|(yield_span, expr_count)| {
|
||||
let live_across_yield = scope.map(|s| {
|
||||
self.region_scope_tree.yield_in_scope(s).and_then(|yield_data| {
|
||||
// If we are recording an expression that is the last yield
|
||||
// in the scope, or that has a postorder CFG index larger
|
||||
// than the one of all of the yields, then its value can't
|
||||
|
|
@ -37,31 +38,43 @@ impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> {
|
|||
// See the mega-comment at `yield_in_scope` for a proof.
|
||||
|
||||
debug!("comparing counts yield: {} self: {}, source_span = {:?}",
|
||||
expr_count, self.expr_count, source_span);
|
||||
yield_data.expr_and_pat_count, self.expr_count, source_span);
|
||||
|
||||
if expr_count >= self.expr_count {
|
||||
Some(yield_span)
|
||||
if yield_data.expr_and_pat_count >= self.expr_count {
|
||||
Some(yield_data)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
});
|
||||
}).unwrap_or_else(|| Some(YieldData {
|
||||
span: DUMMY_SP,
|
||||
expr_and_pat_count: 0,
|
||||
source: match self.kind { // Guess based on the kind of the current generator.
|
||||
hir::GeneratorKind::Gen => hir::YieldSource::Yield,
|
||||
hir::GeneratorKind::Async => hir::YieldSource::Await,
|
||||
},
|
||||
}));
|
||||
|
||||
if let Some(yield_span) = live_across_yield {
|
||||
if let Some(yield_data) = live_across_yield {
|
||||
let ty = self.fcx.resolve_vars_if_possible(&ty);
|
||||
|
||||
debug!("type in expr = {:?}, scope = {:?}, type = {:?}, count = {}, yield_span = {:?}",
|
||||
expr, scope, ty, self.expr_count, yield_span);
|
||||
expr, scope, ty, self.expr_count, yield_data.span);
|
||||
|
||||
if let Some((unresolved_type, unresolved_type_span)) =
|
||||
self.fcx.unresolved_type_vars(&ty)
|
||||
{
|
||||
let note = format!("the type is part of the {} because of this {}",
|
||||
self.kind,
|
||||
yield_data.source);
|
||||
|
||||
// If unresolved type isn't a ty_var then unresolved_type_span is None
|
||||
self.fcx.need_type_info_err_in_generator(
|
||||
unresolved_type_span.unwrap_or(yield_span),
|
||||
unresolved_type)
|
||||
.span_note(yield_span,
|
||||
"the type is part of the generator because of this `yield`")
|
||||
self.kind,
|
||||
unresolved_type_span.unwrap_or(yield_data.span),
|
||||
unresolved_type,
|
||||
)
|
||||
.span_note(yield_data.span, &*note)
|
||||
.emit();
|
||||
} else {
|
||||
// Map the type to the number of types added before it
|
||||
|
|
@ -80,6 +93,7 @@ pub fn resolve_interior<'a, 'tcx>(
|
|||
def_id: DefId,
|
||||
body_id: hir::BodyId,
|
||||
interior: Ty<'tcx>,
|
||||
kind: hir::GeneratorKind,
|
||||
) {
|
||||
let body = fcx.tcx.hir().body(body_id);
|
||||
let mut visitor = InteriorVisitor {
|
||||
|
|
@ -87,6 +101,7 @@ pub fn resolve_interior<'a, 'tcx>(
|
|||
types: FxHashMap::default(),
|
||||
region_scope_tree: fcx.tcx.region_scope_tree(def_id),
|
||||
expr_count: 0,
|
||||
kind,
|
||||
};
|
||||
intravisit::walk_body(&mut visitor, body);
|
||||
|
||||
|
|
|
|||
|
|
@ -217,7 +217,7 @@ pub struct Inherited<'a, 'tcx> {
|
|||
|
||||
deferred_cast_checks: RefCell<Vec<cast::CastCheck<'tcx>>>,
|
||||
|
||||
deferred_generator_interiors: RefCell<Vec<(hir::BodyId, Ty<'tcx>)>>,
|
||||
deferred_generator_interiors: RefCell<Vec<(hir::BodyId, Ty<'tcx>, hir::GeneratorKind)>>,
|
||||
|
||||
// Opaque types found in explicit return types and their
|
||||
// associated fresh inference variable. Writeback resolves these
|
||||
|
|
@ -1071,7 +1071,7 @@ fn check_fn<'a, 'tcx>(
|
|||
|
||||
let span = body.value.span;
|
||||
|
||||
if body.is_generator && can_be_generator.is_some() {
|
||||
if body.generator_kind.is_some() && can_be_generator.is_some() {
|
||||
let yield_ty = fcx.next_ty_var(TypeVariableOrigin {
|
||||
kind: TypeVariableOriginKind::TypeInference,
|
||||
span,
|
||||
|
|
@ -1108,12 +1108,12 @@ fn check_fn<'a, 'tcx>(
|
|||
// We insert the deferred_generator_interiors entry after visiting the body.
|
||||
// This ensures that all nested generators appear before the entry of this generator.
|
||||
// resolve_generator_interiors relies on this property.
|
||||
let gen_ty = if can_be_generator.is_some() && body.is_generator {
|
||||
let gen_ty = if let (Some(_), Some(gen_kind)) = (can_be_generator, body.generator_kind) {
|
||||
let interior = fcx.next_ty_var(TypeVariableOrigin {
|
||||
kind: TypeVariableOriginKind::MiscVariable,
|
||||
span,
|
||||
});
|
||||
fcx.deferred_generator_interiors.borrow_mut().push((body.id(), interior));
|
||||
fcx.deferred_generator_interiors.borrow_mut().push((body.id(), interior, gen_kind));
|
||||
Some(GeneratorTypes {
|
||||
yield_ty: fcx.yield_ty.unwrap(),
|
||||
interior,
|
||||
|
|
@ -2633,9 +2633,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
|
||||
fn resolve_generator_interiors(&self, def_id: DefId) {
|
||||
let mut generators = self.deferred_generator_interiors.borrow_mut();
|
||||
for (body_id, interior) in generators.drain(..) {
|
||||
for (body_id, interior, kind) in generators.drain(..) {
|
||||
self.select_obligations_where_possible(false);
|
||||
generator_interior::resolve_interior(self, def_id, body_id, interior);
|
||||
generator_interior::resolve_interior(self, def_id, body_id, interior, kind);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,9 +7,9 @@ async fn bar<T>() -> () {}
|
|||
|
||||
async fn foo() {
|
||||
bar().await;
|
||||
//~^ ERROR type inside generator must be known in this context
|
||||
//~^ ERROR type inside `async` object must be known in this context
|
||||
//~| NOTE cannot infer type for `T`
|
||||
//~| NOTE the type is part of the generator because of this `yield`
|
||||
//~| NOTE the type is part of the `async` object because of this `await`
|
||||
//~| NOTE in this expansion of desugaring of `await`
|
||||
}
|
||||
fn main() {}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
error[E0698]: type inside generator must be known in this context
|
||||
error[E0698]: type inside `async` object must be known in this context
|
||||
--> $DIR/unresolved_type_param.rs:9:5
|
||||
|
|
||||
LL | bar().await;
|
||||
| ^^^ cannot infer type for `T`
|
||||
|
|
||||
note: the type is part of the generator because of this `yield`
|
||||
note: the type is part of the `async` object because of this `await`
|
||||
--> $DIR/unresolved_type_param.rs:9:5
|
||||
|
|
||||
LL | bar().await;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue