diff options
| author | Mazdak Farrokhzad <twingoow@gmail.com> | 2019-06-19 01:52:13 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2019-06-19 01:52:13 +0200 |
| commit | fde341a4ef6a5728dfd1acb5de0b238918a2dd44 (patch) | |
| tree | ab68af031220c4330a15f77663849e848c858a62 | |
| parent | 9b7b47cd57113fcef6842e249e2c3e9260f44380 (diff) | |
| parent | d67db0042c1f4e163292ea59bdfac546c67f7001 (diff) | |
| download | rust-fde341a4ef6a5728dfd1acb5de0b238918a2dd44.tar.gz rust-fde341a4ef6a5728dfd1acb5de0b238918a2dd44.zip | |
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.
| -rw-r--r-- | src/librustc/cfg/construct.rs | 2 | ||||
| -rw-r--r-- | src/librustc/hir/intravisit.rs | 2 | ||||
| -rw-r--r-- | src/librustc/hir/lowering.rs | 148 | ||||
| -rw-r--r-- | src/librustc/hir/mod.rs | 72 | ||||
| -rw-r--r-- | src/librustc/hir/print.rs | 2 | ||||
| -rw-r--r-- | src/librustc/ich/impls_hir.rs | 10 | ||||
| -rw-r--r-- | src/librustc/infer/error_reporting/need_type_info.rs | 9 | ||||
| -rw-r--r-- | src/librustc/middle/expr_use_visitor.rs | 2 | ||||
| -rw-r--r-- | src/librustc/middle/liveness.rs | 2 | ||||
| -rw-r--r-- | src/librustc/middle/region.rs | 29 | ||||
| -rw-r--r-- | src/librustc_mir/build/mod.rs | 4 | ||||
| -rw-r--r-- | src/librustc_mir/hair/cx/expr.rs | 2 | ||||
| -rw-r--r-- | src/librustc_passes/rvalue_promotion.rs | 2 | ||||
| -rw-r--r-- | src/librustc_typeck/check/expr.rs | 2 | ||||
| -rw-r--r-- | src/librustc_typeck/check/generator_interior.rs | 43 | ||||
| -rw-r--r-- | src/librustc_typeck/check/mod.rs | 12 | ||||
| -rw-r--r-- | src/test/ui/async-await/unresolved_type_param.rs | 4 | ||||
| -rw-r--r-- | src/test/ui/async-await/unresolved_type_param.stderr | 4 |
18 files changed, 222 insertions, 129 deletions
diff --git a/src/librustc/cfg/construct.rs b/src/librustc/cfg/construct.rs index 213e57a3b37..a7750edbb6f 100644 --- a/src/librustc/cfg/construct.rs +++ b/src/librustc/cfg/construct.rs @@ -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()) } diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs index e29a373ec3b..8d7e51d1ea6 100644 --- a/src/librustc/hir/intravisit.rs +++ b/src/librustc/hir/intravisit.rs @@ -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 => {} diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index d2b8c4729a4..4baa61a377b 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -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)) diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 0884a726a27..b063a6541e2 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -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", + }) } } diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs index 7b0a499fa5c..69ee84dfa43 100644 --- a/src/librustc/hir/print.rs +++ b/src/librustc/hir/print.rs @@ -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)?; } diff --git a/src/librustc/ich/impls_hir.rs b/src/librustc/ich/impls_hir.rs index f2f909b6af1..30d76f240d1 100644 --- a/src/librustc/ich/impls_hir.rs +++ b/src/librustc/ich/impls_hir.rs @@ -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); }); } } diff --git a/src/librustc/infer/error_reporting/need_type_info.rs b/src/librustc/infer/error_reporting/need_type_info.rs index 362a680f53c..fe151bdec6a 100644 --- a/src/librustc/infer/error_reporting/need_type_info.rs +++ b/src/librustc/infer/error_reporting/need_type_info.rs @@ -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 } diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 1c3eead90fa..086ddfd7e33 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -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); } } diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index dc6fa066071..bf054d68b70 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -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) } diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index dfab8e36bf9..93cb6ab96f8 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -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); } diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index 001f377c0ee..f7958434afa 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -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, diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index 9f05cf981f5..baf9086a480 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -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!(), }; diff --git a/src/librustc_passes/rvalue_promotion.rs b/src/librustc_passes/rvalue_promotion.rs index 1493d029048..bc1151974bb 100644 --- a/src/librustc_passes/rvalue_promotion.rs +++ b/src/librustc_passes/rvalue_promotion.rs @@ -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 } diff --git a/src/librustc_typeck/check/expr.rs b/src/librustc_typeck/check/expr.rs index 421688097b8..563bb5760a9 100644 --- a/src/librustc_typeck/check/expr.rs +++ b/src/librustc_typeck/check/expr.rs @@ -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 => { diff --git a/src/librustc_typeck/check/generator_interior.rs b/src/librustc_typeck/check/generator_interior.rs index ac2dcbadad8..72f42c85ead 100644 --- a/src/librustc_typeck/check/generator_interior.rs +++ b/src/librustc_typeck/check/generator_interior.rs @@ -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 } }) - }); - - if let Some(yield_span) = live_across_yield { + }).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_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); diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 51908173203..177e2158044 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -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); } } diff --git a/src/test/ui/async-await/unresolved_type_param.rs b/src/test/ui/async-await/unresolved_type_param.rs index 77174b03217..578d41fe0df 100644 --- a/src/test/ui/async-await/unresolved_type_param.rs +++ b/src/test/ui/async-await/unresolved_type_param.rs @@ -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() {} diff --git a/src/test/ui/async-await/unresolved_type_param.stderr b/src/test/ui/async-await/unresolved_type_param.stderr index afb9adf4c77..f3090a2b980 100644 --- a/src/test/ui/async-await/unresolved_type_param.stderr +++ b/src/test/ui/async-await/unresolved_type_param.stderr @@ -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; |
