From d861982ca6a1fa5773373362771aa08b9f732de0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Mon, 26 Dec 2016 14:34:03 +0100 Subject: [PATCH 001/113] Generator literal support --- src/libcore/ops/generator.rs | 38 + src/libcore/ops/mod.rs | 8 + src/librustc/cfg/construct.rs | 2 + src/librustc/hir/intravisit.rs | 11 +- src/librustc/hir/lowering.rs | 98 ++- src/librustc/hir/map/blocks.rs | 3 +- src/librustc/hir/map/collector.rs | 7 + src/librustc/hir/map/mod.rs | 17 +- src/librustc/hir/mod.rs | 28 +- src/librustc/hir/print.rs | 16 +- src/librustc/ich/impls_hir.rs | 21 +- src/librustc/ich/impls_mir.rs | 17 +- src/librustc/ich/impls_ty.rs | 18 + .../infer/error_reporting/need_type_info.rs | 12 + src/librustc/infer/freshen.rs | 1 + src/librustc/infer/mod.rs | 31 + src/librustc/middle/expr_use_visitor.rs | 8 +- src/librustc/middle/lang_items.rs | 3 + src/librustc/middle/liveness.rs | 47 +- src/librustc/middle/mem_categorization.rs | 21 +- src/librustc/middle/region.rs | 68 +- src/librustc/mir/mod.rs | 132 +++- src/librustc/mir/tcx.rs | 5 + src/librustc/mir/transform.rs | 6 +- src/librustc/mir/visit.rs | 28 +- src/librustc/traits/coherence.rs | 2 +- src/librustc/traits/error_reporting.rs | 1 + src/librustc/traits/mod.rs | 19 + src/librustc/traits/project.rs | 58 ++ src/librustc/traits/select.rs | 130 ++- src/librustc/traits/structural_impls.rs | 43 + src/librustc/traits/util.rs | 13 + src/librustc/ty/context.rs | 18 +- src/librustc/ty/error.rs | 1 + src/librustc/ty/fast_reject.rs | 4 + src/librustc/ty/flags.rs | 9 + src/librustc/ty/item_path.rs | 1 + src/librustc/ty/layout.rs | 18 +- src/librustc/ty/maps.rs | 13 +- src/librustc/ty/mod.rs | 14 +- src/librustc/ty/outlives.rs | 10 + src/librustc/ty/relate.rs | 24 + src/librustc/ty/structural_impls.rs | 59 ++ src/librustc/ty/sty.rs | 68 +- src/librustc/ty/util.rs | 10 + src/librustc/ty/walk.rs | 4 + src/librustc/ty/wf.rs | 4 +- src/librustc/util/ppaux.rs | 43 +- .../borrowck/gather_loans/mod.rs | 44 +- src/librustc_borrowck/borrowck/mod.rs | 4 +- src/librustc_borrowck/diagnostics.rs | 2 + src/librustc_data_structures/indexed_set.rs | 8 + src/librustc_data_structures/indexed_vec.rs | 2 +- src/librustc_data_structures/stable_hasher.rs | 9 + src/librustc_driver/driver.rs | 4 + src/librustc_lint/types.rs | 1 + src/librustc_metadata/cstore_impl.rs | 1 + src/librustc_metadata/decoder.rs | 18 + src/librustc_metadata/encoder.rs | 18 +- src/librustc_metadata/schema.rs | 11 + src/librustc_mir/build/expr/as_lvalue.rs | 4 + src/librustc_mir/build/expr/as_rvalue.rs | 36 +- src/librustc_mir/build/expr/as_temp.rs | 2 +- src/librustc_mir/build/expr/category.rs | 2 + src/librustc_mir/build/expr/into.rs | 2 + src/librustc_mir/build/matches/mod.rs | 2 +- src/librustc_mir/build/mod.rs | 87 ++- src/librustc_mir/build/scope.rs | 194 ++++- .../dataflow/drop_flag_effects.rs | 5 + src/librustc_mir/dataflow/mod.rs | 6 + src/librustc_mir/dataflow/move_paths/mod.rs | 6 + src/librustc_mir/hair/cx/expr.rs | 20 +- src/librustc_mir/hair/cx/mod.rs | 1 + src/librustc_mir/hair/mod.rs | 5 + src/librustc_mir/shim.rs | 17 +- src/librustc_mir/transform/copy_prop.rs | 1 + src/librustc_mir/transform/elaborate_drops.rs | 16 +- src/librustc_mir/transform/generator.rs | 739 ++++++++++++++++++ src/librustc_mir/transform/inline.rs | 6 + src/librustc_mir/transform/mod.rs | 1 + src/librustc_mir/transform/no_landing_pads.rs | 2 + src/librustc_mir/transform/promote_consts.rs | 1 + src/librustc_mir/transform/qualify_consts.rs | 3 + src/librustc_mir/transform/type_check.rs | 46 +- src/librustc_mir/util/elaborate_drops.rs | 3 +- src/librustc_mir/util/liveness.rs | 205 +++++ src/librustc_mir/util/mod.rs | 1 + src/librustc_mir/util/pretty.rs | 40 +- src/librustc_passes/consts.rs | 4 + src/librustc_passes/loops.rs | 2 +- src/librustc_passes/mir_stats.rs | 5 + src/librustc_trans/adt.rs | 6 + src/librustc_trans/back/symbol_names.rs | 4 +- src/librustc_trans/collector.rs | 2 + src/librustc_trans/common.rs | 35 +- src/librustc_trans/debuginfo/metadata.rs | 10 + src/librustc_trans/debuginfo/type_names.rs | 3 + src/librustc_trans/mir/analyze.rs | 4 +- src/librustc_trans/mir/block.rs | 23 + src/librustc_trans/mir/constant.rs | 4 + src/librustc_trans/mir/mod.rs | 16 +- src/librustc_trans/monomorphize.rs | 6 + src/librustc_trans/trans_item.rs | 1 + src/librustc_trans/type_of.rs | 7 +- src/librustc_typeck/check/closure.rs | 22 +- .../check/generator_interior.rs | 110 +++ src/librustc_typeck/check/method/probe.rs | 44 ++ src/librustc_typeck/check/mod.rs | 154 +++- src/librustc_typeck/check/regionck.rs | 2 +- src/librustc_typeck/check/upvar.rs | 24 +- src/librustc_typeck/check/writeback.rs | 26 +- src/librustc_typeck/collect.rs | 6 +- src/librustc_typeck/diagnostics.rs | 4 + src/librustc_typeck/variance/constraints.rs | 21 +- src/librustdoc/clean/mod.rs | 2 +- src/libsyntax/ast.rs | 6 + src/libsyntax/feature_gate.rs | 14 + src/libsyntax/fold.rs | 2 + src/libsyntax/parse/parser.rs | 22 +- src/libsyntax/parse/token.rs | 1 + src/libsyntax/print/pprust.rs | 15 + src/libsyntax/visit.rs | 4 + src/libsyntax_pos/symbol.rs | 2 + .../compile-fail/feature-gate-generators.rs | 14 + .../compile-fail/generator/const-yield.rs | 16 + .../generator/generator-not-fnmut.rs | 25 + src/test/run-pass/generator/iterator-count.rs | 44 ++ 127 files changed, 3239 insertions(+), 260 deletions(-) create mode 100644 src/libcore/ops/generator.rs create mode 100644 src/librustc_mir/transform/generator.rs create mode 100644 src/librustc_mir/util/liveness.rs create mode 100644 src/librustc_typeck/check/generator_interior.rs create mode 100644 src/test/compile-fail/feature-gate-generators.rs create mode 100644 src/test/compile-fail/generator/const-yield.rs create mode 100644 src/test/compile-fail/generator/generator-not-fnmut.rs create mode 100644 src/test/run-pass/generator/iterator-count.rs diff --git a/src/libcore/ops/generator.rs b/src/libcore/ops/generator.rs new file mode 100644 index 0000000000000..92330ad6333a2 --- /dev/null +++ b/src/libcore/ops/generator.rs @@ -0,0 +1,38 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +/// The result of a generator resumption. +#[derive(Debug)] +#[cfg(not(stage0))] +#[lang = "generator_state"] +#[unstable(feature = "generator_trait", issue = "0")] +pub enum State { + /// The generator suspended with a value. + Yielded(Y), + + /// The generator completed with a return value. + Complete(R), +} + +/// The trait implemented by builtin generator types. +#[cfg(not(stage0))] +#[lang = "generator"] +#[unstable(feature = "generator_trait", issue = "0")] +#[fundamental] +pub trait Generator { + /// The type of value this generator yields. + type Yield; + + /// The type of value this generator returns. + type Return; + + /// This resumes the execution of the generator. + fn resume(&mut self, arg: Arg) -> State; +} diff --git a/src/libcore/ops/mod.rs b/src/libcore/ops/mod.rs index a78f4fe28a6b4..36b0a3c8a3472 100644 --- a/src/libcore/ops/mod.rs +++ b/src/libcore/ops/mod.rs @@ -152,6 +152,7 @@ mod bit; mod deref; mod drop; mod function; +mod generator; mod index; mod place; mod range; @@ -189,6 +190,13 @@ pub use self::range::{RangeInclusive, RangeToInclusive}; #[unstable(feature = "try_trait", issue = "42327")] pub use self::try::Try; +#[unstable(feature = "generator_trait", issue = "0")] +#[cfg(not(stage0))] +pub use self::generator::State; +#[unstable(feature = "generator_trait", issue = "0")] +#[cfg(not(stage0))] +pub use self::generator::Generator; + #[unstable(feature = "placement_new_protocol", issue = "27779")] pub use self::place::{Place, Placer, InPlace, Boxed, BoxPlace}; diff --git a/src/librustc/cfg/construct.rs b/src/librustc/cfg/construct.rs index fa6b78045ffad..36aeaba0c5ec6 100644 --- a/src/librustc/cfg/construct.rs +++ b/src/librustc/cfg/construct.rs @@ -389,6 +389,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { hir::ExprUnary(_, ref e) | hir::ExprField(ref e, _) | hir::ExprTupField(ref e, _) | + hir::ExprSuspend(ref e) | hir::ExprRepeat(ref e, _) => { self.straightline(expr, pred, Some(&**e).into_iter()) } @@ -401,6 +402,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { hir::ExprClosure(..) | hir::ExprLit(..) | + hir::ExprImplArg(_) | hir::ExprPath(_) => { self.straightline(expr, pred, None::.iter()) } diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs index 57198d8ca0b77..47a0f67a64074 100644 --- a/src/librustc/hir/intravisit.rs +++ b/src/librustc/hir/intravisit.rs @@ -399,6 +399,9 @@ pub fn walk_body<'v, V: Visitor<'v>>(visitor: &mut V, body: &'v Body) { visitor.visit_id(argument.id); visitor.visit_pat(&argument.pat); } + if let Some(ref impl_arg) = body.impl_arg { + visitor.visit_id(impl_arg.id); + } visitor.visit_expr(&body.value); } @@ -978,7 +981,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) { visitor.visit_expr(subexpression); walk_list!(visitor, visit_arm, arms); } - ExprClosure(_, ref function_declaration, body, _fn_decl_span) => { + ExprClosure(_, ref function_declaration, body, _fn_decl_span, _gen) => { visitor.visit_fn(FnKind::Closure(&expression.attrs), function_declaration, body, @@ -1042,6 +1045,12 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) { visitor.visit_expr(input) } } + ExprSuspend(ref subexpression) => { + visitor.visit_expr(subexpression); + } + ExprImplArg(id) => { + visitor.visit_id(id); + }, } } diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 3ae3671b59347..410f5e8d5ef40 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -92,6 +92,8 @@ pub struct LoweringContext<'a> { trait_impls: BTreeMap>, trait_default_impl: BTreeMap, + impl_arg: Option, + catch_scopes: Vec, loop_scopes: Vec, is_in_loop_condition: bool, @@ -137,6 +139,7 @@ pub fn lower_crate(sess: &Session, trait_impls: BTreeMap::new(), trait_default_impl: BTreeMap::new(), exported_macros: Vec::new(), + impl_arg: None, catch_scopes: Vec::new(), loop_scopes: Vec::new(), is_in_loop_condition: false, @@ -362,12 +365,24 @@ impl<'a> LoweringContext<'a> { }) } + fn impl_arg_id(&mut self) -> NodeId { + if self.impl_arg.is_none() { + self.impl_arg = Some(self.next_id()); + } + self.impl_arg.unwrap() + } + fn record_body(&mut self, value: hir::Expr, decl: Option<&FnDecl>) -> hir::BodyId { + let span = value.span; let body = hir::Body { arguments: decl.map_or(hir_vec![], |decl| { decl.inputs.iter().map(|x| self.lower_arg(x)).collect() }), + impl_arg: self.impl_arg.map(|id| hir::ImplArg { + id, + span, + }), value, }; let id = body.id(); @@ -425,6 +440,17 @@ impl<'a> LoweringContext<'a> { result } + fn lower_body(&mut self, decl: Option<&FnDecl>, f: F) -> hir::BodyId + where F: FnOnce(&mut LoweringContext) -> hir::Expr + { + let old_impl_arg = self.impl_arg; + self.impl_arg = None; + let result = f(self); + let r = self.record_body(result, decl); + self.impl_arg = old_impl_arg; + r + } + fn with_loop_scope(&mut self, loop_id: NodeId, f: F) -> T where F: FnOnce(&mut LoweringContext) -> T { @@ -609,13 +635,12 @@ impl<'a> LoweringContext<'a> { }))) } TyKind::Array(ref ty, ref length) => { - let length = self.lower_expr(length); - hir::TyArray(self.lower_ty(ty), - self.record_body(length, None)) + let body = self.lower_body(None, |this| this.lower_expr(length)); + hir::TyArray(self.lower_ty(ty), body) } TyKind::Typeof(ref expr) => { - let expr = self.lower_expr(expr); - hir::TyTypeof(self.record_body(expr, None)) + let body = self.lower_body(None, |this| this.lower_expr(expr)); + hir::TyTypeof(body) } TyKind::TraitObject(ref bounds) => { let mut lifetime_bound = None; @@ -672,8 +697,7 @@ impl<'a> LoweringContext<'a> { attrs: self.lower_attrs(&v.node.attrs), data: self.lower_variant_data(&v.node.data), disr_expr: v.node.disr_expr.as_ref().map(|e| { - let e = self.lower_expr(e); - self.record_body(e, None) + self.lower_body(None, |this| this.lower_expr(e)) }), }, span: v.span, @@ -1287,21 +1311,21 @@ impl<'a> LoweringContext<'a> { hir::ItemUse(path, kind) } ItemKind::Static(ref t, m, ref e) => { - let value = self.lower_expr(e); + let body = self.lower_body(None, |this| this.lower_expr(e)); hir::ItemStatic(self.lower_ty(t), self.lower_mutability(m), - self.record_body(value, None)) + body) } ItemKind::Const(ref t, ref e) => { - let value = self.lower_expr(e); - hir::ItemConst(self.lower_ty(t), - self.record_body(value, None)) + let body = self.lower_body(None, |this| this.lower_expr(e)); + hir::ItemConst(self.lower_ty(t), body) } ItemKind::Fn(ref decl, unsafety, constness, abi, ref generics, ref body) => { self.with_new_scopes(|this| { - let body = this.lower_block(body, false); - let body = this.expr_block(body, ThinVec::new()); - let body_id = this.record_body(body, Some(decl)); + let body_id = this.lower_body(Some(decl), |this| { + let body = this.lower_block(body, false); + this.expr_block(body, ThinVec::new()) + }); hir::ItemFn(this.lower_fn_decl(decl), this.lower_unsafety(unsafety), this.lower_constness(constness), @@ -1394,8 +1418,7 @@ impl<'a> LoweringContext<'a> { TraitItemKind::Const(ref ty, ref default) => { hir::TraitItemKind::Const(this.lower_ty(ty), default.as_ref().map(|x| { - let value = this.lower_expr(x); - this.record_body(value, None) + this.lower_body(None, |this| this.lower_expr(x)) })) } TraitItemKind::Method(ref sig, None) => { @@ -1404,9 +1427,10 @@ impl<'a> LoweringContext<'a> { hir::TraitMethod::Required(names)) } TraitItemKind::Method(ref sig, Some(ref body)) => { + let body_id = this.lower_body(Some(&sig.decl), |this| { let body = this.lower_block(body, false); - let expr = this.expr_block(body, ThinVec::new()); - let body_id = this.record_body(expr, Some(&sig.decl)); + this.expr_block(body, ThinVec::new()) + }); hir::TraitItemKind::Method(this.lower_method_sig(sig), hir::TraitMethod::Provided(body_id)) } @@ -1455,14 +1479,14 @@ impl<'a> LoweringContext<'a> { defaultness: this.lower_defaultness(i.defaultness, true /* [1] */), node: match i.node { ImplItemKind::Const(ref ty, ref expr) => { - let value = this.lower_expr(expr); - let body_id = this.record_body(value, None); + let body_id = this.lower_body(None, |this| this.lower_expr(expr)); hir::ImplItemKind::Const(this.lower_ty(ty), body_id) } ImplItemKind::Method(ref sig, ref body) => { + let body_id = this.lower_body(Some(&sig.decl), |this| { let body = this.lower_block(body, false); - let expr = this.expr_block(body, ThinVec::new()); - let body_id = this.record_body(expr, Some(&sig.decl)); + this.expr_block(body, ThinVec::new()) + }); hir::ImplItemKind::Method(this.lower_method_sig(sig), body_id) } ImplItemKind::Type(ref ty) => hir::ImplItemKind::Type(this.lower_ty(ty)), @@ -1834,8 +1858,8 @@ impl<'a> LoweringContext<'a> { } ExprKind::Repeat(ref expr, ref count) => { let expr = P(self.lower_expr(expr)); - let count = self.lower_expr(count); - hir::ExprRepeat(expr, self.record_body(count, None)) + let body = self.lower_body(None, |this| this.lower_expr(count)); + hir::ExprRepeat(expr, body) } ExprKind::Tup(ref elts) => { hir::ExprTup(elts.iter().map(|x| self.lower_expr(x)).collect()) @@ -1928,11 +1952,17 @@ impl<'a> LoweringContext<'a> { ExprKind::Closure(capture_clause, ref decl, ref body, fn_decl_span) => { self.with_new_scopes(|this| { this.with_parent_def(e.id, |this| { - let expr = this.lower_expr(body); + let mut gen = None; + let body_id = this.lower_body(Some(decl), |this| { + let e = this.lower_expr(body); + gen = this.impl_arg.map(|_| hir::GeneratorClause::Movable); + e + }); hir::ExprClosure(this.lower_capture_clause(capture_clause), this.lower_fn_decl(decl), - this.record_body(expr, Some(decl)), - fn_decl_span) + body_id, + fn_decl_span, + gen) }) }) } @@ -2068,6 +2098,18 @@ impl<'a> LoweringContext<'a> { return ex; } + ExprKind::Yield(ref opt_expr) => { + self.impl_arg_id(); + let expr = opt_expr.as_ref().map(|x| self.lower_expr(x)).unwrap_or_else(|| { + self.expr(e.span, hir::ExprTup(hir_vec![]), ThinVec::new()) + }); + hir::ExprSuspend(P(expr)) + } + + ExprKind::ImplArg => { + hir::ExprImplArg(self.impl_arg_id()) + } + // Desugar ExprIfLet // From: `if let = []` ExprKind::IfLet(ref pat, ref sub_expr, ref body, ref else_opt) => { diff --git a/src/librustc/hir/map/blocks.rs b/src/librustc/hir/map/blocks.rs index 661798a825056..7094bd5b2cc1f 100644 --- a/src/librustc/hir/map/blocks.rs +++ b/src/librustc/hir/map/blocks.rs @@ -252,7 +252,8 @@ impl<'a> FnLikeNode<'a> { } }, map::NodeExpr(e) => match e.node { - ast::ExprClosure(_, ref decl, block, _fn_decl_span) => + ast::ExprClosure(_, ref decl, block, _fn_decl_span, _gen) => + // FIXME: Does this need handling for generators? closure(ClosureParts::new(&decl, block, e.id, e.span, &e.attrs)), _ => bug!("expr FnLikeNode that is not fn-like"), }, diff --git a/src/librustc/hir/map/collector.rs b/src/librustc/hir/map/collector.rs index d3ae3e0e8e8ac..dfc1c7ad36132 100644 --- a/src/librustc/hir/map/collector.rs +++ b/src/librustc/hir/map/collector.rs @@ -182,6 +182,13 @@ impl<'hir> Visitor<'hir> for NodeCollector<'hir> { }); } + fn visit_body(&mut self, b: &'hir Body) { + if let Some(ref impl_arg) = b.impl_arg { + self.insert(impl_arg.id, NodeImplArg(impl_arg)); + } + intravisit::walk_body(self, b); + } + fn visit_fn(&mut self, fk: intravisit::FnKind<'hir>, fd: &'hir FnDecl, b: BodyId, s: Span, id: NodeId) { assert_eq!(self.parent_node, id); diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs index 3fdd9c34f46d9..9a04cef5ee0fa 100644 --- a/src/librustc/hir/map/mod.rs +++ b/src/librustc/hir/map/mod.rs @@ -55,6 +55,7 @@ pub enum Node<'hir> { NodeTraitRef(&'hir TraitRef), NodeLocal(&'hir Pat), NodePat(&'hir Pat), + NodeImplArg(&'hir ImplArg), NodeBlock(&'hir Block), /// NodeStructCtor represents a tuple struct. @@ -84,6 +85,7 @@ enum MapEntry<'hir> { EntryTy(NodeId, &'hir Ty), EntryTraitRef(NodeId, &'hir TraitRef), EntryLocal(NodeId, &'hir Pat), + EntryImplArg(NodeId, &'hir ImplArg), EntryPat(NodeId, &'hir Pat), EntryBlock(NodeId, &'hir Block), EntryStructCtor(NodeId, &'hir VariantData), @@ -115,6 +117,7 @@ impl<'hir> MapEntry<'hir> { NodeTy(n) => EntryTy(p, n), NodeTraitRef(n) => EntryTraitRef(p, n), NodeLocal(n) => EntryLocal(p, n), + NodeImplArg(n) => EntryImplArg(p, n), NodePat(n) => EntryPat(p, n), NodeBlock(n) => EntryBlock(p, n), NodeStructCtor(n) => EntryStructCtor(p, n), @@ -136,6 +139,7 @@ impl<'hir> MapEntry<'hir> { EntryStmt(id, _) => id, EntryTy(id, _) => id, EntryTraitRef(id, _) => id, + EntryImplArg(id, _) => id, EntryLocal(id, _) => id, EntryPat(id, _) => id, EntryBlock(id, _) => id, @@ -162,13 +166,16 @@ impl<'hir> MapEntry<'hir> { EntryTy(_, n) => NodeTy(n), EntryTraitRef(_, n) => NodeTraitRef(n), EntryLocal(_, n) => NodeLocal(n), + EntryImplArg(_, n) => NodeImplArg(n), EntryPat(_, n) => NodePat(n), EntryBlock(_, n) => NodeBlock(n), EntryStructCtor(_, n) => NodeStructCtor(n), EntryLifetime(_, n) => NodeLifetime(n), EntryTyParam(_, n) => NodeTyParam(n), EntryVisibility(_, n) => NodeVisibility(n), - _ => return None + + NotPresent | + RootCrate => return None }) } @@ -201,7 +208,7 @@ impl<'hir> MapEntry<'hir> { EntryExpr(_, expr) => { match expr.node { - ExprClosure(.., body, _) => Some(body), + ExprClosure(.., body, _, _) => Some(body), _ => None, } } @@ -320,6 +327,7 @@ impl<'hir> Map<'hir> { EntryTy(p, _) | EntryTraitRef(p, _) | EntryLocal(p, _) | + EntryImplArg(p, _) | EntryPat(p, _) | EntryBlock(p, _) | EntryStructCtor(p, _) | @@ -895,6 +903,7 @@ impl<'hir> Map<'hir> { Some(EntryTy(_, ty)) => ty.span, Some(EntryTraitRef(_, tr)) => tr.path.span, Some(EntryLocal(_, pat)) => pat.span, + Some(EntryImplArg(_, impl_arg)) => impl_arg.span, Some(EntryPat(_, pat)) => pat.span, Some(EntryBlock(_, block)) => block.span, Some(EntryStructCtor(_, _)) => self.expect_item(self.get_parent(id)).span, @@ -1104,6 +1113,7 @@ impl<'a> print::State<'a> { } NodeLifetime(a) => self.print_lifetime(&a), NodeVisibility(a) => self.print_visibility(&a), + NodeImplArg(_) => bug!("cannot print ImplArg"), NodeTyParam(_) => bug!("cannot print TyParam"), NodeField(_) => bug!("cannot print StructField"), // these cases do not carry enough information in the @@ -1205,6 +1215,9 @@ fn node_id_to_string(map: &Map, id: NodeId, include_id: bool) -> String { Some(NodeLocal(_)) => { format!("local {}{}", map.node_to_pretty_string(id), id_str) } + Some(NodeImplArg(_)) => { + format!("impl_arg {}{}", map.node_to_pretty_string(id), id_str) + } Some(NodePat(_)) => { format!("pat {}{}", map.node_to_pretty_string(id), id_str) } diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index fd79ec3b6b92c..28d5cf2472d7a 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -925,6 +925,13 @@ pub enum UnsafeSource { UserProvided, } +/// represents an implicit argument of a generator +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] +pub struct ImplArg { + pub id: NodeId, + pub span: Span, +} + #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, RustcEncodable, RustcDecodable, Hash, Debug)] pub struct BodyId { pub node_id: NodeId, @@ -934,7 +941,8 @@ pub struct BodyId { #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub struct Body { pub arguments: HirVec, - pub value: Expr + pub value: Expr, + pub impl_arg: Option, } impl Body { @@ -943,6 +951,10 @@ impl Body { node_id: self.value.id } } + + pub fn is_generator(&self) -> bool { + self.impl_arg.is_some() + } } /// An expression @@ -1011,7 +1023,7 @@ pub enum Expr_ { /// A closure (for example, `move |a, b, c| {a + b + c}`). /// /// The final span is the span of the argument block `|...|` - ExprClosure(CaptureClause, P, BodyId, Span), + ExprClosure(CaptureClause, P, BodyId, Span, Option), /// A block (`{ ... }`) ExprBlock(P), @@ -1056,6 +1068,12 @@ pub enum Expr_ { /// For example, `[1; 5]`. The first expression is the element /// to be repeated; the second is the number of times to repeat it. ExprRepeat(P, BodyId), + + /// A suspension point for generators + ExprSuspend(P), + + /// The argument to a generator + ExprImplArg(NodeId), } /// Optionally `Self`-qualified value/type path or associated extension. @@ -1184,6 +1202,12 @@ pub struct Destination { pub target_id: ScopeTarget, } +#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)] +pub enum GeneratorClause { + Immovable, + Movable, +} + #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)] pub enum CaptureClause { CaptureByValue, diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs index beaf65b77d81f..4be48708bb3a1 100644 --- a/src/librustc/hir/print.rs +++ b/src/librustc/hir/print.rs @@ -1312,7 +1312,12 @@ impl<'a> State<'a> { } self.bclose_(expr.span, indent_unit)?; } - hir::ExprClosure(capture_clause, ref decl, body, _fn_decl_span) => { + hir::ExprClosure(capture_clause, ref decl, body, _fn_decl_span, gen) => { + if gen.is_some() { + self.head("gen")?; + space(&mut self.s)?; + } + self.print_capture_clause(capture_clause)?; self.print_closure_args(&decl, body)?; @@ -1461,6 +1466,15 @@ impl<'a> State<'a> { self.pclose()?; } + hir::ExprSuspend(ref expr) => { + word(&mut self.s, "suspend ")?; + self.print_expr(&expr)?; + } + hir::ExprImplArg(_) => { + word(&mut self.s, "gen")?; + space(&mut self.s)?; + word(&mut self.s, "arg")?; + } } self.ann.post(self, NodeExpr(expr))?; self.end() diff --git a/src/librustc/ich/impls_hir.rs b/src/librustc/ich/impls_hir.rs index 7805029a67ff7..d2cc186bad433 100644 --- a/src/librustc/ich/impls_hir.rs +++ b/src/librustc/ich/impls_hir.rs @@ -573,6 +573,8 @@ impl<'a, 'gcx, 'tcx> HashStable> for hir::E hir::ExprBreak(..) | hir::ExprAgain(..) | hir::ExprRet(..) | + hir::ExprSuspend(..) | + hir::ExprImplArg(..) | hir::ExprInlineAsm(..) | hir::ExprRepeat(..) | hir::ExprTup(..) => { @@ -637,7 +639,7 @@ impl_stable_hash_for!(enum hir::Expr_ { ExprWhile(cond, body, label), ExprLoop(body, label, loop_src), ExprMatch(matchee, arms, match_src), - ExprClosure(capture_clause, decl, body_id, span), + ExprClosure(capture_clause, decl, body_id, span, gen), ExprBlock(blk), ExprAssign(lhs, rhs), ExprAssignOp(op, lhs, rhs), @@ -651,7 +653,9 @@ impl_stable_hash_for!(enum hir::Expr_ { ExprRet(val), ExprInlineAsm(asm, inputs, outputs), ExprStruct(path, fields, base), - ExprRepeat(val, times) + ExprRepeat(val, times), + ExprSuspend(val), + ExprImplArg(id) }); impl_stable_hash_for!(enum hir::LocalSource { @@ -686,6 +690,11 @@ impl<'a, 'gcx, 'tcx> HashStable> for hir::M } } +impl_stable_hash_for!(enum hir::GeneratorClause { + Immovable, + Movable +}); + impl_stable_hash_for!(enum hir::CaptureClause { CaptureByValue, CaptureByRef @@ -1022,9 +1031,15 @@ impl_stable_hash_for!(struct hir::Arg { id }); +impl_stable_hash_for!(struct hir::ImplArg { + id, + span +}); + impl_stable_hash_for!(struct hir::Body { arguments, - value + value, + impl_arg }); impl<'a, 'gcx, 'tcx> HashStable> for hir::BodyId { diff --git a/src/librustc/ich/impls_mir.rs b/src/librustc/ich/impls_mir.rs index cb017b7f8864d..d273c6c9c42f1 100644 --- a/src/librustc/ich/impls_mir.rs +++ b/src/librustc/ich/impls_mir.rs @@ -17,7 +17,7 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher, StableHasherResult}; use std::mem; - +impl_stable_hash_for!(struct mir::GeneratorLayout<'tcx> { fields }); impl_stable_hash_for!(struct mir::SourceInfo { span, scope }); impl_stable_hash_for!(enum mir::Mutability { Mut, Not }); impl_stable_hash_for!(enum mir::BorrowKind { Shared, Unique, Mut }); @@ -54,9 +54,11 @@ for mir::Terminator<'tcx> { mir::TerminatorKind::SwitchInt { .. } | mir::TerminatorKind::Resume | mir::TerminatorKind::Return | + mir::TerminatorKind::GeneratorDrop | mir::TerminatorKind::Unreachable | mir::TerminatorKind::Drop { .. } | mir::TerminatorKind::DropAndReplace { .. } | + mir::TerminatorKind::Suspend { .. } | mir::TerminatorKind::Call { .. } => false, }; @@ -146,6 +148,7 @@ for mir::TerminatorKind<'tcx> { } mir::TerminatorKind::Resume | mir::TerminatorKind::Return | + mir::TerminatorKind::GeneratorDrop | mir::TerminatorKind::Unreachable => {} mir::TerminatorKind::Drop { ref location, target, unwind } => { location.hash_stable(hcx, hasher); @@ -161,6 +164,13 @@ for mir::TerminatorKind<'tcx> { target.hash_stable(hcx, hasher); unwind.hash_stable(hcx, hasher); } + mir::TerminatorKind::Suspend { ref value, + resume, + drop } => { + value.hash_stable(hcx, hasher); + resume.hash_stable(hcx, hasher); + drop.hash_stable(hcx, hasher); + } mir::TerminatorKind::Call { ref func, ref args, ref destination, @@ -200,6 +210,8 @@ for mir::AssertMessage<'tcx> { mir::AssertMessage::Math(ref const_math_err) => { const_math_err.hash_stable(hcx, hasher); } + mir::AssertMessage::GeneratorResumedAfterReturn => (), + mir::AssertMessage::GeneratorResumedAfterPanic => (), } } } @@ -406,7 +418,8 @@ for mir::AggregateKind<'tcx> { substs.hash_stable(hcx, hasher); active_field.hash_stable(hcx, hasher); } - mir::AggregateKind::Closure(def_id, ref substs) => { + mir::AggregateKind::Closure(def_id, ref substs) | + mir::AggregateKind::Generator(def_id, ref substs) => { def_id.hash_stable(hcx, hasher); substs.hash_stable(hcx, hasher); } diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index 3e227872848ef..22f202a35ecf7 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -142,6 +142,12 @@ for ty::UpvarCapture<'tcx> { } } +impl_stable_hash_for!(struct ty::GenSig<'tcx> { + impl_arg_ty, + suspend_ty, + return_ty +}); + impl_stable_hash_for!(struct ty::FnSig<'tcx> { inputs_and_output, variadic, @@ -315,6 +321,8 @@ for ::middle::const_val::ConstVal<'tcx> { impl_stable_hash_for!(struct ty::ClosureSubsts<'tcx> { substs }); +impl_stable_hash_for!(tuple_struct ty::GeneratorInterior<'tcx> { ty }); + impl_stable_hash_for!(struct ty::GenericPredicates<'tcx> { parent, predicates @@ -541,6 +549,12 @@ for ty::TypeVariants<'tcx> def_id.hash_stable(hcx, hasher); closure_substs.hash_stable(hcx, hasher); } + TyGenerator(def_id, closure_substs, interior) + => { + def_id.hash_stable(hcx, hasher); + closure_substs.hash_stable(hcx, hasher); + interior.hash_stable(hcx, hasher); + } TyTuple(inner_tys, from_diverging_type_var) => { inner_tys.hash_stable(hcx, hasher); from_diverging_type_var.hash_stable(hcx, hasher); @@ -620,6 +634,8 @@ for ty::TypeckTables<'tcx> { ref upvar_capture_map, ref closure_tys, ref closure_kinds, + ref generator_interiors, + ref generator_sigs, ref liberated_fn_sigs, ref fru_field_types, @@ -650,6 +666,8 @@ for ty::TypeckTables<'tcx> { ich::hash_stable_nodemap(hcx, hasher, closure_tys); ich::hash_stable_nodemap(hcx, hasher, closure_kinds); + ich::hash_stable_nodemap(hcx, hasher, generator_interiors); + ich::hash_stable_nodemap(hcx, hasher, generator_sigs); ich::hash_stable_nodemap(hcx, hasher, liberated_fn_sigs); ich::hash_stable_nodemap(hcx, hasher, fru_field_types); ich::hash_stable_nodemap(hcx, hasher, cast_kinds); diff --git a/src/librustc/infer/error_reporting/need_type_info.rs b/src/librustc/infer/error_reporting/need_type_info.rs index a684881c0912a..a4b83af194d04 100644 --- a/src/librustc/infer/error_reporting/need_type_info.rs +++ b/src/librustc/infer/error_reporting/need_type_info.rs @@ -16,6 +16,7 @@ use ty::{self, Ty, TyInfer, TyVar}; use syntax::ast::NodeId; use syntax_pos::Span; +use syntax_pos::DUMMY_SP; struct FindLocalByTypeVisitor<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, @@ -23,6 +24,7 @@ struct FindLocalByTypeVisitor<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { hir_map: &'a hir::map::Map<'gcx>, found_local_pattern: Option<&'gcx Pat>, found_arg_pattern: Option<&'gcx Pat>, + found_impl_arg: bool, } impl<'a, 'gcx, 'tcx> FindLocalByTypeVisitor<'a, 'gcx, 'tcx> { @@ -68,6 +70,11 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for FindLocalByTypeVisitor<'a, 'gcx, 'tcx> { self.found_arg_pattern = Some(&*argument.pat); } } + if let Some(ref impl_arg) = body.impl_arg { + if !self.found_impl_arg && self.node_matches_type(impl_arg.id) { + self.found_impl_arg = true; + } + } intravisit::walk_body(self, body); } } @@ -101,6 +108,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { hir_map: &self.tcx.hir, found_local_pattern: None, found_arg_pattern: None, + found_impl_arg: false, }; if let Some(body_id) = body_id { @@ -137,6 +145,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } } + if local_visitor.found_impl_arg { + labels.push((DUMMY_SP, format!("consider giving a type to the implicit generator argument"))); + } + let mut err = struct_span_err!(self.tcx.sess, err_span, E0282, diff --git a/src/librustc/infer/freshen.rs b/src/librustc/infer/freshen.rs index 41858088f7e70..b8b5a55f57806 100644 --- a/src/librustc/infer/freshen.rs +++ b/src/librustc/infer/freshen.rs @@ -166,6 +166,7 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for TypeFreshener<'a, 'gcx, 'tcx> { ty::TyFnPtr(_) | ty::TyDynamic(..) | ty::TyClosure(..) | + ty::TyGenerator(..) | ty::TyNever | ty::TyTuple(..) | ty::TyProjection(..) | diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 7154ce9e38f5e..59fab366eaf49 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -992,6 +992,25 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { self.next_region_var(EarlyBoundRegion(span, def.name, def.issue_32330)) } + pub fn type_var_for_impl_arg(&self, + span: Span, + def_id: DefId) + -> Ty<'tcx> { + let default = Some(type_variable::Default { + ty: self.tcx.mk_nil(), + origin_span: span, + def_id: def_id, + }); + + let ty_var_id = self.type_variables + .borrow_mut() + .new_var(false, + TypeVariableOrigin::TypeInference(span), + default); + + self.tcx.mk_var(ty_var_id) + } + /// Create a type inference variable for the given /// type parameter definition. The substitutions are /// for actual parameters that may be referred to by @@ -1362,6 +1381,18 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { self.tcx.fn_sig(def_id) } + + pub fn generator_sig(&self, def_id: DefId) -> Option> { + if let Some(tables) = self.in_progress_tables { + if let Some(id) = self.tcx.hir.as_local_node_id(def_id) { + if let Some(&ty) = tables.borrow().generator_sigs.get(&id) { + return ty.map(|t| ty::Binder(t)); + } + } + } + + self.tcx.generator_sig(def_id) + } } impl<'a, 'gcx, 'tcx> TypeTrace<'tcx> { diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 259bd4f099915..945b612027b9e 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -517,13 +517,19 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { self.consume_expr(&base); } - hir::ExprClosure(.., fn_decl_span) => { + hir::ExprClosure(.., fn_decl_span, _) => { self.walk_captures(expr, fn_decl_span) } hir::ExprBox(ref base) => { self.consume_expr(&base); } + + hir::ExprSuspend(ref value) => { + self.consume_expr(&value); + } + + hir::ExprImplArg(_) => { } } } diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs index 01ed79096b101..a36828ffcc93c 100644 --- a/src/librustc/middle/lang_items.rs +++ b/src/librustc/middle/lang_items.rs @@ -315,6 +315,9 @@ language_item_table! { FnMutTraitLangItem, "fn_mut", fn_mut_trait; FnOnceTraitLangItem, "fn_once", fn_once_trait; + GeneratorStateLangItem, "generator_state", gen_state; + GeneratorTraitLangItem, "generator", gen_trait; + EqTraitLangItem, "eq", eq_trait; OrdTraitLangItem, "ord", ord_trait; diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index 551a550442b3d..1487ae5908e5d 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -249,6 +249,7 @@ struct LocalInfo { #[derive(Copy, Clone, Debug)] enum VarKind { + ImplArg(NodeId), Arg(NodeId, ast::Name), Local(LocalInfo), CleanExit @@ -304,7 +305,7 @@ impl<'a, 'tcx> IrMaps<'a, 'tcx> { self.num_vars += 1; match vk { - Local(LocalInfo { id: node_id, .. }) | Arg(node_id, _) => { + Local(LocalInfo { id: node_id, .. }) | Arg(node_id, _) | ImplArg(node_id) => { self.variable_map.insert(node_id, v); }, CleanExit => {} @@ -329,6 +330,7 @@ impl<'a, 'tcx> IrMaps<'a, 'tcx> { Local(LocalInfo { name, .. }) | Arg(_, name) => { name.to_string() }, + ImplArg(_) => "".to_string(), CleanExit => "".to_string() } } @@ -365,6 +367,10 @@ fn visit_fn<'a, 'tcx: 'a>(ir: &mut IrMaps<'a, 'tcx>, }) }; + if let Some(ref impl_arg) = body.impl_arg { + fn_maps.add_variable(ImplArg(impl_arg.id)); + } + // gather up the various local variables, significant expressions, // and so forth: intravisit::walk_fn(&mut fn_maps, fk, decl, body_id, sp, id); @@ -417,6 +423,10 @@ fn visit_expr<'a, 'tcx>(ir: &mut IrMaps<'a, 'tcx>, expr: &'tcx Expr) { } intravisit::walk_expr(ir, expr); } + hir::ExprImplArg(_) => { + ir.add_live_node_for_node(expr.id, ExprNode(expr.span)); + intravisit::walk_expr(ir, expr); + } hir::ExprClosure(..) => { // Interesting control flow (for loops can contain labeled // breaks or continues) @@ -460,7 +470,7 @@ fn visit_expr<'a, 'tcx>(ir: &mut IrMaps<'a, 'tcx>, expr: &'tcx Expr) { hir::ExprAgain(_) | hir::ExprLit(_) | hir::ExprRet(..) | hir::ExprBlock(..) | hir::ExprAssign(..) | hir::ExprAssignOp(..) | hir::ExprStruct(..) | hir::ExprRepeat(..) | - hir::ExprInlineAsm(..) | hir::ExprBox(..) | + hir::ExprInlineAsm(..) | hir::ExprBox(..) | hir::ExprSuspend(..) | hir::ExprType(..) | hir::ExprPath(hir::QPath::TypeRelative(..)) => { intravisit::walk_expr(ir, expr); } @@ -881,6 +891,9 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { match expr.node { // Interesting cases with control flow or which gen/kill + hir::ExprImplArg(arg_id) => { + self.access_var(expr.id, arg_id, succ, ACC_READ | ACC_USE, expr.span) + } hir::ExprPath(hir::QPath::Resolved(_, ref path)) => { self.access_path(expr.id, path, succ, ACC_READ | ACC_USE) @@ -894,7 +907,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { self.propagate_through_expr(&e, succ) } - hir::ExprClosure(.., blk_id, _) => { + hir::ExprClosure(.., blk_id, _, _) => { debug!("{} is an ExprClosure", self.ir.tcx.hir.node_to_pretty_string(expr.id)); /* @@ -1116,6 +1129,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { hir::ExprCast(ref e, _) | hir::ExprType(ref e, _) | hir::ExprUnary(_, ref e) | + hir::ExprSuspend(ref e) | hir::ExprRepeat(ref e, _) => { self.propagate_through_expr(&e, succ) } @@ -1212,6 +1226,9 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { fn write_lvalue(&mut self, expr: &Expr, succ: LiveNode, acc: u32) -> LiveNode { match expr.node { + hir::ExprImplArg(arg_id) => { + self.access_var(expr.id, arg_id, succ, acc, expr.span) + } hir::ExprPath(hir::QPath::Resolved(_, ref path)) => { self.access_path(expr.id, path, succ, acc) } @@ -1224,18 +1241,23 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { } } + fn access_var(&mut self, id: NodeId, nid: NodeId, succ: LiveNode, acc: u32, span: Span) + -> LiveNode { + let ln = self.live_node(id, span); + if acc != 0 { + self.init_from_succ(ln, succ); + let var = self.variable(nid, span); + self.acc(ln, var, acc); + } + ln + } + fn access_path(&mut self, id: NodeId, path: &hir::Path, succ: LiveNode, acc: u32) -> LiveNode { match path.def { Def::Local(def_id) => { let nid = self.ir.tcx.hir.as_local_node_id(def_id).unwrap(); - let ln = self.live_node(id, path.span); - if acc != 0 { - self.init_from_succ(ln, succ); - let var = self.variable(nid, path.span); - self.acc(ln, var, acc); - } - ln + self.access_var(id, nid, succ, acc, path.span) } _ => succ } @@ -1397,8 +1419,8 @@ fn check_expr<'a, 'tcx>(this: &mut Liveness<'a, 'tcx>, expr: &'tcx Expr) { hir::ExprCast(..) | hir::ExprUnary(..) | hir::ExprRet(..) | hir::ExprBreak(..) | hir::ExprAgain(..) | hir::ExprLit(_) | hir::ExprBlock(..) | hir::ExprAddrOf(..) | - hir::ExprStruct(..) | hir::ExprRepeat(..) | - hir::ExprClosure(..) | hir::ExprPath(_) | + hir::ExprStruct(..) | hir::ExprRepeat(..) | hir::ExprImplArg(_) | + hir::ExprClosure(..) | hir::ExprPath(_) | hir::ExprSuspend(..) | hir::ExprBox(..) | hir::ExprType(..) => { intravisit::walk_expr(this, expr); } @@ -1420,6 +1442,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { self.warn_about_dead_assign(expr.span, expr.id, ln, var); } } + hir::ExprImplArg(_) => bug!(), _ => { // For other kinds of lvalues, no checks are required, // and any embedded expressions are actually rvalues diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 557d4b24f3032..bf5263e75da28 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -602,6 +602,17 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { self.cat_def(expr.id, expr.span, expr_ty, def) } + hir::ExprImplArg(id) => { + Ok(Rc::new(cmt_ { + id: expr.id, + span: expr.span, + cat: Categorization::Local(id), + mutbl: MutabilityCategory::McDeclared, + ty: expr_ty, + note: NoteNone + })) + }, + hir::ExprType(ref e, _) => { self.cat_expr(&e) } @@ -609,7 +620,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { hir::ExprAddrOf(..) | hir::ExprCall(..) | hir::ExprAssign(..) | hir::ExprAssignOp(..) | hir::ExprClosure(..) | hir::ExprRet(..) | - hir::ExprUnary(..) | + hir::ExprUnary(..) | hir::ExprSuspend(..) | hir::ExprMethodCall(..) | hir::ExprCast(..) | hir::ExprArray(..) | hir::ExprTup(..) | hir::ExprIf(..) | hir::ExprBinary(..) | hir::ExprWhile(..) | @@ -703,7 +714,13 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { let kind = match self.tables.closure_kinds.get(&fn_node_id) { Some(&(kind, _)) => kind, - None => span_bug!(span, "missing closure kind") + None => { + let ty = self.node_ty(fn_node_id)?; + match ty.sty { + ty::TyGenerator(..) => ty::ClosureKind::FnOnce, + _ => span_bug!(span, "missing closure kind"), + } + } }; let upvar_id = ty::UpvarId { var_id, diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index 6455d7ecf85ae..2e4d7b3b722da 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -32,6 +32,7 @@ use hir; use hir::def_id::DefId; use hir::intravisit::{self, Visitor, NestedVisitorMap}; use hir::{Block, Arm, Pat, PatKind, Stmt, Expr, Local}; +use hir::map::Node; use mir::transform::MirSource; /// CodeExtent represents a statically-describable extent that can be @@ -789,7 +790,7 @@ fn resolve_expr<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, expr: match expr.node { // Manually recurse over closures, because they are the only // case of nested bodies that share the parent environment. - hir::ExprClosure(.., body, _) => { + hir::ExprClosure(.., body, _, _) => { let body = visitor.tcx.hir.body(body); visitor.visit_body(body); } @@ -1071,7 +1072,10 @@ impl<'a, 'tcx> Visitor<'tcx> for RegionResolutionVisitor<'a, 'tcx> { for argument in &body.arguments { self.visit_pat(&argument.pat); } - + if let Some(ref impl_arg) = body.impl_arg { + record_var_lifetime(self, impl_arg.id, impl_arg.span); + } + // The body of the every fn is a root scope. self.cx.parent = self.cx.var_parent; self.visit_expr(&body.value); @@ -1142,6 +1146,66 @@ fn region_maps<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) Rc::new(maps) } +struct YieldFinder(bool); + +impl<'tcx> Visitor<'tcx> for YieldFinder { + fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> { + NestedVisitorMap::None + } + + fn visit_body(&mut self, _body: &'tcx hir::Body) { + // Closures don't execute + } + + fn visit_expr(&mut self, expr: &'tcx hir::Expr) { + if let hir::ExprSuspend(..) = expr.node { + self.0 = true; + } + + intravisit::walk_expr(self, expr); + } +} + +pub fn extent_has_yield<'a, 'gcx: 'a+'tcx, 'tcx: 'a>(tcx: TyCtxt<'a, 'gcx, 'tcx>, extent: CodeExtent) -> bool { + let mut finder = YieldFinder(false); + + match extent { + CodeExtent::DestructionScope(node_id) | + CodeExtent::Misc(node_id) => { + match tcx.hir.get(node_id) { + Node::NodeItem(_) | + Node::NodeTraitItem(_) | + Node::NodeImplItem(_) => { + let body = tcx.hir.body(tcx.hir.body_owned_by(node_id)); + intravisit::walk_body(&mut finder, body); + } + Node::NodeExpr(expr) => intravisit::walk_expr(&mut finder, expr), + Node::NodeStmt(stmt) => intravisit::walk_stmt(&mut finder, stmt), + Node::NodeBlock(block) => intravisit::walk_block(&mut finder, block), + _ => bug!(), + } + } + + CodeExtent::CallSiteScope(body_id) | + CodeExtent::ParameterScope(body_id) => { + intravisit::walk_body(&mut finder, tcx.hir.body(body_id)) + } + + CodeExtent::Remainder(r) => { + if let Node::NodeBlock(block) = tcx.hir.get(r.block) { + for stmt in &block.stmts[(r.first_statement_index as usize + 1)..] { + intravisit::walk_stmt(&mut finder, stmt); + } + block.expr.as_ref().map(|e| intravisit::walk_expr(&mut finder, e)); + } else { + bug!() + } + } + } + + finder.0 +} + pub fn provide(providers: &mut Providers) { *providers = Providers { region_maps, diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index d78e17ce03cef..fe85bb1b6f782 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -104,6 +104,15 @@ pub struct Mir<'tcx> { /// Return type of the function. pub return_ty: Ty<'tcx>, + /// Suspend type of the function, if it is a generator. + pub suspend_ty: Option>, + + /// Generator drop glue + pub generator_drop: Option>>, + + /// The layout of a generator. Produced by the state transformation. + pub generator_layout: Option>, + /// Declarations of locals. /// /// The first local is the return value pointer, followed by `arg_count` @@ -144,6 +153,7 @@ impl<'tcx> Mir<'tcx> { visibility_scopes: IndexVec, promoted: IndexVec>, return_ty: Ty<'tcx>, + suspend_ty: Option>, local_decls: IndexVec>, arg_count: usize, upvar_decls: Vec, @@ -159,6 +169,9 @@ impl<'tcx> Mir<'tcx> { visibility_scopes, promoted, return_ty, + suspend_ty, + generator_drop: None, + generator_layout: None, local_decls, arg_count, upvar_decls, @@ -168,6 +181,10 @@ impl<'tcx> Mir<'tcx> { } } + pub fn impl_arg_lvalue() -> Lvalue<'tcx> { + Lvalue::Local(Local::new(1)) + } + #[inline] pub fn basic_blocks(&self) -> &IndexVec> { &self.basic_blocks @@ -270,6 +287,9 @@ impl_stable_hash_for!(struct Mir<'tcx> { visibility_scopes, promoted, return_ty, + suspend_ty, + generator_drop, + generator_layout, local_decls, arg_count, upvar_decls, @@ -567,7 +587,20 @@ pub enum TerminatorKind<'tcx> { msg: AssertMessage<'tcx>, target: BasicBlock, cleanup: Option - } + }, + + /// A suspend point + Suspend { + /// The value to return + value: Operand<'tcx>, + /// Where to resume to + resume: BasicBlock, + /// Cleanup to be done if the generator is dropped at this suspend point + drop: Option, + }, + + /// Indicates the end of the dropping of a generator + GeneratorDrop, } impl<'tcx> Terminator<'tcx> { @@ -597,7 +630,7 @@ impl<'tcx> TerminatorKind<'tcx> { match *self { Goto { target: ref b } => slice::ref_slice(b).into_cow(), SwitchInt { targets: ref b, .. } => b[..].into_cow(), - Resume => (&[]).into_cow(), + Resume | GeneratorDrop => (&[]).into_cow(), Return => (&[]).into_cow(), Unreachable => (&[]).into_cow(), Call { destination: Some((_, t)), cleanup: Some(c), .. } => vec![t, c].into_cow(), @@ -605,6 +638,8 @@ impl<'tcx> TerminatorKind<'tcx> { slice::ref_slice(t).into_cow(), Call { destination: None, cleanup: Some(ref c), .. } => slice::ref_slice(c).into_cow(), Call { destination: None, cleanup: None, .. } => (&[]).into_cow(), + Suspend { resume: t, drop: Some(c), .. } => vec![t, c].into_cow(), + Suspend { resume: ref t, drop: None, .. } => slice::ref_slice(t).into_cow(), DropAndReplace { target, unwind: Some(unwind), .. } | Drop { target, unwind: Some(unwind), .. } => { vec![target, unwind].into_cow() @@ -625,13 +660,15 @@ impl<'tcx> TerminatorKind<'tcx> { match *self { Goto { target: ref mut b } => vec![b], SwitchInt { targets: ref mut b, .. } => b.iter_mut().collect(), - Resume => Vec::new(), + Resume | GeneratorDrop => Vec::new(), Return => Vec::new(), Unreachable => Vec::new(), Call { destination: Some((_, ref mut t)), cleanup: Some(ref mut c), .. } => vec![t, c], Call { destination: Some((_, ref mut t)), cleanup: None, .. } => vec![t], Call { destination: None, cleanup: Some(ref mut c), .. } => vec![c], Call { destination: None, cleanup: None, .. } => vec![], + Suspend { resume: ref mut t, drop: Some(ref mut c), .. } => vec![t, c], + Suspend { resume: ref mut t, drop: None, .. } => vec![t], DropAndReplace { ref mut target, unwind: Some(ref mut unwind), .. } | Drop { ref mut target, unwind: Some(ref mut unwind), .. } => vec![target, unwind], DropAndReplace { ref mut target, unwind: None, .. } | @@ -664,6 +701,14 @@ impl<'tcx> BasicBlockData<'tcx> { pub fn terminator_mut(&mut self) -> &mut Terminator<'tcx> { self.terminator.as_mut().expect("invalid terminator state") } + + pub fn retain_statements(&mut self, mut f: F) where F: FnMut(&mut Statement) -> bool { + for s in &mut self.statements { + if !f(s) { + s.kind = StatementKind::Nop; + } + } + } } impl<'tcx> Debug for TerminatorKind<'tcx> { @@ -703,7 +748,9 @@ impl<'tcx> TerminatorKind<'tcx> { Goto { .. } => write!(fmt, "goto"), SwitchInt { discr: ref lv, .. } => write!(fmt, "switchInt({:?})", lv), Return => write!(fmt, "return"), + GeneratorDrop => write!(fmt, "generator_drop"), Resume => write!(fmt, "resume"), + Suspend { ref value, .. } => write!(fmt, "_1 = suspend({:?})", value), Unreachable => write!(fmt, "unreachable"), Drop { ref location, .. } => write!(fmt, "drop({:?})", location), DropAndReplace { ref location, ref value, .. } => @@ -737,6 +784,12 @@ impl<'tcx> TerminatorKind<'tcx> { AssertMessage::Math(ref err) => { write!(fmt, "{:?}", err.description())?; } + AssertMessage::GeneratorResumedAfterReturn => { + write!(fmt, "{:?}", "generator resumed after completion")?; + } + AssertMessage::GeneratorResumedAfterPanic => { + write!(fmt, "{:?}", "generator resumed after panicking")?; + } } write!(fmt, ")") @@ -748,7 +801,7 @@ impl<'tcx> TerminatorKind<'tcx> { pub fn fmt_successor_labels(&self) -> Vec> { use self::TerminatorKind::*; match *self { - Return | Resume | Unreachable => vec![], + Return | Resume | Unreachable | GeneratorDrop => vec![], Goto { .. } => vec!["".into()], SwitchInt { ref values, .. } => { values.iter() @@ -765,6 +818,9 @@ impl<'tcx> TerminatorKind<'tcx> { Call { destination: Some(_), cleanup: None, .. } => vec!["return".into_cow()], Call { destination: None, cleanup: Some(_), .. } => vec!["unwind".into_cow()], Call { destination: None, cleanup: None, .. } => vec![], + Suspend { drop: Some(_), .. } => + vec!["resume".into_cow(), "drop".into_cow()], + Suspend { drop: None, .. } => vec!["resume".into_cow()], DropAndReplace { unwind: None, .. } | Drop { unwind: None, .. } => vec!["return".into_cow()], DropAndReplace { unwind: Some(_), .. } | @@ -784,7 +840,9 @@ pub enum AssertMessage<'tcx> { len: Operand<'tcx>, index: Operand<'tcx> }, - Math(ConstMathErr) + Math(ConstMathErr), + GeneratorResumedAfterReturn, + GeneratorResumedAfterPanic, } /////////////////////////////////////////////////////////////////////////// @@ -1120,6 +1178,7 @@ pub enum AggregateKind<'tcx> { /// number and is present only for union expressions. Adt(&'tcx AdtDef, usize, &'tcx Substs<'tcx>, Option), Closure(DefId, ClosureSubsts<'tcx>), + Generator(DefId, ClosureSubsts<'tcx>), } #[derive(Copy, Clone, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable)] @@ -1281,6 +1340,30 @@ impl<'tcx> Debug for Rvalue<'tcx> { write!(fmt, "[closure]") } }), + + AggregateKind::Generator(def_id, _) => ty::tls::with(|tcx| { + if let Some(node_id) = tcx.hir.as_local_node_id(def_id) { + let name = format!("[generator@{:?}]", tcx.hir.span(node_id)); + let mut struct_fmt = fmt.debug_struct(&name); + + tcx.with_freevars(node_id, |freevars| { + for (freevar, lv) in freevars.iter().zip(lvs) { + let def_id = freevar.def.def_id(); + let var_id = tcx.hir.as_local_node_id(def_id).unwrap(); + let var_name = tcx.local_var_name_str(var_id); + struct_fmt.field(&var_name, lv); + } + struct_fmt.field("$state", &lvs[freevars.len()]); + for i in (freevars.len() + 1)..lvs.len() { + struct_fmt.field(&format!("${}", i - freevars.len() - 1), &lvs[i]); + } + }); + + struct_fmt.finish() + } else { + write!(fmt, "[generator]") + } + }), } } } @@ -1425,6 +1508,11 @@ impl Location { } } +/// The layout of generator state +#[derive(Clone, Debug, RustcEncodable, RustcDecodable)] +pub struct GeneratorLayout<'tcx> { + pub fields: Vec>, +} /* * TypeFoldable implementations for MIR types @@ -1437,6 +1525,9 @@ impl<'tcx> TypeFoldable<'tcx> for Mir<'tcx> { visibility_scopes: self.visibility_scopes.clone(), promoted: self.promoted.fold_with(folder), return_ty: self.return_ty.fold_with(folder), + suspend_ty: self.suspend_ty.fold_with(folder), + generator_drop: self.generator_drop.fold_with(folder), + generator_layout: self.generator_layout.fold_with(folder), local_decls: self.local_decls.fold_with(folder), arg_count: self.arg_count, upvar_decls: self.upvar_decls.clone(), @@ -1448,12 +1539,27 @@ impl<'tcx> TypeFoldable<'tcx> for Mir<'tcx> { fn super_visit_with>(&self, visitor: &mut V) -> bool { self.basic_blocks.visit_with(visitor) || + self.generator_drop.visit_with(visitor) || + self.generator_layout.visit_with(visitor) || + self.suspend_ty.visit_with(visitor) || self.promoted.visit_with(visitor) || self.return_ty.visit_with(visitor) || self.local_decls.visit_with(visitor) } } +impl<'tcx> TypeFoldable<'tcx> for GeneratorLayout<'tcx> { + fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { + GeneratorLayout { + fields: self.fields.fold_with(folder), + } + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + self.fields.visit_with(visitor) + } +} + impl<'tcx> TypeFoldable<'tcx> for LocalDecl<'tcx> { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { LocalDecl { @@ -1558,6 +1664,11 @@ impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> { target, unwind, }, + Suspend { ref value, resume, drop } => Suspend { + value: value.fold_with(folder), + resume: resume, + drop: drop, + }, Call { ref func, ref args, ref destination, cleanup } => { let dest = destination.as_ref().map(|&(ref loc, dest)| { (loc.fold_with(folder), dest) @@ -1587,6 +1698,7 @@ impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> { cleanup, } }, + GeneratorDrop => GeneratorDrop, Resume => Resume, Return => Return, Unreachable => Unreachable, @@ -1606,6 +1718,8 @@ impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> { Drop { ref location, ..} => location.visit_with(visitor), DropAndReplace { ref location, ref value, ..} => location.visit_with(visitor) || value.visit_with(visitor), + Suspend { ref value, ..} => + value.visit_with(visitor), Call { ref func, ref args, ref destination, .. } => { let dest = if let Some((ref loc, _)) = *destination { loc.visit_with(visitor) @@ -1626,6 +1740,7 @@ impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> { Goto { .. } | Resume | Return | + GeneratorDrop | Unreachable => false } } @@ -1671,7 +1786,9 @@ impl<'tcx> TypeFoldable<'tcx> for Rvalue<'tcx> { AggregateKind::Adt(def, v, substs, n) => AggregateKind::Adt(def, v, substs.fold_with(folder), n), AggregateKind::Closure(id, substs) => - AggregateKind::Closure(id, substs.fold_with(folder)) + AggregateKind::Closure(id, substs.fold_with(folder)), + AggregateKind::Generator(id, substs) => + AggregateKind::Generator(id, substs.fold_with(folder)), }; Aggregate(kind, fields.fold_with(folder)) } @@ -1697,7 +1814,8 @@ impl<'tcx> TypeFoldable<'tcx> for Rvalue<'tcx> { AggregateKind::Array(ty) => ty.visit_with(visitor), AggregateKind::Tuple => false, AggregateKind::Adt(_, _, substs, _) => substs.visit_with(visitor), - AggregateKind::Closure(_, substs) => substs.visit_with(visitor) + AggregateKind::Closure(_, substs) => substs.visit_with(visitor), + AggregateKind::Generator(_, substs) => substs.visit_with(visitor), }) || fields.visit_with(visitor) } } diff --git a/src/librustc/mir/tcx.rs b/src/librustc/mir/tcx.rs index 1af80771fb952..252cf3e4f8064 100644 --- a/src/librustc/mir/tcx.rs +++ b/src/librustc/mir/tcx.rs @@ -202,6 +202,11 @@ impl<'tcx> Rvalue<'tcx> { AggregateKind::Closure(did, substs) => { tcx.mk_closure_from_closure_substs(did, substs) } + AggregateKind::Generator(did, substs) => { + let node_id = tcx.hir.as_local_node_id(did).unwrap(); + let interior = *tcx.typeck_tables_of(did).generator_interiors.get(&node_id).unwrap(); + tcx.mk_generator(did, substs, interior.subst(tcx, substs.substs)) + } } } } diff --git a/src/librustc/mir/transform.rs b/src/librustc/mir/transform.rs index aa91123ef6952..f29405e665051 100644 --- a/src/librustc/mir/transform.rs +++ b/src/librustc/mir/transform.rs @@ -33,7 +33,10 @@ pub enum MirSource { Static(NodeId, hir::Mutability), /// Promoted rvalues within a function. - Promoted(NodeId, Promoted) + Promoted(NodeId, Promoted), + + /// Drop glue for a generator. + GeneratorDrop(NodeId), } impl<'a, 'tcx> MirSource { @@ -70,6 +73,7 @@ impl<'a, 'tcx> MirSource { match *self { MirSource::Fn(id) | MirSource::Const(id) | + MirSource::GeneratorDrop(id) | MirSource::Static(id, _) | MirSource::Promoted(id, _) => id } diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs index ac1c0306f701c..6032dad46eb03 100644 --- a/src/librustc/mir/visit.rs +++ b/src/librustc/mir/visit.rs @@ -247,6 +247,10 @@ macro_rules! make_mir_visitor { self.super_local_decl(local_decl); } + fn visit_local(&mut self, + _local: & $($mutability)* Local) { + } + fn visit_visibility_scope(&mut self, scope: & $($mutability)* VisibilityScope) { self.super_visibility_scope(scope); @@ -395,7 +399,8 @@ macro_rules! make_mir_visitor { } TerminatorKind::Resume | - TerminatorKind::Return | + TerminatorKind::Return | + TerminatorKind::GeneratorDrop | TerminatorKind::Unreachable => { } @@ -442,6 +447,15 @@ macro_rules! make_mir_visitor { self.visit_branch(block, target); cleanup.map(|t| self.visit_branch(block, t)); } + + TerminatorKind::Suspend { ref $($mutability)* value, + resume, + drop } => { + self.visit_operand(value, source_location); + self.visit_branch(block, resume); + drop.map(|t| self.visit_branch(block, t)); + } + } } @@ -456,7 +470,9 @@ macro_rules! make_mir_visitor { self.visit_operand(len, location); self.visit_operand(index, location); } - AssertMessage::Math(_) => {} + AssertMessage::Math(_) => {}, + AssertMessage::GeneratorResumedAfterReturn => {}, + AssertMessage::GeneratorResumedAfterPanic => {}, } } @@ -534,6 +550,11 @@ macro_rules! make_mir_visitor { self.visit_def_id(def_id, location); self.visit_closure_substs(closure_substs); } + AggregateKind::Generator(ref $($mutability)* def_id, + ref $($mutability)* closure_substs) => { + self.visit_def_id(def_id, location); + self.visit_closure_substs(closure_substs); + } } for operand in operands { @@ -561,7 +582,8 @@ macro_rules! make_mir_visitor { context: LvalueContext<'tcx>, location: Location) { match *lvalue { - Lvalue::Local(_) => { + Lvalue::Local(ref $($mutability)* local) => { + self.visit_local(local); } Lvalue::Static(ref $($mutability)* static_) => { self.visit_static(static_, context, location); diff --git a/src/librustc/traits/coherence.rs b/src/librustc/traits/coherence.rs index 34df447a11e15..431bd8ee88f70 100644 --- a/src/librustc/traits/coherence.rs +++ b/src/librustc/traits/coherence.rs @@ -301,7 +301,7 @@ fn ty_is_local_constructor(ty: Ty, infer_is_local: InferIsLocal)-> bool { true } - ty::TyClosure(..) | ty::TyAnon(..) => { + ty::TyClosure(..) | ty::TyGenerator(..) | ty::TyAnon(..) => { bug!("ty_is_local invoked on unexpected type: {:?}", ty) } } diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index c02d1394f6bb5..5248405913869 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -251,6 +251,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { AdtKind::Union => Some(16), AdtKind::Enum => Some(17), }, + ty::TyGenerator(..) => Some(18), ty::TyInfer(..) | ty::TyError => None } } diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index e14203b34a180..e13e25250a135 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -310,6 +310,9 @@ pub enum Vtable<'tcx, N> { /// Same as above, but for a fn pointer type with the given signature. VtableFnPointer(VtableFnPointerData<'tcx, N>), + + /// Vtable automatically generated for a generator + VtableGenerator(VtableGeneratorData<'tcx, N>), } /// Identifies a particular impl in the source, along with a set of @@ -329,6 +332,15 @@ pub struct VtableImplData<'tcx, N> { pub nested: Vec } +#[derive(Clone, PartialEq, Eq)] +pub struct VtableGeneratorData<'tcx, N> { + pub closure_def_id: DefId, + pub substs: ty::ClosureSubsts<'tcx>, + /// Nested obligations. This can be non-empty if the generator + /// signature contains associated types. + pub nested: Vec +} + #[derive(Clone, PartialEq, Eq)] pub struct VtableClosureData<'tcx, N> { pub closure_def_id: DefId, @@ -743,6 +755,7 @@ impl<'tcx, N> Vtable<'tcx, N> { VtableBuiltin(i) => i.nested, VtableDefaultImpl(d) => d.nested, VtableClosure(c) => c.nested, + VtableGenerator(c) => c.nested, VtableObject(d) => d.nested, VtableFnPointer(d) => d.nested, } @@ -754,6 +767,7 @@ impl<'tcx, N> Vtable<'tcx, N> { &mut VtableParam(ref mut n) => n, &mut VtableBuiltin(ref mut i) => &mut i.nested, &mut VtableDefaultImpl(ref mut d) => &mut d.nested, + &mut VtableGenerator(ref mut c) => &mut c.nested, &mut VtableClosure(ref mut c) => &mut c.nested, &mut VtableObject(ref mut d) => &mut d.nested, &mut VtableFnPointer(ref mut d) => &mut d.nested, @@ -784,6 +798,11 @@ impl<'tcx, N> Vtable<'tcx, N> { fn_ty: p.fn_ty, nested: p.nested.into_iter().map(f).collect(), }), + VtableGenerator(c) => VtableGenerator(VtableGeneratorData { + closure_def_id: c.closure_def_id, + substs: c.substs, + nested: c.nested.into_iter().map(f).collect(), + }), VtableClosure(c) => VtableClosure(VtableClosureData { closure_def_id: c.closure_def_id, substs: c.substs, diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs index b5284852747f9..35b8b93581551 100644 --- a/src/librustc/traits/project.rs +++ b/src/librustc/traits/project.rs @@ -19,6 +19,7 @@ use super::PredicateObligation; use super::SelectionContext; use super::SelectionError; use super::VtableClosureData; +use super::VtableGeneratorData; use super::VtableFnPointerData; use super::VtableImplData; use super::util; @@ -884,6 +885,7 @@ fn assemble_candidates_from_impls<'cx, 'gcx, 'tcx>( match vtable { super::VtableClosure(_) | + super::VtableGenerator(_) | super::VtableFnPointer(_) | super::VtableObject(_) => { debug!("assemble_candidates_from_impls: vtable={:?}", @@ -1043,6 +1045,8 @@ fn confirm_select_candidate<'cx, 'gcx, 'tcx>( match vtable { super::VtableImpl(data) => confirm_impl_candidate(selcx, obligation, data), + super::VtableGenerator(data) => + confirm_generator_candidate(selcx, obligation, data), super::VtableClosure(data) => confirm_closure_candidate(selcx, obligation, data), super::VtableFnPointer(data) => @@ -1125,6 +1129,60 @@ fn confirm_object_candidate<'cx, 'gcx, 'tcx>( confirm_param_env_candidate(selcx, obligation, env_predicate) } +fn confirm_generator_candidate<'cx, 'gcx, 'tcx>( + selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>, + obligation: &ProjectionTyObligation<'tcx>, + vtable: VtableGeneratorData<'tcx, PredicateObligation<'tcx>>) + -> Progress<'tcx> +{ + let gen_sig = selcx.infcx().generator_sig(vtable.closure_def_id).unwrap() + .subst(selcx.tcx(), vtable.substs.substs); + let Normalized { + value: gen_sig, + obligations + } = normalize_with_depth(selcx, + obligation.param_env, + obligation.cause.clone(), + obligation.recursion_depth+1, + &gen_sig); + + debug!("confirm_generator_candidate: obligation={:?},gen_sig={:?},obligations={:?}", + obligation, + gen_sig, + obligations); + + let tcx = selcx.tcx(); + + let gen_def_id = tcx.lang_items.gen_trait().unwrap(); + + // Note: we unwrap the binder here but re-create it below (1) + let ty::Binder((trait_ref, suspend_ty, return_ty)) = + tcx.generator_trait_ref_and_outputs(gen_def_id, + obligation.predicate.trait_ref.self_ty(), + gen_sig); + + let name = obligation.predicate.item_name(tcx); + let ty = if name == Symbol::intern("Return") { + return_ty + } else if name == Symbol::intern("Yield") { + suspend_ty + } else { + bug!() + }; + + let predicate = ty::Binder(ty::ProjectionPredicate { // (1) recreate binder here + projection_ty: ty::ProjectionTy { + trait_ref: trait_ref, + item_def_id: obligation.predicate.item_def_id, + }, + ty: ty + }); + + confirm_param_env_candidate(selcx, obligation, predicate) + .with_addl_obligations(vtable.nested) + .with_addl_obligations(obligations) +} + fn confirm_fn_pointer_candidate<'cx, 'gcx, 'tcx>( selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>, obligation: &ProjectionTyObligation<'tcx>, diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index c690bebed8c00..dc12bf100ecd6 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -24,9 +24,9 @@ use super::{ObjectCastObligation, Obligation}; use super::TraitNotObjectSafe; use super::Selection; use super::SelectionResult; -use super::{VtableBuiltin, VtableImpl, VtableParam, VtableClosure, +use super::{VtableBuiltin, VtableImpl, VtableParam, VtableClosure, VtableGenerator, VtableFnPointer, VtableObject, VtableDefaultImpl}; -use super::{VtableImplData, VtableObjectData, VtableBuiltinData, +use super::{VtableImplData, VtableObjectData, VtableBuiltinData, VtableGeneratorData, VtableClosureData, VtableDefaultImplData, VtableFnPointerData}; use super::util; @@ -43,6 +43,7 @@ use middle::lang_items; use rustc_data_structures::bitvec::BitVector; use rustc_data_structures::snapshot_vec::{SnapshotVecDelegate, SnapshotVec}; +use std::iter; use std::cell::RefCell; use std::cmp; use std::fmt; @@ -197,6 +198,10 @@ enum SelectionCandidate<'tcx> { /// confirmation step what ClosureKind obligation to emit. ClosureCandidate(/* closure */ DefId, ty::ClosureSubsts<'tcx>, ty::ClosureKind), + /// Implementation of a `Generator` trait by one of the anonymous types + /// generated for a generator. + GeneratorCandidate(/* function / closure */ DefId, ty::ClosureSubsts<'tcx>), + /// Implementation of a `Fn`-family trait by one of the anonymous /// types generated for a fn pointer type (e.g., `fn(int)->int`) FnPointerCandidate, @@ -228,6 +233,11 @@ impl<'a, 'tcx> ty::Lift<'tcx> for SelectionCandidate<'a> { ParamCandidate(ref trait_ref) => { return tcx.lift(trait_ref).map(ParamCandidate); } + GeneratorCandidate(def_id, ref substs) => { + return tcx.lift(substs).map(|substs| { + GeneratorCandidate(def_id, substs) + }); + } ClosureCandidate(def_id, ref substs, kind) => { return tcx.lift(substs).map(|substs| { ClosureCandidate(def_id, substs, kind) @@ -1295,6 +1305,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { &mut candidates)?; } else if self.tcx().lang_items.unsize_trait() == Some(def_id) { self.assemble_candidates_for_unsizing(obligation, &mut candidates); + } else if self.tcx().lang_items.gen_trait() == Some(def_id) { + self.assemble_generator_candidates(obligation, &mut candidates)?; } else { self.assemble_closure_candidates(obligation, &mut candidates)?; self.assemble_fn_pointer_candidates(obligation, &mut candidates)?; @@ -1480,6 +1492,31 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { }) } + fn assemble_generator_candidates(&mut self, + obligation: &TraitObligation<'tcx>, + candidates: &mut SelectionCandidateSet<'tcx>) + -> Result<(),SelectionError<'tcx>> + { + let self_ty = *obligation.self_ty().skip_binder(); + let (closure_def_id, substs) = match self_ty.sty { + ty::TyGenerator(id, substs, _) => (id, substs), + ty::TyInfer(ty::TyVar(_)) => { + debug!("assemble_generator_candidates: ambiguous self-type"); + candidates.ambiguous = true; + return Ok(()); + } + _ => { return Ok(()); } + }; + + debug!("assemble_generator_candidates: self_ty={:?} obligation={:?}", + self_ty, + obligation); + + candidates.vec.push(GeneratorCandidate(closure_def_id, substs)); + + Ok(()) + } + /// Check for the artificial impl that the compiler will create for an obligation like `X : /// FnMut<..>` where `X` is a closure type. /// @@ -1848,6 +1885,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { } ImplCandidate(..) | ClosureCandidate(..) | + GeneratorCandidate(..) | FnPointerCandidate | BuiltinObjectCandidate | BuiltinUnsizeCandidate | @@ -1928,7 +1966,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { ty::TyInfer(ty::IntVar(_)) | ty::TyInfer(ty::FloatVar(_)) | ty::TyUint(_) | ty::TyInt(_) | ty::TyBool | ty::TyFloat(_) | ty::TyFnDef(..) | ty::TyFnPtr(_) | ty::TyRawPtr(..) | - ty::TyChar | ty::TyRef(..) | + ty::TyChar | ty::TyRef(..) | ty::TyGenerator(..) | ty::TyArray(..) | ty::TyClosure(..) | ty::TyNever | ty::TyError => { // safe for everything @@ -1980,7 +2018,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { } ty::TyDynamic(..) | ty::TyStr | ty::TySlice(..) | - ty::TyClosure(..) | + ty::TyClosure(..) | ty::TyGenerator(..) | ty::TyRef(_, ty::TypeAndMut { ty: _, mutbl: hir::MutMutable }) => { Never } @@ -2081,6 +2119,11 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { substs.upvar_tys(def_id, self.tcx()).collect() } + ty::TyGenerator(def_id, ref substs, interior) => { + let witness = iter::once(interior.witness()); + substs.upvar_tys(def_id, self.tcx()).chain(witness).collect() + } + // for `PhantomData`, we pass `T` ty::TyAdt(def, substs) if def.is_phantom_data() => { substs.types().collect() @@ -2190,6 +2233,12 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { Ok(VtableClosure(vtable_closure)) } + GeneratorCandidate(closure_def_id, substs) => { + let vtable_generator = + self.confirm_generator_candidate(obligation, closure_def_id, substs)?; + Ok(VtableGenerator(vtable_generator)) + } + BuiltinObjectCandidate => { // This indicates something like `(Trait+Send) : // Send`. In this case, we know that this holds @@ -2518,6 +2567,40 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { Ok(VtableFnPointerData { fn_ty: self_ty, nested: obligations }) } + fn confirm_generator_candidate(&mut self, + obligation: &TraitObligation<'tcx>, + closure_def_id: DefId, + substs: ty::ClosureSubsts<'tcx>) + -> Result>, + SelectionError<'tcx>> + { + debug!("confirm_generator_candidate({:?},{:?},{:?})", + obligation, + closure_def_id, + substs); + + let Normalized { + value: trait_ref, + obligations + } = self.generator_trait_ref(obligation, closure_def_id, substs); + + debug!("confirm_generator_candidate(closure_def_id={:?}, trait_ref={:?}, obligations={:?})", + closure_def_id, + trait_ref, + obligations); + + self.confirm_poly_trait_refs(obligation.cause.clone(), + obligation.param_env, + obligation.predicate.to_poly_trait_ref(), + trait_ref)?; + + Ok(VtableGeneratorData { + closure_def_id: closure_def_id, + substs: substs.clone(), + nested: obligations + }) + } + fn confirm_closure_candidate(&mut self, obligation: &TraitObligation<'tcx>, closure_def_id: DefId, @@ -3019,6 +3102,45 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { &trait_ref) } + fn generator_trait_ref_unnormalized(&mut self, + obligation: &TraitObligation<'tcx>, + closure_def_id: DefId, + substs: ty::ClosureSubsts<'tcx>) + -> ty::PolyTraitRef<'tcx> + { + let gen_sig = self.infcx.generator_sig(closure_def_id).unwrap() + .subst(self.tcx(), substs.substs); + let ty::Binder((trait_ref, ..)) = + self.tcx().generator_trait_ref_and_outputs(obligation.predicate.def_id(), + obligation.predicate.0.self_ty(), // (1) + gen_sig); + // (1) Feels icky to skip the binder here, but OTOH we know + // that the self-type is an generator type and hence is + // in fact unparameterized (or at least does not reference any + // regions bound in the obligation). Still probably some + // refactoring could make this nicer. + + ty::Binder(trait_ref) + } + + fn generator_trait_ref(&mut self, + obligation: &TraitObligation<'tcx>, + closure_def_id: DefId, + substs: ty::ClosureSubsts<'tcx>) + -> Normalized<'tcx, ty::PolyTraitRef<'tcx>> + { + let trait_ref = self.generator_trait_ref_unnormalized( + obligation, closure_def_id, substs); + + // A generator signature can contain associated types which + // must be normalized. + normalize_with_depth(self, + obligation.param_env, + obligation.cause.clone(), + obligation.recursion_depth+1, + &trait_ref) + } + /// Returns the obligations that are implied by instantiating an /// impl or trait. The obligations are substituted and fully /// normalized. This is used when confirming an impl or default diff --git a/src/librustc/traits/structural_impls.rs b/src/librustc/traits/structural_impls.rs index f1c176561ea48..93994329178e7 100644 --- a/src/librustc/traits/structural_impls.rs +++ b/src/librustc/traits/structural_impls.rs @@ -53,6 +53,9 @@ impl<'tcx, N: fmt::Debug> fmt::Debug for traits::Vtable<'tcx, N> { super::VtableClosure(ref d) => write!(f, "{:?}", d), + super::VtableGenerator(ref d) => + write!(f, "{:?}", d), + super::VtableFnPointer(ref d) => write!(f, "VtableFnPointer({:?})", d), @@ -77,6 +80,15 @@ impl<'tcx, N: fmt::Debug> fmt::Debug for traits::VtableImplData<'tcx, N> { } } +impl<'tcx, N: fmt::Debug> fmt::Debug for traits::VtableGeneratorData<'tcx, N> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "VtableGenerator(closure_def_id={:?}, substs={:?}, nested={:?})", + self.closure_def_id, + self.substs, + self.nested) + } +} + impl<'tcx, N: fmt::Debug> fmt::Debug for traits::VtableClosureData<'tcx, N> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "VtableClosure(closure_def_id={:?}, substs={:?}, nested={:?})", @@ -278,6 +290,19 @@ impl<'a, 'tcx> Lift<'tcx> for traits::Vtable<'a, ()> { }) } traits::VtableDefaultImpl(t) => Some(traits::VtableDefaultImpl(t)), + traits::VtableGenerator(traits::VtableGeneratorData { + closure_def_id, + substs, + nested + }) => { + tcx.lift(&substs).map(|substs| { + traits::VtableGenerator(traits::VtableGeneratorData { + closure_def_id: closure_def_id, + substs: substs, + nested: nested + }) + }) + } traits::VtableClosure(traits::VtableClosureData { closure_def_id, substs, @@ -351,6 +376,20 @@ impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::VtableImplData< } } +impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::VtableGeneratorData<'tcx, N> { + fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { + traits::VtableGeneratorData { + closure_def_id: self.closure_def_id, + substs: self.substs.fold_with(folder), + nested: self.nested.fold_with(folder), + } + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + self.substs.visit_with(visitor) || self.nested.visit_with(visitor) + } +} + impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::VtableClosureData<'tcx, N> { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { traits::VtableClosureData { @@ -422,6 +461,9 @@ impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::Vtable<'tcx, N> match *self { traits::VtableImpl(ref v) => traits::VtableImpl(v.fold_with(folder)), traits::VtableDefaultImpl(ref t) => traits::VtableDefaultImpl(t.fold_with(folder)), + traits::VtableGenerator(ref d) => { + traits::VtableGenerator(d.fold_with(folder)) + } traits::VtableClosure(ref d) => { traits::VtableClosure(d.fold_with(folder)) } @@ -438,6 +480,7 @@ impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::Vtable<'tcx, N> match *self { traits::VtableImpl(ref v) => v.visit_with(visitor), traits::VtableDefaultImpl(ref t) => t.visit_with(visitor), + traits::VtableGenerator(ref d) => d.visit_with(visitor), traits::VtableClosure(ref d) => d.visit_with(visitor), traits::VtableFnPointer(ref d) => d.visit_with(visitor), traits::VtableParam(ref n) => n.visit_with(visitor), diff --git a/src/librustc/traits/util.rs b/src/librustc/traits/util.rs index dae0c896909c8..957e6e9bc5ec7 100644 --- a/src/librustc/traits/util.rs +++ b/src/librustc/traits/util.rs @@ -513,6 +513,19 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { ty::Binder((trait_ref, sig.skip_binder().output())) } + pub fn generator_trait_ref_and_outputs(self, + fn_trait_def_id: DefId, + self_ty: Ty<'tcx>, + sig: ty::PolyGenSig<'tcx>) + -> ty::Binder<(ty::TraitRef<'tcx>, Ty<'tcx>, Ty<'tcx>)> + { + let trait_ref = ty::TraitRef { + def_id: fn_trait_def_id, + substs: self.mk_substs_trait(self_ty, &[sig.skip_binder().impl_arg_ty]), + }; + ty::Binder((trait_ref, sig.skip_binder().suspend_ty, sig.skip_binder().return_ty)) + } + pub fn impl_is_default(self, node_item_def_id: DefId) -> bool { match self.hir.as_local_node_id(node_item_def_id) { Some(node_id) => { diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 45ddd4c0ff179..6f276afc1025b 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -30,7 +30,7 @@ use ty::ReprOptions; use traits; use ty::{self, Ty, TypeAndMut}; use ty::{TyS, TypeVariants, Slice}; -use ty::{AdtKind, AdtDef, ClosureSubsts, Region}; +use ty::{AdtKind, AdtDef, ClosureSubsts, GeneratorInterior, Region}; use hir::FreevarMap; use ty::{PolyFnSig, InferTy, ParamTy, ProjectionTy, ExistentialPredicate, Predicate}; use ty::RegionKind; @@ -233,6 +233,10 @@ pub struct TypeckTables<'tcx> { /// that caused the closure to be this kind. pub closure_kinds: NodeMap<(ty::ClosureKind, Option<(Span, ast::Name)>)>, + pub generator_sigs: NodeMap>>, + + pub generator_interiors: NodeMap>, + /// For each fn, records the "liberated" types of its arguments /// and return type. Liberated means that all bound regions /// (including late-bound regions) are replaced with free @@ -275,6 +279,8 @@ impl<'tcx> TypeckTables<'tcx> { node_substs: NodeMap(), adjustments: NodeMap(), upvar_capture_map: FxHashMap(), + generator_sigs: NodeMap(), + generator_interiors: NodeMap(), closure_tys: NodeMap(), closure_kinds: NodeMap(), liberated_fn_sigs: NodeMap(), @@ -1040,7 +1046,7 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { pub fn print_debug_stats(self) { sty_debug_print!( self, - TyAdt, TyArray, TySlice, TyRawPtr, TyRef, TyFnDef, TyFnPtr, + TyAdt, TyArray, TySlice, TyRawPtr, TyRef, TyFnDef, TyFnPtr, TyGenerator, TyDynamic, TyClosure, TyTuple, TyParam, TyInfer, TyProjection, TyAnon); println!("Substs interner: #{}", self.interners.substs.borrow().len()); @@ -1395,6 +1401,14 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { self.mk_ty(TyClosure(closure_id, closure_substs)) } + pub fn mk_generator(self, + id: DefId, + closure_substs: ClosureSubsts<'tcx>, + interior: GeneratorInterior<'tcx>) + -> Ty<'tcx> { + self.mk_ty(TyGenerator(id, closure_substs, interior)) + } + pub fn mk_var(self, v: TyVid) -> Ty<'tcx> { self.mk_infer(TyVar(v)) } diff --git a/src/librustc/ty/error.rs b/src/librustc/ty/error.rs index 3442cf0ef698a..695c9427001a4 100644 --- a/src/librustc/ty/error.rs +++ b/src/librustc/ty/error.rs @@ -213,6 +213,7 @@ impl<'a, 'gcx, 'lcx, 'tcx> ty::TyS<'tcx> { |p| format!("trait {}", tcx.item_path_str(p.def_id()))) } ty::TyClosure(..) => "closure".to_string(), + ty::TyGenerator(..) => "generator".to_string(), ty::TyTuple(..) => "tuple".to_string(), ty::TyInfer(ty::TyVar(_)) => "inferred type".to_string(), ty::TyInfer(ty::IntVar(_)) => "integral variable".to_string(), diff --git a/src/librustc/ty/fast_reject.rs b/src/librustc/ty/fast_reject.rs index 68f85ba7d33e2..353a1cd5355b9 100644 --- a/src/librustc/ty/fast_reject.rs +++ b/src/librustc/ty/fast_reject.rs @@ -30,6 +30,7 @@ pub enum SimplifiedType { TupleSimplifiedType(usize), TraitSimplifiedType(DefId), ClosureSimplifiedType(DefId), + GeneratorSimplifiedType(DefId), AnonSimplifiedType(DefId), FunctionSimplifiedType(usize), ParameterSimplifiedType, @@ -72,6 +73,9 @@ pub fn simplify_type<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, ty::TyClosure(def_id, _) => { Some(ClosureSimplifiedType(def_id)) } + ty::TyGenerator(def_id, _, _) => { + Some(GeneratorSimplifiedType(def_id)) + } ty::TyNever => Some(NeverSimplifiedType), ty::TyTuple(ref tys, _) => { Some(TupleSimplifiedType(tys.len())) diff --git a/src/librustc/ty/flags.rs b/src/librustc/ty/flags.rs index ce2bb23660ce0..72e4e20d70b4c 100644 --- a/src/librustc/ty/flags.rs +++ b/src/librustc/ty/flags.rs @@ -85,6 +85,15 @@ impl FlagComputation { } } + &ty::TyGenerator(_, ref substs, ref interior) => { + // FIXME: Find out why TyClosure has HAS_TY_CLOSURE + // and see if the same reason applies here + self.add_flags(TypeFlags::HAS_TY_CLOSURE); + self.add_flags(TypeFlags::HAS_LOCAL_NAMES); + self.add_substs(&substs.substs); + self.add_ty(interior.witness()); + } + &ty::TyClosure(_, ref substs) => { self.add_flags(TypeFlags::HAS_TY_CLOSURE); self.add_flags(TypeFlags::HAS_LOCAL_NAMES); diff --git a/src/librustc/ty/item_path.rs b/src/librustc/ty/item_path.rs index 73b577e2e876b..01640712a38b8 100644 --- a/src/librustc/ty/item_path.rs +++ b/src/librustc/ty/item_path.rs @@ -350,6 +350,7 @@ pub fn characteristic_def_id_of_type(ty: Ty) -> Option { ty::TyFnDef(def_id, _) | ty::TyClosure(def_id, _) => Some(def_id), + ty::TyGenerator(def_id, _, _) => Some(def_id), ty::TyBool | ty::TyChar | diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index 009b0619bd75f..df6fa05a962f7 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -1226,7 +1226,17 @@ impl<'a, 'tcx> Layout { Univariant { variant: unit, non_zero: false } } - // Tuples and closures. + // Tuples, generators and closures. + ty::TyGenerator(def_id, ref substs, _) => { + let tys = substs.field_tys(def_id, tcx); + let st = Struct::new(dl, + &tys.map(|ty| ty.layout(tcx, param_env)) + .collect::, _>>()?, + &ReprOptions::default(), + StructKind::AlwaysSizedUnivariant, ty)?; + Univariant { variant: st, non_zero: false } + } + ty::TyClosure(def_id, ref substs) => { let tys = substs.upvar_tys(def_id, tcx); let st = Struct::new(dl, @@ -2240,11 +2250,15 @@ impl<'a, 'tcx> TyLayout<'tcx> { ty::TySlice(element) => element, ty::TyStr => tcx.types.u8, - // Tuples and closures. + // Tuples, generators and closures. ty::TyClosure(def_id, ref substs) => { substs.upvar_tys(def_id, tcx).nth(i).unwrap() } + ty::TyGenerator(def_id, ref substs, _) => { + substs.field_tys(def_id, tcx).nth(i).unwrap() + } + ty::TyTuple(tys, _) => tys[i], // SIMD vector types. diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs index 7a45a706ea405..1d436834b22e5 100644 --- a/src/librustc/ty/maps.rs +++ b/src/librustc/ty/maps.rs @@ -540,8 +540,13 @@ macro_rules! define_maps { impl<$tcx> Query<$tcx> { pub fn describe(&self, tcx: TyCtxt) -> String { - match *self { - $(Query::$name(key) => queries::$name::describe(tcx, key)),* + let (r, name) = match *self { + $(Query::$name(key) => (queries::$name::describe(tcx, key), stringify!($name))),* + }; + if tcx.sess.verbose() { + format!("{} [{}]", r, name) + } else { + r } } } @@ -909,6 +914,10 @@ define_maps! { <'tcx> /// The signature of functions and closures. [] fn_sig: FnSignature(DefId) -> ty::PolyFnSig<'tcx>, + /// Records the signature of each generator. The def ID is the ID of the + /// expression defining the closure. + [] generator_sig: TypeckTables(DefId) -> Option>, + /// Caches CoerceUnsized kinds for impls on custom types. [] coerce_unsized_info: CoerceUnsizedInfo(DefId) -> ty::adjustment::CoerceUnsizedInfo, diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 804f47b5283f2..cfcb0c062ad22 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -25,6 +25,7 @@ use middle::privacy::AccessLevels; use middle::resolve_lifetime::ObjectLifetimeDefault; use middle::region::CodeExtent; use mir::Mir; +use mir::GeneratorLayout; use traits; use ty; use ty::subst::{Subst, Substs}; @@ -59,9 +60,9 @@ use rustc_data_structures::transitive_relation::TransitiveRelation; use hir; pub use self::sty::{Binder, DebruijnIndex}; -pub use self::sty::{FnSig, PolyFnSig}; +pub use self::sty::{FnSig, GenSig, PolyFnSig, PolyGenSig}; pub use self::sty::{InferTy, ParamTy, ProjectionTy, ExistentialPredicate}; -pub use self::sty::{ClosureSubsts, TypeAndMut}; +pub use self::sty::{ClosureSubsts, GeneratorInterior, TypeAndMut}; pub use self::sty::{TraitRef, TypeVariants, PolyTraitRef}; pub use self::sty::{ExistentialTraitRef, PolyExistentialTraitRef}; pub use self::sty::{ExistentialProjection, PolyExistentialProjection}; @@ -1699,7 +1700,7 @@ impl<'a, 'gcx, 'tcx> AdtDef { let result = match ty.sty { TyBool | TyChar | TyInt(..) | TyUint(..) | TyFloat(..) | TyRawPtr(..) | TyRef(..) | TyFnDef(..) | TyFnPtr(_) | - TyArray(..) | TyClosure(..) | TyNever => { + TyArray(..) | TyClosure(..) | TyGenerator(..) | TyNever => { vec![] } @@ -1976,6 +1977,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { }, } }, + Some(hir_map::NodeImplArg(_)) => Symbol::intern("impl arg").as_str(), r => bug!("Variable id {} maps to {:?}, not local", id, r), } } @@ -1996,6 +1998,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { hir::ExprUnary(hir::UnDeref, _) | hir::ExprField(..) | hir::ExprTupField(..) | + hir::ExprImplArg(_) | hir::ExprIndex(..) => { true } @@ -2027,6 +2030,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { hir::ExprBox(..) | hir::ExprAddrOf(..) | hir::ExprBinary(..) | + hir::ExprSuspend(..) | hir::ExprCast(..) => { false } @@ -2258,6 +2262,10 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { self.trait_def(trait_def_id).has_default_impl } + pub fn generator_layout(self, def_id: DefId) -> &'tcx GeneratorLayout<'tcx> { + self.optimized_mir(def_id).generator_layout.as_ref().unwrap() + } + /// Given the def_id of an impl, return the def_id of the trait it implements. /// If it implements no trait, return `None`. pub fn trait_id_of_impl(self, def_id: DefId) -> Option { diff --git a/src/librustc/ty/outlives.rs b/src/librustc/ty/outlives.rs index ab1b1b3857d00..3549a7706439e 100644 --- a/src/librustc/ty/outlives.rs +++ b/src/librustc/ty/outlives.rs @@ -115,6 +115,16 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } } + ty::TyGenerator(def_id, ref substs, ref interior) => { + // Same as the closure case + for upvar_ty in substs.upvar_tys(def_id, *self) { + self.compute_components(upvar_ty, out); + } + + // But generators can have additional interior types + self.compute_components(interior.witness(), out); + } + // OutlivesTypeParameterEnv -- the actual checking that `X:'a` // is implied by the environment is done in regionck. ty::TyParam(p) => { diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs index 0d9ef8196c794..437f511cb3d0e 100644 --- a/src/librustc/ty/relate.rs +++ b/src/librustc/ty/relate.rs @@ -389,6 +389,18 @@ pub fn super_relate_tys<'a, 'gcx, 'tcx, R>(relation: &mut R, Ok(tcx.mk_dynamic(relation.relate(a_obj, b_obj)?, region_bound)) } + (&ty::TyGenerator(a_id, a_substs, a_interior), + &ty::TyGenerator(b_id, b_substs, b_interior)) + if a_id == b_id => + { + // All TyGenerator types with the same id represent + // the (anonymous) type of the same generator expression. So + // all of their regions should be equated. + let substs = relation.relate(&a_substs, &b_substs)?; + let interior = relation.relate(&a_interior, &b_interior)?; + Ok(tcx.mk_generator(a_id, substs, interior)) + } + (&ty::TyClosure(a_id, a_substs), &ty::TyClosure(b_id, b_substs)) if a_id == b_id => @@ -512,6 +524,18 @@ impl<'tcx> Relate<'tcx> for ty::ClosureSubsts<'tcx> { } } +impl<'tcx> Relate<'tcx> for ty::GeneratorInterior<'tcx> { + fn relate<'a, 'gcx, R>(relation: &mut R, + a: &ty::GeneratorInterior<'tcx>, + b: &ty::GeneratorInterior<'tcx>) + -> RelateResult<'tcx, ty::GeneratorInterior<'tcx>> + where R: TypeRelation<'a, 'gcx, 'tcx>, 'gcx: 'a+'tcx, 'tcx: 'a + { + let interior = relation.relate(&a.witness(), &b.witness())?; + Ok(ty::GeneratorInterior::new(interior)) + } +} + impl<'tcx> Relate<'tcx> for &'tcx Substs<'tcx> { fn relate<'a, 'gcx, R>(relation: &mut R, a: &&'tcx Substs<'tcx>, diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index f261a56cdccdd..63a09435feaa9 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -29,6 +29,15 @@ impl<'tcx, A: Lift<'tcx>, B: Lift<'tcx>> Lift<'tcx> for (A, B) { } } +impl<'tcx, A: Lift<'tcx>, B: Lift<'tcx>, C: Lift<'tcx>> Lift<'tcx> for (A, B, C) { + type Lifted = (A::Lifted, B::Lifted, C::Lifted); + fn lift_to_tcx<'a, 'gcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Option { + tcx.lift(&self.0).and_then(|a| { + tcx.lift(&self.1).and_then(|b| tcx.lift(&self.2).map(|c| (a, b, c))) + }) + } +} + impl<'tcx, T: Lift<'tcx>> Lift<'tcx> for Option { type Lifted = Option; fn lift_to_tcx<'a, 'gcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Option { @@ -220,6 +229,15 @@ impl<'a, 'tcx> Lift<'tcx> for ty::ClosureSubsts<'a> { } } +impl<'a, 'tcx> Lift<'tcx> for ty::GeneratorInterior<'a> { + type Lifted = ty::GeneratorInterior<'tcx>; + fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option { + tcx.lift(&self.witness()).map(|witness| { + ty::GeneratorInterior(witness) + }) + } +} + impl<'a, 'tcx> Lift<'tcx> for ty::adjustment::Adjustment<'a> { type Lifted = ty::adjustment::Adjustment<'tcx>; fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option { @@ -283,6 +301,19 @@ impl<'a, 'tcx> Lift<'tcx> for ty::adjustment::AutoBorrow<'a> { } } +impl<'a, 'tcx> Lift<'tcx> for ty::GenSig<'a> { + type Lifted = ty::GenSig<'tcx>; + fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option { + tcx.lift(&(self.impl_arg_ty, self.suspend_ty, self.return_ty)).map(|(impl_arg_ty, suspend_ty, return_ty)| { + ty::GenSig { + impl_arg_ty, + suspend_ty, + return_ty, + } + }) + } +} + impl<'a, 'tcx> Lift<'tcx> for ty::FnSig<'a> { type Lifted = ty::FnSig<'tcx>; fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option { @@ -541,6 +572,7 @@ impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> { ty::TyRef(ref r, tm) => { ty::TyRef(r.fold_with(folder), tm.fold_with(folder)) } + ty::TyGenerator(did, substs, interior) => ty::TyGenerator(did, substs.fold_with(folder), interior.fold_with(folder)), ty::TyClosure(did, substs) => ty::TyClosure(did, substs.fold_with(folder)), ty::TyProjection(ref data) => ty::TyProjection(data.fold_with(folder)), ty::TyAnon(did, substs) => ty::TyAnon(did, substs.fold_with(folder)), @@ -572,6 +604,7 @@ impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> { ty::TyFnDef(_, substs) => substs.visit_with(visitor), ty::TyFnPtr(ref f) => f.visit_with(visitor), ty::TyRef(r, ref tm) => r.visit_with(visitor) || tm.visit_with(visitor), + ty::TyGenerator(_did, ref substs, ref interior) => substs.visit_with(visitor) || interior.visit_with(visitor), ty::TyClosure(_did, ref substs) => substs.visit_with(visitor), ty::TyProjection(ref data) => data.visit_with(visitor), ty::TyAnon(_, ref substs) => substs.visit_with(visitor), @@ -596,6 +629,22 @@ impl<'tcx> TypeFoldable<'tcx> for ty::TypeAndMut<'tcx> { } } +impl<'tcx> TypeFoldable<'tcx> for ty::GenSig<'tcx> { + fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { + ty::GenSig { + impl_arg_ty: self.impl_arg_ty.fold_with(folder), + suspend_ty: self.suspend_ty.fold_with(folder), + return_ty: self.return_ty.fold_with(folder), + } + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + self.impl_arg_ty.visit_with(visitor) || + self.suspend_ty.visit_with(visitor) || + self.return_ty.visit_with(visitor) + } +} + impl<'tcx> TypeFoldable<'tcx> for ty::FnSig<'tcx> { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { let inputs_and_output = self.inputs_and_output.fold_with(folder); @@ -686,6 +735,16 @@ impl<'tcx> TypeFoldable<'tcx> for ty::ClosureSubsts<'tcx> { } } +impl<'tcx> TypeFoldable<'tcx> for ty::GeneratorInterior<'tcx> { + fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { + ty::GeneratorInterior(self.0.fold_with(folder)) + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + self.0.visit_with(visitor) + } +} + impl<'tcx> TypeFoldable<'tcx> for ty::adjustment::Adjustment<'tcx> { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { ty::adjustment::Adjustment { diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index 5f89714b33fda..7d703ebc8541f 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -149,6 +149,9 @@ pub enum TypeVariants<'tcx> { /// `|a| a`. TyClosure(DefId, ClosureSubsts<'tcx>), + /// The anonymous type of a generator. Pairs with a TyClosure for closure generators. + TyGenerator(DefId, ClosureSubsts<'tcx>, GeneratorInterior<'tcx>), + /// The never type `!` TyNever, @@ -275,6 +278,50 @@ impl<'a, 'gcx, 'acx, 'tcx> ClosureSubsts<'tcx> { } } +impl<'a, 'gcx, 'tcx> ClosureSubsts<'tcx> { + pub fn state_tys(self, def_id: DefId, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> + impl Iterator> + 'tcx + { + let state = tcx.generator_layout(def_id).fields.iter(); + let state: Vec<_> = state.map(|d| d.ty.subst(tcx, self.substs)).collect(); + state.into_iter() + } + + pub fn field_tys(self, def_id: DefId, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> + impl Iterator> + 'tcx + { + let upvars = self.upvar_tys(def_id, tcx); + let state = self.state_tys(def_id, tcx); + let tys: Vec<_> = upvars.chain(iter::once(tcx.types.u32)).chain(state).collect(); + tys.into_iter() + } +} + +/// This describes the types that can be contained in a generator. +/// It will be a type variable initially and unified in the last stages of typeck of a body. +/// It contains a tuple of all the types that could end up on a generator frame. +/// The state transformation MIR pass may only produce layouts which mention types in this tuple. +/// Upvars are not counted here. +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] +pub struct GeneratorInterior<'tcx>(pub Ty<'tcx>); + +impl<'tcx> GeneratorInterior<'tcx> { + pub fn new(witness: Ty<'tcx>) -> GeneratorInterior<'tcx> { + GeneratorInterior(witness) + } + + pub fn witness(&self) -> Ty<'tcx> { + self.0 + } + + pub fn as_slice(&self) -> &'tcx Slice> { + match self.0.sty { + ty::TyTuple(s, _) => s, + _ => bug!(), + } + } +} + #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] pub enum ExistentialPredicate<'tcx> { /// e.g. Iterator @@ -593,6 +640,25 @@ impl<'a, 'tcx> ProjectionTy<'tcx> { } } +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] +pub struct GenSig<'tcx> { + pub impl_arg_ty: Ty<'tcx>, + pub suspend_ty: Ty<'tcx>, + pub return_ty: Ty<'tcx>, +} + +#[allow(warnings)] +pub type PolyGenSig<'tcx> = Binder>; + +#[allow(warnings)] +impl<'tcx> PolyGenSig<'tcx> { + pub fn suspend_ty(&self) -> ty::Binder> { + self.map_bound_ref(|sig| sig.suspend_ty) + } + pub fn return_ty(&self) -> ty::Binder> { + self.map_bound_ref(|sig| sig.return_ty) + } +} /// Signature of a function type, which I have arbitrarily /// decided to use to refer to the input/output types. @@ -1393,7 +1459,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { TyAdt(_, substs) | TyAnon(_, substs) => { substs.regions().collect() } - TyClosure(_, ref substs) => { + TyClosure(_, ref substs) | TyGenerator(_, ref substs, _) => { substs.substs.regions().collect() } TyProjection(ref data) => { diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index df4bbad3859f4..6bbcc674ef408 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -27,6 +27,7 @@ use rustc_data_structures::stable_hasher::{StableHasher, StableHasherResult, HashStable}; use rustc_data_structures::fx::FxHashMap; use std::cmp; +use std::iter; use std::hash::Hash; use std::intrinsics; use syntax::ast::{self, Name}; @@ -568,6 +569,12 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { }).collect() } + ty::TyGenerator(def_id, substs, interior) => { + substs.upvar_tys(def_id, self).chain(iter::once(interior.witness())).map(|ty| { + self.dtorck_constraint_for_ty(span, for_ty, depth+1, ty) + }).collect() + } + ty::TyAdt(def, substs) => { let ty::DtorckConstraint { dtorck_types, outlives @@ -689,6 +696,7 @@ impl<'a, 'gcx, 'tcx, W> TypeVisitor<'tcx> for TypeIdHasher<'a, 'gcx, 'tcx, W> TyRawPtr(m) | TyRef(_, m) => self.hash(m.mutbl), TyClosure(def_id, _) | + TyGenerator(def_id, _, _) | TyAnon(def_id, _) | TyFnDef(def_id, _) => self.def_id(def_id), TyAdt(d, _) => self.def_id(d.did), @@ -1111,6 +1119,8 @@ fn needs_drop_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty::TyClosure(def_id, ref substs) => substs.upvar_tys(def_id, tcx).any(needs_drop), + ty::TyGenerator(..) => true, + ty::TyTuple(ref tys, _) => tys.iter().cloned().any(needs_drop), // unions don't have destructors regardless of the child types diff --git a/src/librustc/ty/walk.rs b/src/librustc/ty/walk.rs index a7f0bafe9b67d..a2087b0b2f1bf 100644 --- a/src/librustc/ty/walk.rs +++ b/src/librustc/ty/walk.rs @@ -112,6 +112,10 @@ fn push_subtypes<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent_ty: Ty<'tcx>) { ty::TyClosure(_, ref substs) => { stack.extend(substs.substs.types().rev()); } + ty::TyGenerator(_, ref substs, ref interior) => { + stack.extend(substs.substs.types().rev()); + stack.push(interior.witness()); + } ty::TyTuple(ts, _) => { stack.extend(ts.iter().cloned().rev()); } diff --git a/src/librustc/ty/wf.rs b/src/librustc/ty/wf.rs index c24c583ad1e19..e2abd16d001bc 100644 --- a/src/librustc/ty/wf.rs +++ b/src/librustc/ty/wf.rs @@ -239,8 +239,8 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> { } } - ty::TyClosure(..) => { - // the types in a closure are always the types of + ty::TyGenerator(..) | ty::TyClosure(..) => { + // the types in a closure or generator are always the types of // local variables (or possibly references to local // variables), we'll walk those. // diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index d9c99ccd50843..33ab83d236f7c 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -17,7 +17,7 @@ use ty::{BrAnon, BrEnv, BrFresh, BrNamed}; use ty::{TyBool, TyChar, TyAdt}; use ty::{TyError, TyStr, TyArray, TySlice, TyFloat, TyFnDef, TyFnPtr}; use ty::{TyParam, TyRawPtr, TyRef, TyNever, TyTuple}; -use ty::{TyClosure, TyProjection, TyAnon}; +use ty::{TyClosure, TyGenerator, TyProjection, TyAnon}; use ty::{TyDynamic, TyInt, TyUint, TyInfer}; use ty::{self, Ty, TyCtxt, TypeFoldable}; @@ -715,6 +715,12 @@ impl<'tcx> fmt::Display for ty::TraitRef<'tcx> { } } +impl<'tcx> fmt::Display for ty::GeneratorInterior<'tcx> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.0) + } +} + impl<'tcx> fmt::Display for ty::TypeVariants<'tcx> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { @@ -813,6 +819,41 @@ impl<'tcx> fmt::Display for ty::TypeVariants<'tcx> { }) } TyStr => write!(f, "str"), + TyGenerator(did, substs, interior) => ty::tls::with(|tcx| { + let upvar_tys = substs.upvar_tys(did, tcx); + write!(f, "[generator")?; + + if let Some(node_id) = tcx.hir.as_local_node_id(did) { + write!(f, "@{:?}", tcx.hir.span(node_id))?; + let mut sep = " "; + tcx.with_freevars(node_id, |freevars| { + for (freevar, upvar_ty) in freevars.iter().zip(upvar_tys) { + let def_id = freevar.def.def_id(); + let node_id = tcx.hir.as_local_node_id(def_id).unwrap(); + write!(f, + "{}{}:{}", + sep, + tcx.local_var_name_str(node_id), + upvar_ty)?; + sep = ", "; + } + Ok(()) + })? + } else { + // cross-crate closure types should only be + // visible in trans bug reports, I imagine. + write!(f, "@{:?}", did)?; + let mut sep = " "; + for (index, upvar_ty) in upvar_tys.enumerate() { + write!(f, "{}{}:{}", sep, index, upvar_ty)?; + sep = ", "; + } + } + + write!(f, " {}", interior)?; + + write!(f, "]") + }), TyClosure(did, substs) => ty::tls::with(|tcx| { let upvar_tys = substs.upvar_tys(did, tcx); write!(f, "[closure")?; diff --git a/src/librustc_borrowck/borrowck/gather_loans/mod.rs b/src/librustc_borrowck/borrowck/gather_loans/mod.rs index 7dcb6ce76a401..6fbe954b9c64e 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/mod.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/mod.rs @@ -21,6 +21,7 @@ use borrowck::move_data::MoveData; use rustc::middle::expr_use_visitor as euv; use rustc::middle::mem_categorization as mc; use rustc::middle::mem_categorization::Categorization; +use rustc::middle::region::extent_has_yield; use rustc::middle::region; use rustc::ty::{self, TyCtxt}; @@ -36,19 +37,20 @@ mod gather_moves; mod move_error; pub fn gather_loans_in_fn<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, - body: hir::BodyId) + body_id: hir::BodyId) -> (Vec>, move_data::MoveData<'tcx>) { - let def_id = bccx.tcx.hir.body_owner_def_id(body); + let def_id = bccx.tcx.hir.body_owner_def_id(body_id); let param_env = bccx.tcx.param_env(def_id); + let body = bccx.tcx.hir.body(body_id); let mut glcx = GatherLoanCtxt { bccx: bccx, all_loans: Vec::new(), - item_ub: region::CodeExtent::Misc(body.node_id), + item_ub: region::CodeExtent::Misc(body_id.node_id), move_data: MoveData::new(), move_error_collector: move_error::MoveErrorCollector::new(), + generator: body.is_generator(), }; - let body = glcx.bccx.tcx.hir.body(body); euv::ExprUseVisitor::new(&mut glcx, bccx.tcx, param_env, &bccx.region_maps, bccx.tables) .consume_body(body); @@ -65,6 +67,7 @@ struct GatherLoanCtxt<'a, 'tcx: 'a> { /// `item_ub` is used as an upper-bound on the lifetime whenever we /// ask for the scope of an expression categorized as an upvar. item_ub: region::CodeExtent, + generator: bool, } impl<'a, 'tcx> euv::Delegate<'tcx> for GatherLoanCtxt<'a, 'tcx> { @@ -134,6 +137,21 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for GatherLoanCtxt<'a, 'tcx> { borrow_id, cmt, loan_region, bk, loan_cause); + let borrows_impl_arg = match cmt.cat { + Categorization::Local(id) => match self.bccx.tcx.hir.find(id) { + Some(hir::map::NodeImplArg(..)) => true, + _ => false, + }, + _ => false, + }; + + if borrows_impl_arg { + span_err!(self.bccx.tcx.sess, + borrow_span, + E0805, + "cannot borrow the implicit argument of a generator"); + } + self.guarantee_valid(borrow_id, borrow_span, cmt, @@ -201,6 +219,19 @@ fn check_aliasability<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, } } +fn check_yields<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, + borrow_span: Span, + loan_region: ty::Region<'tcx>) { + if let &ty::RegionKind::ReScope(extent) = loan_region { + if extent_has_yield(bccx.tcx, extent) { + span_err!(bccx.tcx.sess, + borrow_span, + E0806, + "cannot borrow this value across the suspend point of a generator"); + } + } +} + /// Implements the M-* rules in README.md. fn check_mutability<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, borrow_span: Span, @@ -312,6 +343,11 @@ impl<'a, 'tcx> GatherLoanCtxt<'a, 'tcx> { return; } + // Check that the region has no yields if this is in a generator + if self.generator { + check_yields(self.bccx, borrow_span, loan_region); + } + // Check that the lifetime of the borrow does not exceed // the lifetime of the data being borrowed. if lifetime::guarantee_lifetime(self.bccx, self.item_ub, diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index 1bfc5805bc8fd..a0c9a311e05e5 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -306,7 +306,7 @@ pub fn closure_to_block(closure_id: ast::NodeId, tcx: TyCtxt) -> ast::NodeId { match tcx.hir.get(closure_id) { hir_map::NodeExpr(expr) => match expr.node { - hir::ExprClosure(.., body_id, _) => { + hir::ExprClosure(.., body_id, _, _) => { body_id.node_id } _ => { @@ -609,7 +609,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { move_data::Captured => (match self.tcx.hir.expect_expr(the_move.id).node { - hir::ExprClosure(.., fn_decl_span) => fn_decl_span, + hir::ExprClosure(.., fn_decl_span, _) => fn_decl_span, ref r => bug!("Captured({}) maps to non-closure: {:?}", the_move.id, r), }, " (into closure)"), diff --git a/src/librustc_borrowck/diagnostics.rs b/src/librustc_borrowck/diagnostics.rs index 38dcc73123691..415b633a623a2 100644 --- a/src/librustc_borrowck/diagnostics.rs +++ b/src/librustc_borrowck/diagnostics.rs @@ -1191,4 +1191,6 @@ register_diagnostics! { E0594, // cannot assign to {} E0595, // closure cannot assign to {} E0598, // lifetime of {} is too short to guarantee its contents can be... + E0805, // borrow of the implicit argument of a generator + E0806, // borrow across a suspend point } diff --git a/src/librustc_data_structures/indexed_set.rs b/src/librustc_data_structures/indexed_set.rs index 572ce98d3ae8e..821e2b01431c5 100644 --- a/src/librustc_data_structures/indexed_set.rs +++ b/src/librustc_data_structures/indexed_set.rs @@ -21,6 +21,7 @@ use indexed_vec::Idx; /// /// In other words, `T` is the type used to index into the bitvector /// this type uses to represent the set of object it holds. +#[derive(Eq, PartialEq)] pub struct IdxSetBuf { _pd: PhantomData, bits: Vec, @@ -109,6 +110,13 @@ impl IdxSet { } } + /// Removes all elements + pub fn clear(&mut self) { + for b in &mut self.bits { + *b = 0; + } + } + /// Removes `elem` from the set `self`; returns true iff this changed `self`. pub fn remove(&mut self, elem: &T) -> bool { self.bits.clear_bit(elem.index()) diff --git a/src/librustc_data_structures/indexed_vec.rs b/src/librustc_data_structures/indexed_vec.rs index 29ac650aa7053..8e2a759b46794 100644 --- a/src/librustc_data_structures/indexed_vec.rs +++ b/src/librustc_data_structures/indexed_vec.rs @@ -38,7 +38,7 @@ impl Idx for u32 { fn index(self) -> usize { self as usize } } -#[derive(Clone)] +#[derive(Clone, PartialEq, Eq)] pub struct IndexVec { pub raw: Vec, _marker: PhantomData diff --git a/src/librustc_data_structures/stable_hasher.rs b/src/librustc_data_structures/stable_hasher.rs index 5e291ea3c152b..866261b4f63dd 100644 --- a/src/librustc_data_structures/stable_hasher.rs +++ b/src/librustc_data_structures/stable_hasher.rs @@ -292,6 +292,15 @@ impl, CTX> HashStable for Vec { } } +impl, CTX> HashStable for Box { + #[inline] + fn hash_stable(&self, + ctx: &mut CTX, + hasher: &mut StableHasher) { + (**self).hash_stable(ctx, hasher); + } +} + impl, CTX> HashStable for ::std::rc::Rc { #[inline] fn hash_stable(&self, diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index c592882a1e43b..704d3568ca3cd 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -957,6 +957,10 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, passes.push_pass(MIR_OPTIMIZED, mir::transform::deaggregator::Deaggregator); passes.push_pass(MIR_OPTIMIZED, mir::transform::copy_prop::CopyPropagation); passes.push_pass(MIR_OPTIMIZED, mir::transform::simplify::SimplifyLocals); + + passes.push_pass(MIR_OPTIMIZED, mir::transform::generator::StateTransform); + passes.push_pass(MIR_OPTIMIZED, mir::transform::no_landing_pads::NoLandingPads); + passes.push_pass(MIR_OPTIMIZED, mir::transform::add_call_guards::AddCallGuards); passes.push_pass(MIR_OPTIMIZED, mir::transform::dump_mir::Marker("PreTrans")); diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index aca98df9cc998..31aa8c0316aac 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -607,6 +607,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { ty::TyInfer(..) | ty::TyError | ty::TyClosure(..) | + ty::TyGenerator(..) | ty::TyProjection(..) | ty::TyAnon(..) | ty::TyFnDef(..) => bug!("Unexpected type in foreign function"), diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index 5b0612ddab606..4c883f3e014f1 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -104,6 +104,7 @@ provide! { <'tcx> tcx, def_id, cdata, mir } + generator_sig => { cdata.generator_sig(def_id.index, tcx) } mir_const_qualif => { cdata.mir_const_qualif(def_id.index) } typeck_tables_of => { cdata.item_body_tables(def_id.index, tcx) } closure_kind => { cdata.closure_kind(def_id.index) } diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index ad3a9dd9fefaf..2ee5b07347fb3 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -438,6 +438,7 @@ impl<'tcx> EntryKind<'tcx> { EntryKind::Impl(_) | EntryKind::DefaultImpl(_) | EntryKind::Field | + EntryKind::Generator(_) | EntryKind::Closure(_) => return None, }) } @@ -1100,6 +1101,23 @@ impl<'a, 'tcx> CrateMetadata { sig.decode((self, tcx)) } + fn get_generator_data(&self, + id: DefIndex, + tcx: TyCtxt<'a, 'tcx, 'tcx>) + -> Option> { + match self.entry(id).kind { + EntryKind::Generator(data) => Some(data.decode((self, tcx))), + _ => None, + } + } + + pub fn generator_sig(&self, + id: DefIndex, + tcx: TyCtxt<'a, 'tcx, 'tcx>) + -> Option> { + self.get_generator_data(id, tcx).map(|d| d.sig) + } + #[inline] pub fn def_key(&self, index: DefIndex) -> DefKey { self.def_path_table.def_key(index) diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 5d73abc3ee8b8..d29c2746092c9 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -1213,13 +1213,23 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { debug!("IsolatedEncoder::encode_info_for_closure({:?})", def_id); let tcx = self.tcx; - let data = ClosureData { - kind: tcx.closure_kind(def_id), - sig: self.lazy(&tcx.fn_sig(def_id)), + let kind = if let Some(sig) = self.tcx.generator_sig(def_id) { + let layout = self.tcx.generator_layout(def_id); + let data = GeneratorData { + sig, + layout: layout.clone(), + }; + EntryKind::Generator(self.lazy(&data)) + } else { + let data = ClosureData { + kind: tcx.closure_kind(def_id), + sig: self.lazy(&tcx.fn_sig(def_id)), + }; + EntryKind::Closure(self.lazy(&data)) }; Entry { - kind: EntryKind::Closure(self.lazy(&data)), + kind, visibility: self.lazy(&ty::Visibility::Public), span: self.lazy(&tcx.def_span(def_id)), attributes: self.encode_attributes(&tcx.get_attrs(def_id)), diff --git a/src/librustc_metadata/schema.rs b/src/librustc_metadata/schema.rs index 0b670121ba23b..567da85b61c3a 100644 --- a/src/librustc_metadata/schema.rs +++ b/src/librustc_metadata/schema.rs @@ -353,6 +353,7 @@ pub enum EntryKind<'tcx> { Mod(Lazy), MacroDef(Lazy), Closure(Lazy>), + Generator(Lazy>), Trait(Lazy>), Impl(Lazy>), DefaultImpl(Lazy>), @@ -401,6 +402,9 @@ impl<'a, 'gcx, 'tcx> HashStable> for EntryK EntryKind::MacroDef(ref macro_def) => { macro_def.hash_stable(hcx, hasher); } + EntryKind::Generator(data) => { + data.hash_stable(hcx, hasher); + } EntryKind::Closure(closure_data) => { closure_data.hash_stable(hcx, hasher); } @@ -564,3 +568,10 @@ pub struct ClosureData<'tcx> { pub sig: Lazy>, } impl_stable_hash_for!(struct ClosureData<'tcx> { kind, sig }); + +#[derive(RustcEncodable, RustcDecodable)] +pub struct GeneratorData<'tcx> { + pub sig: ty::PolyGenSig<'tcx>, + pub layout: mir::GeneratorLayout<'tcx>, +} +impl_stable_hash_for!(struct GeneratorData<'tcx> { sig, layout }); diff --git a/src/librustc_mir/build/expr/as_lvalue.rs b/src/librustc_mir/build/expr/as_lvalue.rs index 04c23215463dd..78175e0535101 100644 --- a/src/librustc_mir/build/expr/as_lvalue.rs +++ b/src/librustc_mir/build/expr/as_lvalue.rs @@ -80,6 +80,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { success.and(slice.index(idx)) } ExprKind::SelfRef => { + block.and(Lvalue::Local(Local::new(this.arg_offset + 1))) + } + ExprKind::ImplArg => { block.and(Lvalue::Local(Local::new(1))) } ExprKind::VarRef { id } => { @@ -118,6 +121,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { ExprKind::Return { .. } | ExprKind::Literal { .. } | ExprKind::InlineAsm { .. } | + ExprKind::Suspend { .. } | ExprKind::Call { .. } => { // these are not lvalues, so we need to make a temporary. debug_assert!(match Category::of(&expr.kind) { diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs index 2512291f1a44f..6af7bd056b4a3 100644 --- a/src/librustc_mir/build/expr/as_rvalue.rs +++ b/src/librustc_mir/build/expr/as_rvalue.rs @@ -179,12 +179,25 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { block.and(Rvalue::Aggregate(box AggregateKind::Tuple, fields)) } - ExprKind::Closure { closure_id, substs, upvars } => { // see (*) above - let upvars = + ExprKind::Closure { closure_id, substs, upvars, generator } => { // see (*) above + let mut operands: Vec<_> = upvars.into_iter() .map(|upvar| unpack!(block = this.as_operand(block, scope, upvar))) .collect(); - block.and(Rvalue::Aggregate(box AggregateKind::Closure(closure_id, substs), upvars)) + let result = if generator { + // Add the state operand + operands.push(Operand::Constant(box Constant { + span: expr_span, + ty: this.hir.tcx().types.u32, + literal: Literal::Value { + value: ConstVal::Integral(ConstInt::U32(0)), + }, + })); + box AggregateKind::Generator(closure_id, substs) + } else { + box AggregateKind::Closure(closure_id, substs) + }; + block.and(Rvalue::Aggregate(result, operands)) } ExprKind::Adt { adt_def, variant_index, substs, fields, base @@ -226,6 +239,22 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { block = unpack!(this.stmt_expr(block, expr)); block.and(this.unit_rvalue()) } + ExprKind::Suspend { value } => { + let value = unpack!(block = this.as_operand(block, scope, value)); + let impl_arg_ty = this.impl_arg_ty.unwrap(); + block = unpack!(this.build_drop(block, + expr_span, + Lvalue::Local(Local::new(1)), + impl_arg_ty)); + let resume = this.cfg.start_new_block(); + let cleanup = this.generator_drop_cleanup(expr_span); + this.cfg.terminate(block, source_info, TerminatorKind::Suspend { + value: value, + resume: resume, + drop: cleanup, + }); + resume.and(this.unit_rvalue()) + } ExprKind::Literal { .. } | ExprKind::Block { .. } | ExprKind::Match { .. } | @@ -243,6 +272,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { ExprKind::Continue { .. } | ExprKind::Return { .. } | ExprKind::InlineAsm { .. } | + ExprKind::ImplArg | ExprKind::StaticRef { .. } => { // these do not have corresponding `Rvalue` variants, // so make an operand and then return that diff --git a/src/librustc_mir/build/expr/as_temp.rs b/src/librustc_mir/build/expr/as_temp.rs index 9be306d2848b3..041e8fe475d00 100644 --- a/src/librustc_mir/build/expr/as_temp.rs +++ b/src/librustc_mir/build/expr/as_temp.rs @@ -79,7 +79,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // anything because no values with a destructor can be created in // a constant at this time, even if the type may need dropping. if let Some(temp_lifetime) = temp_lifetime { - this.schedule_drop(expr_span, temp_lifetime, &temp, expr_ty); + this.schedule_drop(expr_span, temp_lifetime, &temp, expr_ty, false); } block.and(temp) diff --git a/src/librustc_mir/build/expr/category.rs b/src/librustc_mir/build/expr/category.rs index 35173bb598c7c..0208dbf70349f 100644 --- a/src/librustc_mir/build/expr/category.rs +++ b/src/librustc_mir/build/expr/category.rs @@ -50,6 +50,7 @@ impl Category { ExprKind::Index { .. } | ExprKind::SelfRef | ExprKind::VarRef { .. } | + ExprKind::ImplArg | ExprKind::StaticRef { .. } => Some(Category::Lvalue), @@ -77,6 +78,7 @@ impl Category { ExprKind::Borrow { .. } | ExprKind::Assign { .. } | ExprKind::AssignOp { .. } | + ExprKind::Suspend { .. } | ExprKind::InlineAsm { .. } => Some(Category::Rvalue(RvalueFunc::AsRvalue)), diff --git a/src/librustc_mir/build/expr/into.rs b/src/librustc_mir/build/expr/into.rs index 326c1df69ebeb..ee5b04d03be31 100644 --- a/src/librustc_mir/build/expr/into.rs +++ b/src/librustc_mir/build/expr/into.rs @@ -284,6 +284,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { ExprKind::Index { .. } | ExprKind::Deref { .. } | ExprKind::Literal { .. } | + ExprKind::Suspend { .. } | + ExprKind::ImplArg | ExprKind::Field { .. } => { debug_assert!(match Category::of(&expr.kind).unwrap() { Category::Rvalue(RvalueFunc::Into) => false, diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs index 54f285480ab53..9e96ae474d0a8 100644 --- a/src/librustc_mir/build/matches/mod.rs +++ b/src/librustc_mir/build/matches/mod.rs @@ -203,7 +203,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let local_id = self.var_indices[&var]; let var_ty = self.local_decls[local_id].ty; let extent = self.hir.region_maps.var_scope(var); - self.schedule_drop(span, extent, &Lvalue::Local(local_id), var_ty); + self.schedule_drop(span, extent, &Lvalue::Local(local_id), var_ty, false); } pub fn visit_bindings(&mut self, pattern: &Pattern<'tcx>, mut f: &mut F) diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index 5badef3cfa180..09e891021b1c1 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -71,7 +71,7 @@ pub fn mir_build<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Mir<'t // Assume that everything other than closures // is a constant "initializer" expression. match expr.node { - hir::ExprClosure(_, _, body, _) => body, + hir::ExprClosure(_, _, body, _, _) => body, _ => hir::BodyId { node_id: expr.id } } } @@ -94,13 +94,18 @@ pub fn mir_build<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Mir<'t let ty = tcx.type_of(tcx.hir.local_def_id(id)); let mut abi = fn_sig.abi; - let implicit_argument = if let ty::TyClosure(..) = ty.sty { - // HACK(eddyb) Avoid having RustCall on closures, - // as it adds unnecessary (and wrong) auto-tupling. - abi = Abi::Rust; - Some((closure_self_ty(tcx, id, body_id), None)) - } else { - None + let implicit_argument = match ty.sty { + ty::TyClosure(..) => { + // HACK(eddyb) Avoid having RustCall on closures, + // as it adds unnecessary (and wrong) auto-tupling. + abi = Abi::Rust; + Some((closure_self_ty(tcx, id, body_id), None)) + } + ty::TyGenerator(..) => { + let gen_ty = tcx.body_tables(body_id).node_id_to_type(id); + Some((gen_ty, None)) + } + _ => None, }; let body = tcx.hir.body(body_id); @@ -113,7 +118,15 @@ pub fn mir_build<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Mir<'t }); let arguments = implicit_argument.into_iter().chain(explicit_arguments); - build::construct_fn(cx, id, arguments, abi, fn_sig.output(), body) + + let (suspend_ty, impl_arg_ty, return_ty) = if body.is_generator() { + let gen_sig = cx.tables().generator_sigs[&id].clone().unwrap(); + (Some(gen_sig.suspend_ty), Some(gen_sig.impl_arg_ty), gen_sig.return_ty) + } else { + (None, None, fn_sig.output()) + }; + + build::construct_fn(cx, id, arguments, abi, return_ty, suspend_ty, impl_arg_ty, body) } else { build::construct_const(cx, body_id) }; @@ -198,7 +211,7 @@ fn create_constructor_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, /////////////////////////////////////////////////////////////////////////// // BuildMir -- walks a crate, looking for fn items and methods to build MIR from -fn closure_self_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, +pub fn closure_self_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, closure_expr_id: ast::NodeId, body_id: hir::BodyId) -> Ty<'tcx> { @@ -231,6 +244,9 @@ struct Builder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { fn_span: Span, arg_count: usize, + arg_offset: usize, + + impl_arg_ty: Option>, /// the current set of scopes, updated as we traverse; /// see the `scope` module for more details @@ -326,6 +342,8 @@ fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>, arguments: A, abi: Abi, return_ty: Ty<'gcx>, + suspend_ty: Option>, + impl_arg_ty: Option>, body: &'gcx hir::Body) -> Mir<'tcx> where A: Iterator, Option<&'gcx hir::Pat>)> @@ -334,7 +352,13 @@ fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>, let tcx = hir.tcx(); let span = tcx.hir.span(fn_id); - let mut builder = Builder::new(hir.clone(), span, arguments.len(), return_ty); + let arg_offset = if impl_arg_ty.is_some() { 1 } else { 0 }; + let mut builder = Builder::new(hir.clone(), + span, + arguments.len() + arg_offset, + arg_offset, + impl_arg_ty, + return_ty); let call_site_extent = CodeExtent::CallSiteScope(body.id()); let arg_extent = CodeExtent::ParameterScope(body.id()); @@ -342,7 +366,7 @@ fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>, let source_info = builder.source_info(span); unpack!(block = builder.in_scope((call_site_extent, source_info), block, |builder| { unpack!(block = builder.in_scope((arg_extent, source_info), block, |builder| { - builder.args_and_body(block, &arguments, arg_extent, &body.value) + builder.args_and_body(block, &arguments, arg_extent, impl_arg_ty, &body.value) })); // Attribute epilogue to function's closing brace let fn_end = Span { lo: span.hi, ..span }; @@ -387,7 +411,7 @@ fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>, }).collect() }); - let mut mir = builder.finish(upvar_decls, return_ty); + let mut mir = builder.finish(upvar_decls, return_ty, suspend_ty); mir.spread_arg = spread_arg; mir } @@ -400,7 +424,7 @@ fn construct_const<'a, 'gcx, 'tcx>(hir: Cx<'a, 'gcx, 'tcx>, let ty = hir.tables().expr_ty_adjusted(ast_expr); let owner_id = tcx.hir.body_owner(body_id); let span = tcx.hir.span(owner_id); - let mut builder = Builder::new(hir.clone(), span, 0, ty); + let mut builder = Builder::new(hir.clone(), span, 0, 0, None, ty); let mut block = START_BLOCK; let expr = builder.hir.mirror(ast_expr); @@ -412,7 +436,7 @@ fn construct_const<'a, 'gcx, 'tcx>(hir: Cx<'a, 'gcx, 'tcx>, // Constants can't `return` so a return block should not be created. assert_eq!(builder.cached_return_block, None); - builder.finish(vec![], ty) + builder.finish(vec![], ty, None) } fn construct_error<'a, 'gcx, 'tcx>(hir: Cx<'a, 'gcx, 'tcx>, @@ -420,16 +444,18 @@ fn construct_error<'a, 'gcx, 'tcx>(hir: Cx<'a, 'gcx, 'tcx>, -> Mir<'tcx> { let span = hir.tcx().hir.span(hir.tcx().hir.body_owner(body_id)); let ty = hir.tcx().types.err; - let mut builder = Builder::new(hir, span, 0, ty); + let mut builder = Builder::new(hir, span, 0, 0, None, ty); let source_info = builder.source_info(span); builder.cfg.terminate(START_BLOCK, source_info, TerminatorKind::Unreachable); - builder.finish(vec![], ty) + builder.finish(vec![], ty, None) } impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { fn new(hir: Cx<'a, 'gcx, 'tcx>, span: Span, arg_count: usize, + arg_offset: usize, + impl_arg_ty: Option>, return_ty: Ty<'tcx>) -> Builder<'a, 'gcx, 'tcx> { let mut builder = Builder { @@ -437,6 +463,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { cfg: CFG { basic_blocks: IndexVec::new() }, fn_span: span, arg_count: arg_count, + arg_offset, + impl_arg_ty, scopes: vec![], visibility_scopes: IndexVec::new(), visibility_scope: ARGUMENT_VISIBILITY_SCOPE, @@ -458,7 +486,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { fn finish(self, upvar_decls: Vec, - return_ty: Ty<'tcx>) + return_ty: Ty<'tcx>, + suspend_ty: Option>) -> Mir<'tcx> { for (index, block) in self.cfg.basic_blocks.iter().enumerate() { if block.terminator.is_none() { @@ -470,6 +499,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { self.visibility_scopes, IndexVec::new(), return_ty, + suspend_ty, self.local_decls, self.arg_count, upvar_decls, @@ -481,9 +511,26 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { mut block: BasicBlock, arguments: &[(Ty<'gcx>, Option<&'gcx hir::Pat>)], argument_extent: CodeExtent, + impl_arg_ty: Option>, ast_body: &'gcx hir::Expr) -> BlockAnd<()> { + if let Some(impl_arg_ty) = impl_arg_ty { + self.local_decls.push(LocalDecl { + mutability: Mutability::Mut, + ty: impl_arg_ty, + is_user_variable: false, + source_info: SourceInfo { + scope: ARGUMENT_VISIBILITY_SCOPE, + span: self.fn_span, + }, + name: None, + }); + let lvalue = Lvalue::Local(Local::new(1)); + // Make sure we drop the argument on completion + self.schedule_drop(ast_body.span, argument_extent, &lvalue, impl_arg_ty, true); + }; + // Allocate locals for the function arguments for &(ty, pattern) in arguments.iter() { // If this is a simple binding pattern, give the local a nice name for debuginfo. @@ -510,7 +557,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // Bind the argument patterns for (index, &(ty, pattern)) in arguments.iter().enumerate() { // Function arguments always get the first Local indices after the return pointer - let lvalue = Lvalue::Local(Local::new(index + 1)); + let lvalue = Lvalue::Local(Local::new(self.arg_offset + index + 1)); if let Some(pattern) = pattern { let pattern = Pattern::from_hir(self.hir.tcx().global_tcx(), @@ -523,7 +570,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // Make sure we drop (parts of) the argument even when not matched on. self.schedule_drop(pattern.as_ref().map_or(ast_body.span, |pat| pat.span), - argument_extent, &lvalue, ty); + argument_extent, &lvalue, ty, false); } diff --git a/src/librustc_mir/build/scope.rs b/src/librustc_mir/build/scope.rs index 2244ffde3c9d0..3ee33fbe16260 100644 --- a/src/librustc_mir/build/scope.rs +++ b/src/librustc_mir/build/scope.rs @@ -124,6 +124,9 @@ pub struct Scope<'tcx> { /// end of the vector (top of the stack) first. drops: Vec>, + /// Is the first drop the drop of the implicit argument? + impl_arg_drop: bool, + /// A scope may only have one associated free, because: /// /// 1. We require a `free` to only be scheduled in the scope of @@ -141,6 +144,9 @@ pub struct Scope<'tcx> { /// The cache for drop chain on “normal” exit into a particular BasicBlock. cached_exits: FxHashMap<(BasicBlock, CodeExtent), BasicBlock>, + + /// The cache for drop chain on "generator drop" exit. + cached_generator_drop: Option, } #[derive(Debug)] @@ -155,14 +161,22 @@ struct DropData<'tcx> { kind: DropKind } +#[derive(Debug, Default, Clone, Copy)] +struct CachedBlock { + /// The cached block for the cleanups-on-diverge path. This block + /// contains code to run the current drop and all the preceding + /// drops (i.e. those having lower index in Drop’s Scope drop + /// array) + unwind: Option, + + /// The cached block for unwinds during cleanups-on-generator-drop path + generator_drop: Option, +} + #[derive(Debug)] enum DropKind { Value { - /// The cached block for the cleanups-on-diverge path. This block - /// contains code to run the current drop and all the preceding - /// drops (i.e. those having lower index in Drop’s Scope drop - /// array) - cached_block: Option + cached_block: CachedBlock, }, Storage } @@ -180,7 +194,7 @@ struct FreeData<'tcx> { /// The cached block containing code to run the free. The block will also execute all the drops /// in the scope. - cached_block: Option + cached_block: CachedBlock, } #[derive(Clone, Debug)] @@ -197,6 +211,29 @@ pub struct BreakableScope<'tcx> { pub break_destination: Lvalue<'tcx>, } +impl CachedBlock { + fn invalidate(&mut self) { + self.generator_drop = None; + self.unwind = None; + } + + fn get(&self, generator_drop: bool) -> Option { + if generator_drop { + self.generator_drop + } else { + self.unwind + } + } + + fn ref_mut(&mut self, generator_drop: bool) -> &mut Option { + if generator_drop { + &mut self.generator_drop + } else { + &mut self.unwind + } + } +} + impl<'tcx> Scope<'tcx> { /// Invalidate all the cached blocks in the scope. /// @@ -209,11 +246,27 @@ impl<'tcx> Scope<'tcx> { if !unwind { return; } for dropdata in &mut self.drops { if let DropKind::Value { ref mut cached_block } = dropdata.kind { - *cached_block = None; + cached_block.invalidate(); } } if let Some(ref mut freedata) = self.free { - freedata.cached_block = None; + freedata.cached_block.invalidate(); + } + } + + fn drops(&self, generator_drop: bool) -> &[DropData<'tcx>] { + if self.impl_arg_drop && generator_drop { + &self.drops[1..] + } else { + &self.drops[..] + } + } + + fn drops_mut(&mut self, generator_drop: bool) -> &mut [DropData<'tcx>] { + if self.impl_arg_drop && generator_drop { + &mut self.drops[1..] + } else { + &mut self.drops[..] } } @@ -221,17 +274,19 @@ impl<'tcx> Scope<'tcx> { /// /// Precondition: the caches must be fully filled (i.e. diverge_cleanup is called) in order for /// this method to work correctly. - fn cached_block(&self) -> Option { - let mut drops = self.drops.iter().rev().filter_map(|data| { + fn cached_block(&self, generator_drop: bool) -> Option { + let mut drops = self.drops(generator_drop).iter().rev().filter_map(|data| { match data.kind { - DropKind::Value { cached_block } => Some(cached_block), + DropKind::Value { cached_block } => { + Some(cached_block.get(generator_drop)) + } DropKind::Storage => None } }); if let Some(cached_block) = drops.next() { Some(cached_block.expect("drop cache is not filled")) } else if let Some(ref data) = self.free { - Some(data.cached_block.expect("free cache is not filled")) + Some(data.cached_block.get(generator_drop).expect("free cache is not filled")) } else { None } @@ -320,7 +375,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { extent: extent, needs_cleanup: false, drops: vec![], + impl_arg_drop: false, free: None, + cached_generator_drop: None, cached_exits: FxHashMap() }); } @@ -342,7 +399,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { &scope, &self.scopes, block, - self.arg_count)); + self.arg_count, + false)); self.cfg.push_end_region(block, extent.1, scope.extent); block.unit() @@ -385,7 +443,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { scope, rest, block, - self.arg_count)); + self.arg_count, + false)); // End all regions for scopes out of which we are breaking. self.cfg.push_end_region(block, extent.1, scope.extent); @@ -393,7 +452,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { if let Some(ref free_data) = scope.free { let next = self.cfg.start_new_block(); let free = build_free(self.hir.tcx(), &tmp, free_data, next); - self.cfg.terminate(block, scope.source_info(span), free); + self.cfg.terminate(block, scope.source_info(free_data.span), free); block = next; } } @@ -403,6 +462,63 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { TerminatorKind::Goto { target: target }); } + /// Creates a path that performs all required cleanup for dropping a generator. + /// + /// This path terminates in GeneratorDrop. Returns the start of the path. + /// None indicates there’s no cleanup to do at this point. + pub fn generator_drop_cleanup(&mut self, span: Span) -> Option { + if !self.scopes.iter().any(|scope| scope.needs_cleanup) { + return None; + } + + // Fill in the cache + self.diverge_cleanup_gen(span, true); + + let src_info = self.scopes[0].source_info(self.fn_span); + let tmp = self.get_unit_temp(); + let mut block = self.cfg.start_new_block(); + let result = block; + let mut rest = &mut self.scopes[..]; + + while let Some((scope, rest_)) = {rest}.split_last_mut() { + rest = rest_; + if !scope.needs_cleanup { + continue; + } + block = if let Some(b) = scope.cached_generator_drop { + self.cfg.terminate(block, src_info, + TerminatorKind::Goto { target: b }); + return Some(result); + } else { + let b = self.cfg.start_new_block(); + scope.cached_generator_drop = Some(b); + self.cfg.terminate(block, src_info, + TerminatorKind::Goto { target: b }); + b + }; + unpack!(block = build_scope_drops(&mut self.cfg, + scope, + rest, + block, + self.arg_count, + true)); + + // End all regions for scopes out of which we are breaking. + self.cfg.push_end_region(block, src_info, scope.extent); + + if let Some(ref free_data) = scope.free { + let next = self.cfg.start_new_block(); + let free = build_free(self.hir.tcx(), &tmp, free_data, next); + self.cfg.terminate(block, scope.source_info(free_data.span), free); + block = next; + } + } + + self.cfg.terminate(block, src_info, TerminatorKind::GeneratorDrop); + + Some(result) + } + /// Creates a new visibility scope, nested in the current one. pub fn new_visibility_scope(&mut self, span: Span) -> VisibilityScope { let parent = self.visibility_scope; @@ -487,7 +603,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { None, MirSource::Fn(_) => Some(self.topmost_scope()), - MirSource::Promoted(..) => + MirSource::Promoted(..) | + MirSource::GeneratorDrop(..) => bug!(), } } @@ -500,10 +617,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { span: Span, extent: CodeExtent, lvalue: &Lvalue<'tcx>, - lvalue_ty: Ty<'tcx>) { + lvalue_ty: Ty<'tcx>, + impl_arg: bool) { let needs_drop = self.hir.needs_drop(lvalue_ty); let drop_kind = if needs_drop { - DropKind::Value { cached_block: None } + DropKind::Value { cached_block: CachedBlock::default() } } else { // Only temps and vars need their storage dead. match *lvalue { @@ -570,6 +688,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let extent_span = extent.span(&tcx.hir).unwrap(); // Attribute scope exit drops to scope's closing brace let scope_end = Span { lo: extent_span.hi, .. extent_span}; + if impl_arg { + assert!(scope.drops.is_empty()); + scope.impl_arg_drop = true; + } scope.drops.push(DropData { span: scope_end, location: lvalue.clone(), @@ -603,7 +725,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { span: span, value: value.clone(), item_ty: item_ty, - cached_block: None + cached_block: CachedBlock::default(), }); return; } @@ -619,6 +741,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { /// See module comment for more details. None indicates there’s no /// cleanup to do at this point. pub fn diverge_cleanup(&mut self, span: Span) -> Option { + self.diverge_cleanup_gen(span, false) + } + + fn diverge_cleanup_gen(&mut self, span: Span, generator_drop: bool) -> Option { if !self.scopes.iter().any(|scope| scope.needs_cleanup) { return None; } @@ -652,7 +778,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { }; for scope in scopes.iter_mut() { - target = build_diverge_scope(hir.tcx(), cfg, &unit_temp, span, scope, target); + target = build_diverge_scope(hir.tcx(), cfg, &unit_temp, span, scope, target, generator_drop); } Some(target) } @@ -729,9 +855,11 @@ fn build_scope_drops<'tcx>(cfg: &mut CFG<'tcx>, scope: &Scope<'tcx>, earlier_scopes: &[Scope<'tcx>], mut block: BasicBlock, - arg_count: usize) + arg_count: usize, + generator_drop: bool) -> BlockAnd<()> { - let mut iter = scope.drops.iter().rev().peekable(); + + let mut iter = scope.drops(generator_drop).iter().rev().peekable(); while let Some(drop_data) = iter.next() { let source_info = scope.source_info(drop_data.span); if let DropKind::Value { .. } = drop_data.kind { @@ -739,14 +867,14 @@ fn build_scope_drops<'tcx>(cfg: &mut CFG<'tcx>, // for us to diverge into in case the drop panics. let on_diverge = iter.peek().iter().filter_map(|dd| { match dd.kind { - DropKind::Value { cached_block } => cached_block, + DropKind::Value { cached_block } => cached_block.get(generator_drop), DropKind::Storage => None } }).next(); // If there’s no `cached_block`s within current scope, // we must look for one in the enclosing scope. let on_diverge = on_diverge.or_else(||{ - earlier_scopes.iter().rev().flat_map(|s| s.cached_block()).next() + earlier_scopes.iter().rev().flat_map(|s| s.cached_block(generator_drop)).next() }); let next = cfg.start_new_block(); cfg.terminate(block, source_info, TerminatorKind::Drop { @@ -759,6 +887,11 @@ fn build_scope_drops<'tcx>(cfg: &mut CFG<'tcx>, match drop_data.kind { DropKind::Value { .. } | DropKind::Storage => { + // We do not need to emit these for generator drops + if generator_drop { + continue + } + // Only temps and vars need their storage dead. match drop_data.location { Lvalue::Local(index) if index.index() > arg_count => {} @@ -780,7 +913,8 @@ fn build_diverge_scope<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, unit_temp: &Lvalue<'tcx>, span: Span, scope: &mut Scope<'tcx>, - mut target: BasicBlock) + mut target: BasicBlock, + generator_drop: bool) -> BasicBlock { // Build up the drops in **reverse** order. The end result will @@ -794,7 +928,7 @@ fn build_diverge_scope<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, // The code in this function reads from right to left. At each // point, we check for cached blocks representing the // remainder. If everything is cached, we'll just walk right to - // left reading the cached results but never created anything. + // left reading the cached results but never create anything. let visibility_scope = scope.visibility_scope; let source_info = |span| SourceInfo { @@ -804,13 +938,13 @@ fn build_diverge_scope<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, // Next, build up any free. if let Some(ref mut free_data) = scope.free { - target = if let Some(cached_block) = free_data.cached_block { + target = if let Some(cached_block) = free_data.cached_block.get(generator_drop) { cached_block } else { let into = cfg.start_new_cleanup_block(); cfg.terminate(into, source_info(free_data.span), build_free(tcx, unit_temp, free_data, target)); - free_data.cached_block = Some(into); + *free_data.cached_block.ref_mut(generator_drop) = Some(into); into }; } @@ -818,7 +952,7 @@ fn build_diverge_scope<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, // Next, build up the drops. Here we iterate the vector in // *forward* order, so that we generate drops[0] first (right to // left in diagram above). - for (j, drop_data) in scope.drops.iter_mut().enumerate() { + for (j, drop_data) in scope.drops_mut(generator_drop).iter_mut().enumerate() { debug!("build_diverge_scope drop_data[{}]: {:?}", j, drop_data); // Only full value drops are emitted in the diverging path, // not StorageDead. @@ -829,7 +963,7 @@ fn build_diverge_scope<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, // match the behavior of clang, but on inspection eddyb says // this is not what clang does. let cached_block = match drop_data.kind { - DropKind::Value { ref mut cached_block } => cached_block, + DropKind::Value { ref mut cached_block } => cached_block.ref_mut(generator_drop), DropKind::Storage => continue }; target = if let Some(cached_block) = *cached_block { diff --git a/src/librustc_mir/dataflow/drop_flag_effects.rs b/src/librustc_mir/dataflow/drop_flag_effects.rs index daafbecc5dfa3..2f8e932a7382a 100644 --- a/src/librustc_mir/dataflow/drop_flag_effects.rs +++ b/src/librustc_mir/dataflow/drop_flag_effects.rs @@ -299,6 +299,11 @@ pub(crate) fn drop_flag_effects_for_location<'a, 'tcx, F>( move_data.rev_lookup.find(location), |moi| callback(moi, DropFlagState::Present)) } + mir::TerminatorKind::Suspend { .. } => { + on_lookup_result_bits(tcx, mir, move_data, + move_data.rev_lookup.find(&Mir::impl_arg_lvalue()), + |moi| callback(moi, DropFlagState::Present)) + } _ => { // other terminators do not contain move-ins } diff --git a/src/librustc_mir/dataflow/mod.rs b/src/librustc_mir/dataflow/mod.rs index d7ad9f9c09aef..6eebe9da9f080 100644 --- a/src/librustc_mir/dataflow/mod.rs +++ b/src/librustc_mir/dataflow/mod.rs @@ -452,15 +452,21 @@ impl<'a, 'tcx: 'a, D> DataflowAnalysis<'a, 'tcx, D> match bb_data.terminator().kind { mir::TerminatorKind::Return | mir::TerminatorKind::Resume | + mir::TerminatorKind::GeneratorDrop | mir::TerminatorKind::Unreachable => {} mir::TerminatorKind::Goto { ref target } | mir::TerminatorKind::Assert { ref target, cleanup: None, .. } | + mir::TerminatorKind::Suspend { resume: ref target, drop: None, .. } | mir::TerminatorKind::Drop { ref target, location: _, unwind: None } | mir::TerminatorKind::DropAndReplace { ref target, value: _, location: _, unwind: None } => { self.propagate_bits_into_entry_set_for(in_out, changed, target); } + mir::TerminatorKind::Suspend { resume: ref target, drop: Some(ref drop), .. } => { + self.propagate_bits_into_entry_set_for(in_out, changed, target); + self.propagate_bits_into_entry_set_for(in_out, changed, drop); + } mir::TerminatorKind::Assert { ref target, cleanup: Some(ref unwind), .. } | mir::TerminatorKind::Drop { ref target, location: _, unwind: Some(ref unwind) } | mir::TerminatorKind::DropAndReplace { diff --git a/src/librustc_mir/dataflow/move_paths/mod.rs b/src/librustc_mir/dataflow/move_paths/mod.rs index fbf977b98f901..cc12ae6abfc14 100644 --- a/src/librustc_mir/dataflow/move_paths/mod.rs +++ b/src/librustc_mir/dataflow/move_paths/mod.rs @@ -462,6 +462,7 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> { match term.kind { TerminatorKind::Goto { target: _ } | TerminatorKind::Resume | + TerminatorKind::GeneratorDrop | TerminatorKind::Unreachable => { } TerminatorKind::Return => { @@ -473,6 +474,11 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> { // branching terminators - these don't move anything } + TerminatorKind::Suspend { ref value, .. } => { + self.create_move_path(&Mir::impl_arg_lvalue()); + self.gather_operand(loc, value); + } + TerminatorKind::Drop { ref location, target: _, unwind: _ } => { self.gather_move(loc, location); } diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index 06a0c4ff213da..ca634ffef5446 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -428,10 +428,11 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, } } - hir::ExprClosure(..) => { + hir::ExprClosure(.., gen) => { let closure_ty = cx.tables().expr_ty(expr); let (def_id, substs) = match closure_ty.sty { - ty::TyClosure(def_id, substs) => (def_id, substs), + ty::TyClosure(def_id, substs) | + ty::TyGenerator(def_id, substs, _) => (def_id, substs), _ => { span_bug!(expr.span, "closure expr w/o closure type: {:?}", closure_ty); } @@ -446,6 +447,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, closure_id: def_id, substs: substs, upvars: upvars, + generator: gen.is_some(), } } @@ -564,6 +566,9 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, } hir::ExprArray(ref fields) => ExprKind::Array { fields: fields.to_ref() }, hir::ExprTup(ref fields) => ExprKind::Tuple { fields: fields.to_ref() }, + + hir::ExprImplArg(_) => ExprKind::ImplArg, + hir::ExprSuspend(ref v) => ExprKind::Suspend { value: v.to_ref() }, }; Expr { @@ -698,7 +703,8 @@ fn convert_var<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, }); let region = cx.tcx.mk_region(region); - let self_expr = match cx.tcx.closure_kind(closure_def_id) { + let self_expr = if let ty::TyClosure(..) = closure_ty.sty { + match cx.tcx.closure_kind(closure_def_id) { ty::ClosureKind::Fn => { let ref_closure_ty = cx.tcx.mk_ref(region, ty::TypeAndMut { @@ -748,6 +754,14 @@ fn convert_var<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, kind: ExprKind::SelfRef, } } + } + } else { + Expr { + ty: closure_ty, + temp_lifetime: temp_lifetime, + span: expr.span, + kind: ExprKind::SelfRef, + } }; // at this point we have `self.n`, which loads up the upvar diff --git a/src/librustc_mir/hair/cx/mod.rs b/src/librustc_mir/hair/cx/mod.rs index 2f4ab36d394b0..46df40e42871d 100644 --- a/src/librustc_mir/hair/cx/mod.rs +++ b/src/librustc_mir/hair/cx/mod.rs @@ -61,6 +61,7 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> { let constness = match src { MirSource::Const(_) | MirSource::Static(..) => hir::Constness::Const, + MirSource::GeneratorDrop(..) => hir::Constness::NotConst, MirSource::Fn(id) => { let fn_like = FnLikeNode::from_node(infcx.tcx.hir.get(id)); fn_like.map_or(hir::Constness::NotConst, |f| f.constness()) diff --git a/src/librustc_mir/hair/mod.rs b/src/librustc_mir/hair/mod.rs index bb11cce748751..dece9a974f172 100644 --- a/src/librustc_mir/hair/mod.rs +++ b/src/librustc_mir/hair/mod.rs @@ -239,6 +239,7 @@ pub enum ExprKind<'tcx> { closure_id: DefId, substs: ClosureSubsts<'tcx>, upvars: Vec>, + generator: bool, }, Literal { literal: Literal<'tcx>, @@ -248,6 +249,10 @@ pub enum ExprKind<'tcx> { outputs: Vec>, inputs: Vec> }, + ImplArg, + Suspend { + value: ExprRef<'tcx>, + }, } #[derive(Clone, Debug)] diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs index 11ad5d1509d29..bc04be18ac656 100644 --- a/src/librustc_mir/shim.rs +++ b/src/librustc_mir/shim.rs @@ -148,6 +148,12 @@ fn build_drop_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>, { debug!("build_drop_shim(def_id={:?}, ty={:?})", def_id, ty); + // Check if this is a generator, if so, return the drop glue for it + if let Some(&ty::TyS { sty: ty::TyGenerator(gen_def_id, substs, _), .. }) = ty { + let mir = &**tcx.optimized_mir(gen_def_id).generator_drop.as_ref().unwrap(); + return mir.subst(tcx, substs.substs); + } + let substs = if let Some(ty) = ty { tcx.mk_substs(iter::once(Kind::from(ty))) } else { @@ -178,6 +184,7 @@ fn build_drop_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>, ), IndexVec::new(), sig.output(), + None, local_decls_for_sig(&sig, span), sig.inputs().len(), vec![], @@ -213,10 +220,10 @@ fn build_drop_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>, } pub struct DropShimElaborator<'a, 'tcx: 'a> { - mir: &'a Mir<'tcx>, - patch: MirPatch<'tcx>, - tcx: ty::TyCtxt<'a, 'tcx, 'tcx>, - param_env: ty::ParamEnv<'tcx>, + pub mir: &'a Mir<'tcx>, + pub patch: MirPatch<'tcx>, + pub tcx: ty::TyCtxt<'a, 'tcx, 'tcx>, + pub param_env: ty::ParamEnv<'tcx>, } impl<'a, 'tcx> fmt::Debug for DropShimElaborator<'a, 'tcx> { @@ -390,6 +397,7 @@ fn build_call_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>, ), IndexVec::new(), sig.output(), + None, local_decls, sig.inputs().len(), vec![], @@ -461,6 +469,7 @@ pub fn build_adt_ctor<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a, 'gcx, 'tcx>, ), IndexVec::new(), sig.output(), + None, local_decls, sig.inputs().len(), vec![], diff --git a/src/librustc_mir/transform/copy_prop.rs b/src/librustc_mir/transform/copy_prop.rs index dec0717e9e383..d3bbd4d78ed38 100644 --- a/src/librustc_mir/transform/copy_prop.rs +++ b/src/librustc_mir/transform/copy_prop.rs @@ -60,6 +60,7 @@ impl MirPass for CopyPropagation { return } } + MirSource::GeneratorDrop(_) => (), } // We only run when the MIR optimization level is > 1. diff --git a/src/librustc_mir/transform/elaborate_drops.rs b/src/librustc_mir/transform/elaborate_drops.rs index b158cb43ce7a9..387d769e01f67 100644 --- a/src/librustc_mir/transform/elaborate_drops.rs +++ b/src/librustc_mir/transform/elaborate_drops.rs @@ -96,15 +96,20 @@ fn find_dead_unwinds<'a, 'tcx>( MaybeInitializedLvals::new(tcx, mir, &env), |bd, p| &bd.move_data().move_paths[p]); for (bb, bb_data) in mir.basic_blocks().iter_enumerated() { - match bb_data.terminator().kind { + let impl_arg = Mir::impl_arg_lvalue(); + let location = match bb_data.terminator().kind { TerminatorKind::Drop { ref location, unwind: Some(_), .. } | - TerminatorKind::DropAndReplace { ref location, unwind: Some(_), .. } => { + TerminatorKind::DropAndReplace { ref location, unwind: Some(_), .. } => location, + TerminatorKind::Suspend { .. } => &impl_arg, + _ => continue, + }; + let mut init_data = InitializationData { live: flow_inits.sets().on_entry_set_for(bb.index()).to_owned(), dead: IdxSetBuf::new_empty(env.move_data.move_paths.len()), }; debug!("find_dead_unwinds @ {:?}: {:?}; init_data={:?}", - bb, bb_data, init_data.live); + bb, bb_data, init_data.live); for stmt in 0..bb_data.statements.len() { let loc = Location { block: bb, statement_index: stmt }; init_data.apply_location(tcx, mir, env, loc); @@ -130,9 +135,6 @@ fn find_dead_unwinds<'a, 'tcx>( if !maybe_live { dead_unwinds.add(&bb); } - } - _ => {} - } } dead_unwinds @@ -342,9 +344,11 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { { for (bb, data) in self.mir.basic_blocks().iter_enumerated() { let terminator = data.terminator(); + let impl_arg = Mir::impl_arg_lvalue(); let location = match terminator.kind { TerminatorKind::Drop { ref location, .. } | TerminatorKind::DropAndReplace { ref location, .. } => location, + TerminatorKind::Suspend { .. } => &impl_arg, _ => continue }; diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs new file mode 100644 index 0000000000000..5f77096e0c361 --- /dev/null +++ b/src/librustc_mir/transform/generator.rs @@ -0,0 +1,739 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Transforming generator bodies into a state machines + +#![allow(warnings)] + +use rustc::hir; +use rustc::hir::def_id::DefId; +use rustc::middle::const_val::ConstVal; +use rustc::mir::*; +use rustc::mir::transform::{MirPass, MirSource}; +use rustc::mir::visit::{LvalueContext, MutVisitor}; +use rustc::ty::{self, TyCtxt, AdtDef, Ty, GeneratorInterior}; +use rustc::ty::subst::{Kind, Substs}; +use util::dump_mir; +use util::liveness; +use rustc_const_math::ConstInt; +use rustc_data_structures::bitvec::BitVector; +use rustc_data_structures::indexed_vec::Idx; +use std::collections::HashMap; +use std::borrow::Cow; +use std::iter::once; +use syntax::ast::NodeId; +use transform::simplify; + +pub struct StateTransform; + +struct RenameLocalVisitor { + from: Local, + to: Local, +} + +impl<'tcx> MutVisitor<'tcx> for RenameLocalVisitor { + fn visit_local(&mut self, + local: &mut Local) { + if *local == self.from { + *local = self.to; + } + } +} + +struct SwapLocalVisitor { + a: Local, + b: Local, +} + +impl<'tcx> MutVisitor<'tcx> for SwapLocalVisitor { + fn visit_local(&mut self, + local: &mut Local) { + if *local == self.a { + *local = self.b; + } else if *local == self.b { + *local = self.a; + } + } +} + +struct InsertLocalVisitor { + local: Local, +} + +impl<'tcx> MutVisitor<'tcx> for InsertLocalVisitor { + fn visit_local(&mut self, + local: &mut Local) { + if local.index() >= self.local.index() { + *local = Local::new(local.index() + 1); + } + } +} + +struct DerefArgVisitor; + +impl<'tcx> MutVisitor<'tcx> for DerefArgVisitor { + fn visit_lvalue(&mut self, + lvalue: &mut Lvalue<'tcx>, + context: LvalueContext<'tcx>, + location: Location) { + if *lvalue == Lvalue::Local(Local::new(2)) { + *lvalue = Lvalue::Projection(Box::new(Projection { + base: lvalue.clone(), + elem: ProjectionElem::Deref, + })); + } else { + self.super_lvalue(lvalue, context, location); + } + } +} + +struct TransformVisitor<'a, 'tcx: 'a> { + tcx: TyCtxt<'a, 'tcx, 'tcx>, + state_adt_ref: &'tcx AdtDef, + state_substs: &'tcx Substs<'tcx>, + remap: HashMap, usize)>, + bb_target_count: u32, + bb_targets: HashMap<(BasicBlock, Option), u32>, + new_ret_local: Local, + return_block: BasicBlock, + state_field: usize, +} + +impl<'a, 'tcx> TransformVisitor<'a, 'tcx> { + fn make_state(&self, idx: usize, val: Operand<'tcx>) -> Rvalue<'tcx> { + let adt = AggregateKind::Adt(self.state_adt_ref, idx, self.state_substs, None); + Rvalue::Aggregate(box adt, vec![val]) + } + + fn make_field(&self, idx: usize, ty: Ty<'tcx>) -> Lvalue<'tcx> { + let base = Lvalue::Local(Local::new(1)); + let base = Lvalue::Projection(Box::new(Projection { + base: base, + elem: ProjectionElem::Deref, + })); + let field = Projection { + base: base, + elem: ProjectionElem::Field(Field::new(idx), ty), + }; + Lvalue::Projection(Box::new(field)) + } + + fn set_state(&self, state_disc: u32, source_info: SourceInfo) -> Statement<'tcx> { + let state = self.make_field(self.state_field, self.tcx.types.u32); + let val = Operand::Constant(box Constant { + span: source_info.span, + ty: self.tcx.types.u32, + literal: Literal::Value { + value: ConstVal::Integral(ConstInt::U32(state_disc)), + }, + }); + Statement { + source_info, + kind: StatementKind::Assign(state, Rvalue::Use(val)), + } + } +} + +impl<'a, 'tcx> MutVisitor<'tcx> for TransformVisitor<'a, 'tcx> { + fn visit_lvalue(&mut self, + lvalue: &mut Lvalue<'tcx>, + context: LvalueContext<'tcx>, + location: Location) { + if let Lvalue::Local(l) = *lvalue { + if let Some(&(ty, idx)) = self.remap.get(&l) { + *lvalue = self.make_field(idx, ty); + } + } else { + self.super_lvalue(lvalue, context, location); + } + } + + fn visit_basic_block_data(&mut self, + block: BasicBlock, + data: &mut BasicBlockData<'tcx>) { + let ret_val = match data.terminator().kind { + TerminatorKind::Return => Some((1, + self.return_block, + Operand::Consume(Lvalue::Local(self.new_ret_local)), + None)), + TerminatorKind::Suspend { ref value, resume, drop } => Some((0, + resume, + value.clone(), + drop)), + _ => None + }; + + data.retain_statements(|s| { + match s.kind { + StatementKind::StorageLive(ref l) | StatementKind::StorageDead(ref l) => { + if let Lvalue::Local(l) = *l { + !self.remap.contains_key(&l) + } else { + true + } + } + _ => true + } + }); + + ret_val.map(|(state_idx, resume, v, drop)| { + let bb_idx = { + let bb_targets = &mut self.bb_targets; + let bb_target = &mut self.bb_target_count; + *bb_targets.entry((resume, drop)).or_insert_with(|| { + let target = *bb_target; + *bb_target = target.checked_add(1).unwrap(); + target + }) + }; + let source_info = data.terminator().source_info; + data.statements.push(self.set_state(bb_idx, source_info)); + data.statements.push(Statement { + source_info, + kind: StatementKind::Assign(Lvalue::Local(RETURN_POINTER), + self.make_state(state_idx, v)), + }); + data.terminator.as_mut().unwrap().kind = TerminatorKind::Return; + }); + + self.super_basic_block_data(block, data); + } +} + +fn get_body_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, node_id: NodeId) -> (bool, hir::BodyId) { + // Figure out what primary body this item has. + match tcx.hir.get(node_id) { + hir::map::NodeItem(item) => { + match item.node { + hir::ItemConst(_, body) | + hir::ItemStatic(_, _, body) | + hir::ItemFn(.., body) => (false, body), + _ => bug!(), + } + } + hir::map::NodeTraitItem(item) => { + match item.node { + hir::TraitItemKind::Const(_, Some(body)) | + hir::TraitItemKind::Method(_, + hir::TraitMethod::Provided(body)) => (false, body), + _ => bug!(), + } + } + hir::map::NodeImplItem(item) => { + match item.node { + hir::ImplItemKind::Const(_, body) | + hir::ImplItemKind::Method(_, body) => (false, body), + _ => bug!(), + } + } + hir::map::NodeExpr(expr) => { + // FIXME(eddyb) Closures should have separate + // function definition IDs and expression IDs. + // Type-checking should not let closures get + // this far in a constant position. + // Assume that everything other than closures + // is a constant "initializer" expression. + match expr.node { + hir::ExprClosure(_, _, body, _, _) => (true, body), + _ => (false, hir::BodyId { node_id: expr.id }) + } + } + _ => bug!(), + } +} + +fn ensure_generator_state_argument<'a, 'tcx>( + tcx: TyCtxt<'a, 'tcx, 'tcx>, + node_id: NodeId, + def_id: DefId, + mir: &mut Mir<'tcx>) -> (Ty<'tcx>, GeneratorInterior<'tcx>) { + let interior = *tcx.typeck_tables_of(def_id).generator_interiors.get(&node_id).unwrap(); + + let gen_ty = mir.local_decls.raw[2].ty; + + let region = ty::ReFree(ty::FreeRegion { + scope: def_id, + bound_region: ty::BoundRegion::BrEnv, + }); + + let region = tcx.mk_region(region); + + let ref_gen_ty = tcx.mk_ref(region, ty::TypeAndMut { + ty: gen_ty, + mutbl: hir::MutMutable + }); + + // Replace the by value generator argument + mir.local_decls.raw[2].ty = ref_gen_ty; + + // Add a deref to accesses of the generator state for upvars + DerefArgVisitor.visit_mir(mir); + + // Swap generator and implicit argument + SwapLocalVisitor { + a: Local::new(1), + b: Local::new(2), + }.visit_mir(mir); + + mir.local_decls.raw[..].swap(1, 2); + + (gen_ty, interior) +} + +fn replace_result_variable<'tcx>(ret_ty: Ty<'tcx>, + mir: &mut Mir<'tcx>) -> Local { + let source_info = SourceInfo { + span: mir.span, + scope: ARGUMENT_VISIBILITY_SCOPE, + }; + + let new_ret = LocalDecl { + mutability: Mutability::Mut, + ty: ret_ty, + name: None, + source_info, + is_user_variable: false, + }; + let new_ret_local = Local::new(mir.local_decls.len()); + mir.local_decls.push(new_ret); + mir.local_decls.swap(0, new_ret_local.index()); + + RenameLocalVisitor { + from: RETURN_POINTER, + to: new_ret_local, + }.visit_mir(mir); + + new_ret_local +} + +fn locals_live_across_suspend_points<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + mir: &Mir<'tcx>, + source: MirSource) -> liveness::LocalSet { + use rustc_data_structures::indexed_set::IdxSetBuf; + let mut set = liveness::LocalSet::new_empty(mir.local_decls.len()); + let result = liveness::liveness_of_locals(mir); + liveness::dump_mir(tcx, "generator_liveness", source, mir, &result); + + for (block, data) in mir.basic_blocks().iter_enumerated() { + if let TerminatorKind::Suspend { .. } = data.terminator().kind { + set.union(&result.outs[block]); + } + } + + // The implicit argument is defined after each suspend point so it can never be live in a suspend point. + set.remove(&Local::new(2)); + + // The generator argument is ignored + set.remove(&Local::new(1)); + + set +} + +fn compute_layout<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + def_id: DefId, + source: MirSource, + interior: GeneratorInterior<'tcx>, + mir: &mut Mir<'tcx>) -> (HashMap, usize)>, GeneratorLayout<'tcx>) { + let source_info = SourceInfo { + span: mir.span, + scope: ARGUMENT_VISIBILITY_SCOPE, + }; + + let mut live_locals = locals_live_across_suspend_points(tcx, mir, source); + + let allowed = tcx.erase_regions(&interior.as_slice()); + + for (local, decl) in mir.local_decls.iter_enumerated() { + if !live_locals.contains(&local) { + continue; + } + if !allowed.contains(&decl.ty) { + tcx.sess.span_warn(mir.span, + &format!("generator contains type {} in MIR, but typeck only knows about {}", + decl.ty, + interior)); + } + } + + let upvar_len = mir.upvar_decls.len(); + let live_decls : Vec<_> = mir.local_decls.iter_enumerated_mut().filter(|&(local, _)| live_locals.contains(&local)).collect(); + + let mut remap = HashMap::new(); + let unit = tcx.mk_nil(); + let mut vars: Vec<_> = live_decls.into_iter().enumerate().map(|(idx, (local, decl))| { + let var = decl.clone(); + *decl = LocalDecl { + mutability: Mutability::Mut, + ty: unit, + name: None, + source_info, + is_user_variable: false, + }; + remap.insert(local, (var.ty, upvar_len + 1 + idx)); + var + }).collect(); + + let layout = GeneratorLayout { + fields: vars + }; + + (remap, layout) +} + +fn insert_entry_point<'tcx>(mir: &mut Mir<'tcx>, + block: BasicBlockData<'tcx>) { + mir.basic_blocks_mut().raw.insert(0, block); + + let blocks = mir.basic_blocks_mut().iter_mut(); + + for target in blocks.flat_map(|b| b.terminator_mut().successors_mut()) { + *target = BasicBlock::new(target.index() + 1); + } +} + +fn elaborate_generator_drops<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + def_id: DefId, + mir: &mut Mir<'tcx>) { + use util::elaborate_drops::{elaborate_drop, Unwind, DropElaborator, DropStyle, DropFlagMode}; + use util::patch::MirPatch; + use shim::DropShimElaborator; + + let param_env = tcx.param_env(def_id); + let gen = Local::new(2); + + for block in mir.basic_blocks().indices() { + let (target, unwind, source_info) = match mir.basic_blocks()[block].terminator() { + &Terminator { + source_info, + kind: TerminatorKind::Drop { + location: Lvalue::Local(local), + target, + unwind + } + } if local == gen => (target, unwind, source_info), + _ => continue, + }; + let unwind = if let Some(unwind) = unwind { + Unwind::To(unwind) + } else { + Unwind::InCleanup + }; + let patch = { + let mut elaborator = DropShimElaborator { + mir: &mir, + patch: MirPatch::new(mir), + tcx, + param_env + }; + elaborate_drop( + &mut elaborator, + source_info, + &Lvalue::Local(gen), + (), + target, + unwind, + block + ); + elaborator.patch + }; + patch.apply(mir); + } +} + +fn generate_drop<'a, 'tcx>( + tcx: TyCtxt<'a, 'tcx, 'tcx>, + transform: &TransformVisitor<'a, 'tcx>, + node_id: NodeId, + def_id: DefId, + source: MirSource, + gen_ty: Ty<'tcx>, + mir: &mut Mir<'tcx>) { + let source_info = SourceInfo { + span: mir.span, + scope: ARGUMENT_VISIBILITY_SCOPE, + }; + + mir.basic_blocks_mut().push(BasicBlockData { + statements: Vec::new(), + terminator: Some(Terminator { + source_info, + kind: TerminatorKind::Return, + }), + is_cleanup: false, + }); + + let cases: Vec<_> = transform.bb_targets.iter().filter_map(|(&(r, u), &s)| { + u.map(|d| (s, d)) + }).collect(); + + // The poisoned state 1 falls through to the default case which is just to return + + let switch = TerminatorKind::SwitchInt { + discr: Operand::Consume(transform.make_field(transform.state_field, tcx.types.u32)), + switch_ty: tcx.types.u32, + values: Cow::from(cases.iter().map(|&(i, _)| { + ConstInt::U32(i) + }).collect::>()), + targets: cases.iter().map(|&(_, d)| d).chain(once(transform.return_block)).collect(), + }; + + insert_entry_point(mir, BasicBlockData { + statements: Vec::new(), + terminator: Some(Terminator { + source_info, + kind: switch, + }), + is_cleanup: false, + }); + + for block in mir.basic_blocks_mut() { + let kind = &mut block.terminator_mut().kind; + if let TerminatorKind::GeneratorDrop = *kind { + *kind = TerminatorKind::Return; + } + } + + // Remove the implicit argument + mir.arg_count = 1; + mir.local_decls.raw.pop(); + + // Replace the return variable + let source_info = SourceInfo { + span: mir.span, + scope: ARGUMENT_VISIBILITY_SCOPE, + }; + + mir.return_ty = tcx.mk_nil(); + mir.local_decls[RETURN_POINTER] = LocalDecl { + mutability: Mutability::Mut, + ty: tcx.mk_nil(), + name: None, + source_info, + is_user_variable: false, + }; + + // Change the generator argument from &mut to *mut + mir.local_decls[Local::new(1)] = LocalDecl { + mutability: Mutability::Mut, + ty: tcx.mk_ptr(ty::TypeAndMut { + ty: gen_ty, + mutbl: hir::Mutability::MutMutable, + }), + name: None, + source_info, + is_user_variable: false, + }; + + // Make sure we remove dead blocks to remove + // unrelated code from the resume part of the function + simplify::remove_dead_blocks(mir); + + dump_mir(tcx, None, "generator_drop", &0, source, mir); +} + +fn generate_resume<'a, 'tcx>( + tcx: TyCtxt<'a, 'tcx, 'tcx>, + mut transform: TransformVisitor<'a, 'tcx>, + node_id: NodeId, + def_id: DefId, + source: MirSource, + mir: &mut Mir<'tcx>) { + // Poison the generator when it unwinds + for block in mir.basic_blocks_mut() { + let source_info = block.terminator().source_info; + if let &TerminatorKind::Resume = &block.terminator().kind { + block.statements.push(transform.set_state(1, source_info)); + } + } + + let drop_arg = mir.local_decls.raw[2].ty.needs_drop(tcx, tcx.param_env(def_id)); + + let cleanup = if drop_arg { + Some(BasicBlock::new(mir.basic_blocks().len() + 1)) + } else { + None + }; + + let term = TerminatorKind::Assert { + cond: Operand::Constant(box Constant { + span: mir.span, + ty: tcx.types.bool, + literal: Literal::Value { + value: ConstVal::Bool(false), + }, + }), + expected: true, + msg: AssertMessage::GeneratorResumedAfterReturn, + target: transform.return_block, + cleanup: cleanup, + }; + + let source_info = SourceInfo { + span: mir.span, + scope: ARGUMENT_VISIBILITY_SCOPE, + }; + + mir.basic_blocks_mut().push(BasicBlockData { + statements: Vec::new(), + terminator: Some(Terminator { + source_info, + kind: term, + }), + is_cleanup: false, + }); + + if drop_arg { + let resume_block = BasicBlock::new(mir.basic_blocks().len() + 1); + + let term = TerminatorKind::Drop { + location: Lvalue::Local(Local::new(2)), + target: resume_block, + unwind: None, + }; + + mir.basic_blocks_mut().push(BasicBlockData { + statements: Vec::new(), + terminator: Some(Terminator { + source_info, + kind: term, + }), + is_cleanup: true, + }); + + mir.basic_blocks_mut().push(BasicBlockData { + statements: Vec::new(), + terminator: Some(Terminator { + source_info, + kind: TerminatorKind::Resume, + }), + is_cleanup: true, + }); + } + + let poisoned_block = BasicBlock::new(mir.basic_blocks().len()); + + let term = TerminatorKind::Assert { + cond: Operand::Constant(box Constant { + span: mir.span, + ty: tcx.types.bool, + literal: Literal::Value { + value: ConstVal::Bool(false), + }, + }), + expected: true, + msg: AssertMessage::GeneratorResumedAfterPanic, + target: transform.return_block, + cleanup: cleanup, + }; + + mir.basic_blocks_mut().push(BasicBlockData { + statements: Vec::new(), + terminator: Some(Terminator { + source_info, + kind: term, + }), + is_cleanup: false, + }); + + transform.bb_targets.insert((poisoned_block, None), 1); + + let switch = TerminatorKind::SwitchInt { + discr: Operand::Consume(transform.make_field(transform.state_field, tcx.types.u32)), + switch_ty: tcx.types.u32, + values: Cow::from(transform.bb_targets.values().map(|&i| { + ConstInt::U32(i) + }).collect::>()), + targets: transform.bb_targets.keys().map(|&(k, _)| k).chain(once(transform.return_block)).collect(), + }; + + insert_entry_point(mir, BasicBlockData { + statements: Vec::new(), + terminator: Some(Terminator { + source_info, + kind: switch, + }), + is_cleanup: false, + }); + + // Make sure we remove dead blocks to remove + // unrelated code from the drop part of the function + simplify::remove_dead_blocks(mir); + + dump_mir(tcx, None, "generator_resume", &0, source, mir); +} + +impl MirPass for StateTransform { + fn run_pass<'a, 'tcx>(&self, + tcx: TyCtxt<'a, 'tcx, 'tcx>, + source: MirSource, + mir: &mut Mir<'tcx>) { + let suspend_ty = if let Some(suspend_ty) = mir.suspend_ty { + suspend_ty + } else { + // This only applies to generators + return + }; + + assert!(mir.generator_drop.is_none()); + + let node_id = source.item_id(); + let def_id = tcx.hir.local_def_id(source.item_id()); + + elaborate_generator_drops(tcx, def_id, mir); + + let (gen_ty, interior) = ensure_generator_state_argument(tcx, node_id, def_id, mir); + + let state_did = tcx.lang_items.gen_state().unwrap(); + let state_adt_ref = tcx.adt_def(state_did); + let state_substs = tcx.mk_substs([Kind::from(suspend_ty), + Kind::from(mir.return_ty)].iter()); + let ret_ty = tcx.mk_adt(state_adt_ref, state_substs); + + let new_ret_local = replace_result_variable(ret_ty, mir); + + let (remap, layout) = compute_layout(tcx, def_id, source, interior, mir); + + let return_block = BasicBlock::new(mir.basic_blocks().len()); + + let state_field = mir.upvar_decls.len(); + + let mut bb_targets = HashMap::new(); + bb_targets.insert((BasicBlock::new(0), None), 0); + + let mut transform = TransformVisitor { + tcx, + state_adt_ref, + state_substs, + remap, + bb_target_count: 2, + bb_targets, + new_ret_local, + return_block, + state_field, + }; + transform.visit_mir(mir); + + mir.return_ty = ret_ty; + mir.suspend_ty = None; + mir.arg_count = 2; + mir.spread_arg = None; + mir.generator_layout = Some(layout); + + dump_mir(tcx, None, "generator_post-transform", &0, source, mir); + + let mut drop_impl = mir.clone(); + + generate_drop(tcx, &transform, node_id, def_id, source, gen_ty, &mut drop_impl); + + mir.generator_drop = Some(box drop_impl); + + generate_resume(tcx, transform, node_id, def_id, source, mir); + } +} diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs index d3fee8045e6e3..1353be0046de3 100644 --- a/src/librustc_mir/transform/inline.rs +++ b/src/librustc_mir/transform/inline.rs @@ -175,6 +175,10 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { return false; } + // Cannot inline generators which haven't been transformed yet + if callee_mir.suspend_ty.is_some() { + return false; + } let attrs = tcx.get_attrs(callsite.callee); let hint = attr::find_inline_attr(None, &attrs[..]); @@ -652,6 +656,8 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Integrator<'a, 'tcx> { self.super_terminator_kind(block, kind, loc); match *kind { + TerminatorKind::GeneratorDrop | + TerminatorKind::Suspend { .. } => bug!(), TerminatorKind::Goto { ref mut target} => { *target = self.update_target(*target); } diff --git a/src/librustc_mir/transform/mod.rs b/src/librustc_mir/transform/mod.rs index c9c8ad0e0eb63..159d3a1f8eba9 100644 --- a/src/librustc_mir/transform/mod.rs +++ b/src/librustc_mir/transform/mod.rs @@ -39,6 +39,7 @@ pub mod dump_mir; pub mod deaggregator; pub mod instcombine; pub mod copy_prop; +pub mod generator; pub mod inline; pub mod nll; diff --git a/src/librustc_mir/transform/no_landing_pads.rs b/src/librustc_mir/transform/no_landing_pads.rs index 8595663ba18c4..d68d702696f51 100644 --- a/src/librustc_mir/transform/no_landing_pads.rs +++ b/src/librustc_mir/transform/no_landing_pads.rs @@ -43,6 +43,8 @@ impl<'tcx> MutVisitor<'tcx> for NoLandingPads { TerminatorKind::Resume | TerminatorKind::Return | TerminatorKind::Unreachable | + TerminatorKind::GeneratorDrop | + TerminatorKind::Suspend { .. } | TerminatorKind::SwitchInt { .. } => { /* nothing to do */ }, diff --git a/src/librustc_mir/transform/promote_consts.rs b/src/librustc_mir/transform/promote_consts.rs index e1c4602b045eb..f46a9a1a6fa9f 100644 --- a/src/librustc_mir/transform/promote_consts.rs +++ b/src/librustc_mir/transform/promote_consts.rs @@ -392,6 +392,7 @@ pub fn promote_candidates<'a, 'tcx>(mir: &mut Mir<'tcx>, }).into_iter().collect(), IndexVec::new(), ty, + None, initial_locals, 0, vec![], diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index 9bb0f07aa68ac..cb75dd9a52999 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -376,6 +376,8 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> { TerminatorKind::SwitchInt {..} | TerminatorKind::DropAndReplace { .. } | TerminatorKind::Resume | + TerminatorKind::GeneratorDrop | + TerminatorKind::Suspend { .. } | TerminatorKind::Unreachable => None, TerminatorKind::Return => { @@ -966,6 +968,7 @@ impl MirPass for QualifyAndPromoteConstants { } MirSource::Static(_, hir::MutImmutable) => Mode::Static, MirSource::Static(_, hir::MutMutable) => Mode::StaticMut, + MirSource::GeneratorDrop(_) | MirSource::Const(_) | MirSource::Promoted(..) => return }; diff --git a/src/librustc_mir/transform/type_check.rs b/src/librustc_mir/transform/type_check.rs index 7e6fccf30192c..b3cbe62321a15 100644 --- a/src/librustc_mir/transform/type_check.rs +++ b/src/librustc_mir/transform/type_check.rs @@ -34,7 +34,7 @@ fn mirbug(tcx: TyCtxt, span: Span, msg: &str) { macro_rules! span_mirbug { ($context:expr, $elem:expr, $($message:tt)*) => ({ mirbug($context.tcx(), $context.last_span, - &format!("broken MIR ({:?}): {}", $elem, format!($($message)*))) + &format!("broken MIR in {:?} ({:?}): {}", $context.body_id, $elem, format!($($message)*))) }) } @@ -60,6 +60,7 @@ struct TypeVerifier<'a, 'b: 'a, 'gcx: 'b+'tcx, 'tcx: 'b> { cx: &'a mut TypeChecker<'b, 'gcx, 'tcx>, mir: &'a Mir<'tcx>, last_span: Span, + body_id: ast::NodeId, errors_reported: bool } @@ -108,6 +109,7 @@ impl<'a, 'b, 'gcx, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'gcx, 'tcx> { impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> { fn new(cx: &'a mut TypeChecker<'b, 'gcx, 'tcx>, mir: &'a Mir<'tcx>) -> Self { TypeVerifier { + body_id: cx.body_id, cx: cx, mir: mir, last_span: mir.span, @@ -297,6 +299,19 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> { }) } } + ty::TyGenerator(def_id, substs, _) => { + // Try upvars first. `field_tys` requires final optimized MIR. + if let Some(ty) = substs.upvar_tys(def_id, tcx).nth(field.index()) { + return Ok(ty); + } + + return match substs.field_tys(def_id, tcx).nth(field.index()) { + Some(ty) => Ok(ty), + None => Err(FieldAccessError::OutOfRange { + field_count: substs.field_tys(def_id, tcx).count() + 1 + }) + } + } ty::TyTuple(tys, _) => { return match tys.get(field.index()) { Some(&ty) => Ok(ty), @@ -427,6 +442,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { TerminatorKind::Goto { .. } | TerminatorKind::Resume | TerminatorKind::Return | + TerminatorKind::GeneratorDrop | TerminatorKind::Unreachable | TerminatorKind::Drop { .. } => { // no checks needed for these @@ -493,6 +509,20 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { } } } + TerminatorKind::Suspend { ref value, .. } => { + let value_ty = value.ty(mir, tcx); + match mir.suspend_ty { + None => span_mirbug!(self, term, "suspend in non-generator"), + Some(ty) if ty != value_ty => { + span_mirbug!(self, + term, + "type of suspend value is ({:?}, but the suspend type is ({:?}", + value_ty, + ty); + } + _ => (), + } + } } } @@ -619,6 +649,20 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { span_mirbug!(self, block, "return on cleanup block") } } + TerminatorKind::GeneratorDrop { .. } => { + if is_cleanup { + span_mirbug!(self, block, "generator_drop in cleanup block") + } + } + TerminatorKind::Suspend { resume, drop, .. } => { + if is_cleanup { + span_mirbug!(self, block, "suspend in cleanup block") + } + self.assert_iscleanup(mir, block, resume, is_cleanup); + if let Some(drop) = drop { + self.assert_iscleanup(mir, block, drop, is_cleanup); + } + } TerminatorKind::Unreachable => {} TerminatorKind::Drop { target, unwind, .. } | TerminatorKind::DropAndReplace { target, unwind, .. } | diff --git a/src/librustc_mir/util/elaborate_drops.rs b/src/librustc_mir/util/elaborate_drops.rs index da7e218439cf0..203bda16a5c66 100644 --- a/src/librustc_mir/util/elaborate_drops.rs +++ b/src/librustc_mir/util/elaborate_drops.rs @@ -752,7 +752,8 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> fn open_drop<'a>(&mut self) -> BasicBlock { let ty = self.lvalue_ty(self.lvalue); match ty.sty { - ty::TyClosure(def_id, substs) => { + ty::TyClosure(def_id, substs) | + ty::TyGenerator(def_id, substs, _) => { let tys : Vec<_> = substs.upvar_tys(def_id, self.tcx()).collect(); self.open_drop_for_tuple(&tys) } diff --git a/src/librustc_mir/util/liveness.rs b/src/librustc_mir/util/liveness.rs new file mode 100644 index 0000000000000..be13472dba32a --- /dev/null +++ b/src/librustc_mir/util/liveness.rs @@ -0,0 +1,205 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Liveness analysis. + +// FIXME: Make sure this analysis uses proper MIR semantics. Also find out what the MIR semantics are. + +use rustc::mir::*; +use rustc::mir::visit::{LvalueContext, Visitor}; +use rustc_data_structures::indexed_vec::{IndexVec, Idx}; +use rustc_data_structures::indexed_set::IdxSetBuf; +use util::pretty::{write_basic_block, dump_enabled, write_mir_intro}; +use rustc::mir::transform::MirSource; +use rustc::ty::item_path; +use std::path::{PathBuf, Path}; +use std::fs; +use rustc::ty::TyCtxt; +use std::io::{self, Write}; + +pub type LocalSet = IdxSetBuf; + +#[derive(Eq, PartialEq, Clone)] +struct BlockInfo { + defs: LocalSet, + uses: LocalSet, +} + +struct BlockInfoVisitor { + pre_defs: LocalSet, + defs: LocalSet, + uses: LocalSet, +} + +impl<'tcx> Visitor<'tcx> for BlockInfoVisitor { + fn visit_lvalue(&mut self, + lvalue: &Lvalue<'tcx>, + context: LvalueContext<'tcx>, + location: Location) { + if let Lvalue::Local(local) = *lvalue { + match context { + LvalueContext::Store | LvalueContext::Call => { + self.defs.add(&local); + } + LvalueContext::Projection(..) | + LvalueContext::Borrow { .. } | + LvalueContext::Inspect | + LvalueContext::Consume | + LvalueContext::Drop => { + // Ignore uses which are already defined in this block + if !self.pre_defs.contains(&local) { + self.uses.add(&local); + } + } + LvalueContext::StorageLive | LvalueContext::StorageDead => (), + } + } + + self.super_lvalue(lvalue, context, location) + } +} + +fn block<'tcx>(b: &BasicBlockData<'tcx>, locals: usize) -> BlockInfo { + let mut visitor = BlockInfoVisitor { + pre_defs: LocalSet::new_empty(locals), + defs: LocalSet::new_empty(locals), + uses: LocalSet::new_empty(locals), + }; + + let dummy_location = Location { block: BasicBlock::new(0), statement_index: 0 }; + + for statement in &b.statements { + visitor.visit_statement(BasicBlock::new(0), statement, dummy_location); + visitor.pre_defs.union(&visitor.defs); + } + visitor.visit_terminator(BasicBlock::new(0), b.terminator(), dummy_location); + + BlockInfo { + defs: visitor.defs, + uses: visitor.uses, + } +} + +pub struct LivenessResult { + pub ins: IndexVec, + pub outs: IndexVec, +} + +pub fn liveness_of_locals<'tcx>(mir: &Mir<'tcx>) -> LivenessResult { + let locals = mir.local_decls.len(); + let def_use: IndexVec<_, _> = mir.basic_blocks().iter().map(|b| { + block(b, locals) + }).collect(); + + let copy = |from: &IndexVec, to: &mut IndexVec| { + for (i, set) in to.iter_enumerated_mut() { + set.clone_from(&from[i]); + } + }; + + let mut ins: IndexVec<_, _> = mir.basic_blocks() + .indices() + .map(|_| LocalSet::new_empty(locals)).collect(); + let mut outs = ins.clone(); + + let mut ins_ = ins.clone(); + let mut outs_ = outs.clone(); + + loop { + copy(&ins, &mut ins_); + copy(&outs, &mut outs_); + + for b in mir.basic_blocks().indices().rev() { + // out = ∪ {ins of successors} + outs[b].clear(); + for &successor in mir.basic_blocks()[b].terminator().successors().into_iter() { + outs[b].union(&ins[successor]); + } + + // in = use ∪ (out - def) + ins[b].clone_from(&outs[b]); + ins[b].subtract(&def_use[b].defs); + ins[b].union(&def_use[b].uses); + } + + if ins_ == ins && outs_ == outs { + break; + } + } + + LivenessResult { + ins, + outs, + } +} + +pub fn dump_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + pass_name: &str, + source: MirSource, + mir: &Mir<'tcx>, + result: &LivenessResult) { + if !dump_enabled(tcx, pass_name, source) { + return; + } + let node_path = item_path::with_forced_impl_filename_line(|| { // see notes on #41697 below + tcx.item_path_str(tcx.hir.local_def_id(source.item_id())) + }); + dump_matched_mir_node(tcx, pass_name, &node_path, + source, mir, result); +} + +fn dump_matched_mir_node<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + pass_name: &str, + node_path: &str, + source: MirSource, + mir: &Mir<'tcx>, + result: &LivenessResult) { + let mut file_path = PathBuf::new(); + if let Some(ref file_dir) = tcx.sess.opts.debugging_opts.dump_mir_dir { + let p = Path::new(file_dir); + file_path.push(p); + }; + let file_name = format!("rustc.node{}{}-liveness.mir", + source.item_id(), pass_name); + file_path.push(&file_name); + let _ = fs::File::create(&file_path).and_then(|mut file| { + writeln!(file, "// MIR local liveness analysis for `{}`", node_path)?; + writeln!(file, "// source = {:?}", source)?; + writeln!(file, "// pass_name = {}", pass_name)?; + writeln!(file, "")?; + write_mir_fn(tcx, source, mir, &mut file, result)?; + Ok(()) + }); +} + +pub fn write_mir_fn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + src: MirSource, + mir: &Mir<'tcx>, + w: &mut Write, + result: &LivenessResult) + -> io::Result<()> { + write_mir_intro(tcx, src, mir, w)?; + for block in mir.basic_blocks().indices() { + let print = |w: &mut Write, prefix, result: &IndexVec| { + let live: Vec = mir.local_decls.indices().filter(|i| result[block].contains(i)).map(|i| format!("{:?}", i)).collect(); + writeln!(w, "{} {{{}}}", prefix, live.join(", ")) + }; + print(w, " ", &result.ins)?; + write_basic_block(tcx, block, mir, w)?; + print(w, " ", &result.outs)?; + if block.index() + 1 != mir.basic_blocks().len() { + writeln!(w, "")?; + } + } + + writeln!(w, "}}")?; + Ok(()) +} + diff --git a/src/librustc_mir/util/mod.rs b/src/librustc_mir/util/mod.rs index 4386bab38c039..b03fd0196a369 100644 --- a/src/librustc_mir/util/mod.rs +++ b/src/librustc_mir/util/mod.rs @@ -14,6 +14,7 @@ pub mod patch; mod graphviz; mod pretty; +pub mod liveness; pub use self::pretty::{dump_enabled, dump_mir, write_mir_pretty}; pub use self::graphviz::{write_mir_graphviz}; diff --git a/src/librustc_mir/util/pretty.rs b/src/librustc_mir/util/pretty.rs index 22a8c4378d4c3..e3087efbfe626 100644 --- a/src/librustc_mir/util/pretty.rs +++ b/src/librustc_mir/util/pretty.rs @@ -94,6 +94,7 @@ fn dump_matched_mir_node<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, mir: &Mir<'tcx>) { let promotion_id = match source { MirSource::Promoted(_, id) => format!("-{:?}", id), + MirSource::GeneratorDrop(_) => format!("-drop"), _ => String::new() }; @@ -120,6 +121,9 @@ fn dump_matched_mir_node<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, writeln!(file, "// source = {:?}", source)?; writeln!(file, "// pass_name = {}", pass_name)?; writeln!(file, "// disambiguator = {}", disambiguator)?; + if let Some(ref layout) = mir.generator_layout { + writeln!(file, "// generator_layout = {:?}", layout)?; + } writeln!(file, "")?; write_mir_fn(tcx, source, mir, &mut file)?; Ok(()) @@ -176,7 +180,7 @@ pub fn write_mir_fn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } /// Write out a human-readable textual representation for the given basic block. -fn write_basic_block(tcx: TyCtxt, +pub fn write_basic_block(tcx: TyCtxt, block: BasicBlock, mir: &Mir, w: &mut Write) @@ -274,7 +278,7 @@ fn write_scope_tree(tcx: TyCtxt, /// Write out a human-readable textual representation of the MIR's `fn` type and the types of its /// local variables (both user-defined bindings and compiler temporaries). -fn write_mir_intro<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, +pub fn write_mir_intro<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, src: MirSource, mir: &Mir, w: &mut Write) @@ -322,28 +326,32 @@ fn write_mir_sig(tcx: TyCtxt, src: MirSource, mir: &Mir, w: &mut Write) MirSource::Const(_) => write!(w, "const")?, MirSource::Static(_, hir::MutImmutable) => write!(w, "static")?, MirSource::Static(_, hir::MutMutable) => write!(w, "static mut")?, - MirSource::Promoted(_, i) => write!(w, "{:?} in", i)? + MirSource::Promoted(_, i) => write!(w, "{:?} in", i)?, + MirSource::GeneratorDrop(_) => write!(w, "drop_glue")?, } item_path::with_forced_impl_filename_line(|| { // see notes on #41697 elsewhere write!(w, " {}", tcx.node_path_str(src.item_id())) })?; - if let MirSource::Fn(_) = src { - write!(w, "(")?; - - // fn argument types. - for (i, arg) in mir.args_iter().enumerate() { - if i != 0 { - write!(w, ", ")?; + match src { + MirSource::Fn(_) | MirSource::GeneratorDrop(_) => { + write!(w, "(")?; + + // fn argument types. + for (i, arg) in mir.args_iter().enumerate() { + if i != 0 { + write!(w, ", ")?; + } + write!(w, "{:?}: {}", Lvalue::Local(arg), mir.local_decls[arg].ty)?; } - write!(w, "{:?}: {}", Lvalue::Local(arg), mir.local_decls[arg].ty)?; - } - write!(w, ") -> {}", mir.return_ty) - } else { - assert_eq!(mir.arg_count, 0); - write!(w, ": {} =", mir.return_ty) + write!(w, ") -> {}", mir.return_ty) + } + _ => { + assert_eq!(mir.arg_count, 0); + write!(w, ": {} =", mir.return_ty) + } } } diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/consts.rs index a881bf9eac7bf..e3d665c4bcb1b 100644 --- a/src/librustc_passes/consts.rs +++ b/src/librustc_passes/consts.rs @@ -435,6 +435,10 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node hir::ExprAgain(_) | hir::ExprRet(_) | + // Generator expressions + hir::ExprSuspend(_) | + hir::ExprImplArg(_) | + // Expressions with side-effects. hir::ExprAssign(..) | hir::ExprAssignOp(..) | diff --git a/src/librustc_passes/loops.rs b/src/librustc_passes/loops.rs index 21a4c007fb192..8b6aeabcc12ef 100644 --- a/src/librustc_passes/loops.rs +++ b/src/librustc_passes/loops.rs @@ -81,7 +81,7 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> { hir::ExprLoop(ref b, _, source) => { self.with_context(Loop(LoopKind::Loop(source)), |v| v.visit_block(&b)); } - hir::ExprClosure(.., b, _) => { + hir::ExprClosure(.., b, _, _) => { self.with_context(Closure, |v| v.visit_nested_body(b)); } hir::ExprBreak(label, ref opt_expr) => { diff --git a/src/librustc_passes/mir_stats.rs b/src/librustc_passes/mir_stats.rs index 4dd38cc515c77..8df4559a01f31 100644 --- a/src/librustc_passes/mir_stats.rs +++ b/src/librustc_passes/mir_stats.rs @@ -158,6 +158,8 @@ impl<'a, 'tcx> mir_visit::Visitor<'tcx> for StatCollector<'a, 'tcx> { TerminatorKind::DropAndReplace { .. } => "TerminatorKind::DropAndReplace", TerminatorKind::Call { .. } => "TerminatorKind::Call", TerminatorKind::Assert { .. } => "TerminatorKind::Assert", + TerminatorKind::GeneratorDrop => "TerminatorKind::GeneratorDrop", + TerminatorKind::Suspend { .. } => "TerminatorKind::Suspend", }, kind); self.super_terminator_kind(block, kind, location); } @@ -169,6 +171,8 @@ impl<'a, 'tcx> mir_visit::Visitor<'tcx> for StatCollector<'a, 'tcx> { self.record(match *msg { AssertMessage::BoundsCheck { .. } => "AssertMessage::BoundsCheck", AssertMessage::Math(..) => "AssertMessage::Math", + AssertMessage::GeneratorResumedAfterReturn => "AssertMessage::GeneratorResumedAfterReturn", + AssertMessage::GeneratorResumedAfterPanic => "AssertMessage::GeneratorResumedAfterPanic", }, msg); self.super_assert_message(msg, location); } @@ -196,6 +200,7 @@ impl<'a, 'tcx> mir_visit::Visitor<'tcx> for StatCollector<'a, 'tcx> { AggregateKind::Tuple => "AggregateKind::Tuple", AggregateKind::Adt(..) => "AggregateKind::Adt", AggregateKind::Closure(..) => "AggregateKind::Closure", + AggregateKind::Generator(..) => "AggregateKind::Generator", }, kind); "Rvalue::Aggregate" diff --git a/src/librustc_trans/adt.rs b/src/librustc_trans/adt.rs index d1c1dd7436a5b..11db23732fba3 100644 --- a/src/librustc_trans/adt.rs +++ b/src/librustc_trans/adt.rs @@ -77,6 +77,12 @@ pub fn compute_fields<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>, if variant_index > 0 { bug!("{} is a closure, which only has one variant", t);} substs.upvar_tys(def_id, cx.tcx()).collect() }, + ty::TyGenerator(def_id, substs, _) => { + if variant_index > 0 { bug!("{} is a generator, which only has one variant", t);} + substs.field_tys(def_id, cx.tcx()).map(|t| { + cx.tcx().normalize_associated_type(&t) + }).collect() + }, _ => bug!("{} is not a type that can have fields.", t) } } diff --git a/src/librustc_trans/back/symbol_names.rs b/src/librustc_trans/back/symbol_names.rs index 10b66fb199108..d646b515bf41e 100644 --- a/src/librustc_trans/back/symbol_names.rs +++ b/src/librustc_trans/back/symbol_names.rs @@ -287,7 +287,9 @@ fn compute_symbol_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, instance: Instance let hash = get_symbol_hash(tcx, Some(def_id), instance_ty, Some(substs)); - SymbolPathBuffer::from_interned(tcx.def_symbol_name(def_id)).finish(hash) + let buffer = SymbolPathBuffer::from_interned(tcx.def_symbol_name(def_id)); + + buffer.finish(hash) } // Follow C++ namespace-mangling style, see diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs index b31295f4022ed..57edb14a42d41 100644 --- a/src/librustc_trans/collector.rs +++ b/src/librustc_trans/collector.rs @@ -629,6 +629,8 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { mir::TerminatorKind::Return | mir::TerminatorKind::Unreachable | mir::TerminatorKind::Assert { .. } => {} + mir::TerminatorKind::GeneratorDrop | + mir::TerminatorKind::Suspend { .. } => bug!(), } self.super_terminator_kind(block, kind, location); diff --git a/src/librustc_trans/common.rs b/src/librustc_trans/common.rs index 9b0803908b162..ebadba51bcf28 100644 --- a/src/librustc_trans/common.rs +++ b/src/librustc_trans/common.rs @@ -28,12 +28,13 @@ use type_::Type; use value::Value; use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::layout::{Layout, LayoutTyper}; -use rustc::ty::subst::{Subst, Substs}; +use rustc::ty::subst::{Kind, Subst, Substs}; use rustc::hir; use libc::{c_uint, c_char}; use std::iter; +use syntax::abi::Abi; use syntax::attr; use syntax::symbol::InternedString; use syntax_pos::Span; @@ -91,6 +92,16 @@ pub fn type_pair_fields<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) } })) } + ty::TyGenerator(def_id, substs, _) => { + let mut tys = substs.field_tys(def_id, ccx.tcx()); + tys.next().and_then(|first_ty| tys.next().and_then(|second_ty| { + if tys.next().is_some() { + None + } else { + Some([first_ty, second_ty]) + } + })) + } ty::TyTuple(tys, _) => { if tys.len() != 2 { return None; @@ -517,6 +528,28 @@ pub fn ty_fn_sig<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, sig.abi )) } + ty::TyGenerator(def_id, substs, _) => { + let tcx = ccx.tcx(); + let sig = tcx.generator_sig(def_id).unwrap().subst(tcx, substs.substs); + + let env_region = ty::ReLateBound(ty::DebruijnIndex::new(1), ty::BrEnv); + let env_ty = tcx.mk_mut_ref(tcx.mk_region(env_region), ty); + + sig.map_bound(|sig| { + let state_did = tcx.lang_items.gen_state().unwrap(); + let state_adt_ref = tcx.adt_def(state_did); + let state_substs = tcx.mk_substs([Kind::from(sig.suspend_ty), + Kind::from(sig.return_ty)].iter()); + let ret_ty = tcx.mk_adt(state_adt_ref, state_substs); + + tcx.mk_fn_sig(iter::once(env_ty).chain(iter::once(sig.impl_arg_ty)), + ret_ty, + false, + hir::Unsafety::Normal, + Abi::Rust + ) + }) + } _ => bug!("unexpected type {:?} to ty_fn_sig", ty) } } diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs index 61204b88e130e..399176461dfae 100644 --- a/src/librustc_trans/debuginfo/metadata.rs +++ b/src/librustc_trans/debuginfo/metadata.rs @@ -580,6 +580,16 @@ pub fn type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, unique_type_id, usage_site_span).finalize(cx) } + ty::TyGenerator(def_id, substs, _) => { + let upvar_tys : Vec<_> = substs.field_tys(def_id, cx.tcx()).map(|t| { + cx.tcx().normalize_associated_type(&t) + }).collect(); + prepare_tuple_metadata(cx, + t, + &upvar_tys, + unique_type_id, + usage_site_span).finalize(cx) + } ty::TyAdt(def, ..) => match def.adt_kind() { AdtKind::Struct => { prepare_struct_metadata(cx, diff --git a/src/librustc_trans/debuginfo/type_names.rs b/src/librustc_trans/debuginfo/type_names.rs index 6e36073107b56..826b4c09cc2d3 100644 --- a/src/librustc_trans/debuginfo/type_names.rs +++ b/src/librustc_trans/debuginfo/type_names.rs @@ -165,6 +165,9 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, ty::TyClosure(..) => { output.push_str("closure"); } + ty::TyGenerator(..) => { + output.push_str("generator"); + } ty::TyError | ty::TyInfer(_) | ty::TyProjection(..) | diff --git a/src/librustc_trans/mir/analyze.rs b/src/librustc_trans/mir/analyze.rs index 45afcf51b5203..54f2af3c179bd 100644 --- a/src/librustc_trans/mir/analyze.rs +++ b/src/librustc_trans/mir/analyze.rs @@ -215,8 +215,10 @@ pub fn cleanup_kinds<'a, 'tcx>(mir: &mir::Mir<'tcx>) -> IndexVec { + TerminatorKind::SwitchInt { .. } | + TerminatorKind::Suspend { .. } => { /* nothing to do */ } TerminatorKind::Call { cleanup: unwind, .. } | diff --git a/src/librustc_trans/mir/block.rs b/src/librustc_trans/mir/block.rs index 9bb29c340d983..a0369b80df0d8 100644 --- a/src/librustc_trans/mir/block.rs +++ b/src/librustc_trans/mir/block.rs @@ -374,6 +374,27 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { vec![msg_file_line_col], Some(ErrKind::Math(err.clone()))) } + mir::AssertMessage::GeneratorResumedAfterReturn | + mir::AssertMessage::GeneratorResumedAfterPanic => { + let str = if let mir::AssertMessage::GeneratorResumedAfterReturn = *msg { + "generator resumed after completion" + } else { + "generator resumed after panicking" + }; + let msg_str = Symbol::intern(str).as_str(); + let msg_str = C_str_slice(bcx.ccx, msg_str); + let msg_file_line = C_struct(bcx.ccx, + &[msg_str, filename, line], + false); + let align = llalign_of_min(bcx.ccx, common::val_ty(msg_file_line)); + let msg_file_line = consts::addr_of(bcx.ccx, + msg_file_line, + align, + "panic_loc"); + (lang_items::PanicFnLangItem, + vec![msg_file_line], + None) + } }; // If we know we always panic, and the error message @@ -557,6 +578,8 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { destination.as_ref().map(|&(_, target)| (ret_dest, sig.output(), target)), cleanup); } + mir::TerminatorKind::GeneratorDrop | + mir::TerminatorKind::Suspend { .. } => bug!("generator ops in trans"), } } diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs index 98e774a29877d..6f03a806a4148 100644 --- a/src/librustc_trans/mir/constant.rs +++ b/src/librustc_trans/mir/constant.rs @@ -322,6 +322,9 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { mir::AssertMessage::Math(ref err) => { ErrKind::Math(err.clone()) } + mir::AssertMessage::GeneratorResumedAfterReturn | + mir::AssertMessage::GeneratorResumedAfterPanic => + span_bug!(span, "{:?} should not appear in constants?", msg), }; let err = ConstEvalErr { span: span, kind: err }; @@ -565,6 +568,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { } mir::AggregateKind::Adt(..) | mir::AggregateKind::Closure(..) | + mir::AggregateKind::Generator(..) | mir::AggregateKind::Tuple => { Const::new(trans_const(self.ccx, dest_ty, kind, &fields), dest_ty) } diff --git a/src/librustc_trans/mir/mod.rs b/src/librustc_trans/mir/mod.rs index a7f12babb10f9..ba27f684ab3f3 100644 --- a/src/librustc_trans/mir/mod.rs +++ b/src/librustc_trans/mir/mod.rs @@ -524,15 +524,15 @@ fn arg_local_refs<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, } // Or is it the closure environment? - let (closure_ty, env_ref) = if let ty::TyRef(_, mt) = arg_ty.sty { - (mt.ty, true) - } else { - (arg_ty, false) + let (closure_ty, env_ref) = match arg_ty.sty { + ty::TyRef(_, mt) | ty::TyRawPtr(mt) => (mt.ty, true), + _ => (arg_ty, false) }; - let upvar_tys = if let ty::TyClosure(def_id, substs) = closure_ty.sty { - substs.upvar_tys(def_id, tcx) - } else { - bug!("upvar_decls with non-closure arg0 type `{}`", closure_ty); + + let upvar_tys = match closure_ty.sty { + ty::TyClosure(def_id, substs) | + ty::TyGenerator(def_id, substs, _) => substs.upvar_tys(def_id, tcx), + _ => bug!("upvar_decls with non-closure arg0 type `{}`", closure_ty) }; // Store the pointer to closure data in an alloca for debuginfo diff --git a/src/librustc_trans/monomorphize.rs b/src/librustc_trans/monomorphize.rs index 1f6a262162d39..94612ef652331 100644 --- a/src/librustc_trans/monomorphize.rs +++ b/src/librustc_trans/monomorphize.rs @@ -125,6 +125,12 @@ fn resolve_associated_item<'a, 'tcx>( let substs = tcx.erase_regions(&substs); ty::Instance::new(def_id, substs) } + traits::VtableGenerator(closure_data) => { + Instance { + def: ty::InstanceDef::Item(closure_data.closure_def_id), + substs: closure_data.substs.substs + } + } traits::VtableClosure(closure_data) => { let trait_closure_kind = tcx.lang_items.fn_trait_kind(trait_id).unwrap(); resolve_closure(scx, closure_data.closure_def_id, closure_data.substs, diff --git a/src/librustc_trans/trans_item.rs b/src/librustc_trans/trans_item.rs index b94fd13c3a4a2..3841e9bfeb723 100644 --- a/src/librustc_trans/trans_item.rs +++ b/src/librustc_trans/trans_item.rs @@ -504,6 +504,7 @@ impl<'a, 'tcx> DefPathBasedNames<'a, 'tcx> { self.push_type_name(sig.output(), output); } }, + ty::TyGenerator(def_id, ref closure_substs, _) | ty::TyClosure(def_id, ref closure_substs) => { self.push_def_path(def_id, output); let generics = self.tcx.generics_of(self.tcx.closure_base_def_id(def_id)); diff --git a/src/librustc_trans/type_of.rs b/src/librustc_trans/type_of.rs index 9f9126ba83a8f..38c49833e0d75 100644 --- a/src/librustc_trans/type_of.rs +++ b/src/librustc_trans/type_of.rs @@ -133,6 +133,11 @@ pub fn in_memory_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> // fill it in *after* placing it into the type cache. adt::incomplete_type_of(cx, t, "closure") } + ty::TyGenerator(..) => { + // Only create the named struct, but don't fill it in. We + // fill it in *after* placing it into the type cache. + adt::incomplete_type_of(cx, t, "generator") + } ty::TyRef(_, ty::TypeAndMut{ty, ..}) | ty::TyRawPtr(ty::TypeAndMut{ty, ..}) => { @@ -197,7 +202,7 @@ pub fn in_memory_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> // If this was an enum or struct, fill in the type now. match t.sty { - ty::TyAdt(..) | ty::TyClosure(..) if !t.is_simd() && !t.is_box() => { + ty::TyAdt(..) | ty::TyClosure(..) | ty::TyGenerator(..) if !t.is_simd() && !t.is_box() => { adt::finish_type_of(cx, t, &mut llty); } _ => () diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index 802eee91efcf3..4884c811a1b3c 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -32,7 +32,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { debug!("check_expr_closure(expr={:?},expected={:?})", expr, expected); - + // FIXME: See if expected_kind here can impact generators + // It's always helpful for inference if we know the kind of // closure sooner rather than later, so first examine the expected // type, and see if can glean a closure kind from there. @@ -70,22 +71,29 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // inference phase (`upvar.rs`). let base_substs = Substs::identity_for_item(self.tcx, self.tcx.closure_base_def_id(expr_def_id)); - let closure_type = self.tcx.mk_closure(expr_def_id, - base_substs.extend_to(self.tcx, expr_def_id, + let substs = base_substs.extend_to(self.tcx, expr_def_id, |_, _| span_bug!(expr.span, "closure has region param"), |_, _| self.infcx.next_ty_var(TypeVariableOrigin::TransformedUpvar(expr.span)) - ) ); - debug!("check_closure: expr.id={:?} closure_type={:?}", expr.id, closure_type); - let fn_sig = self.liberate_late_bound_regions(expr_def_id, &sig); let fn_sig = self.inh.normalize_associated_types_in(body.value.span, body.value.id, self.param_env, &fn_sig); - check_fn(self, self.param_env, fn_sig, decl, expr.id, body); + let interior = check_fn(self, self.param_env, fn_sig, decl, expr.id, body).1; + + if let Some(interior) = interior { + let closure_substs = ty::ClosureSubsts { + substs: substs, + }; + return self.tcx.mk_generator(expr_def_id, closure_substs, interior); + } + + let closure_type = self.tcx.mk_closure(expr_def_id, substs); + + debug!("check_closure: expr.id={:?} closure_type={:?}", expr.id, closure_type); // Tuple up the arguments and insert the resulting function type into // the `closures` table. diff --git a/src/librustc_typeck/check/generator_interior.rs b/src/librustc_typeck/check/generator_interior.rs new file mode 100644 index 0000000000000..3b6708470a142 --- /dev/null +++ b/src/librustc_typeck/check/generator_interior.rs @@ -0,0 +1,110 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap}; +use rustc::hir::{self, Body, Pat, PatKind, Expr}; +use rustc::hir::def_id::DefId; +use rustc::ty::Ty; +use rustc::middle::region::{RegionMaps, CodeExtent, extent_has_yield}; +use util::nodemap::FxHashSet; +use std::rc::Rc; +use super::FnCtxt; + +struct InteriorVisitor<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { + fcx: &'a FnCtxt<'a, 'gcx, 'tcx>, + types: FxHashSet>, + region_maps: Rc, +} + +impl<'a, 'gcx, 'tcx> InteriorVisitor<'a, 'gcx, 'tcx> { + fn record(&mut self, ty: Ty<'tcx>, scope: Option, expr: Option<&'tcx Expr>) { + use syntax_pos::DUMMY_SP; + + if scope.map(|s| extent_has_yield(self.fcx.tcx, s)).unwrap_or(true) { + if self.fcx.tcx.sess.verbose() { + if let Some(s) = scope { + self.fcx.tcx.sess.span_warn(s.span(&self.fcx.tcx.hir).unwrap_or(DUMMY_SP), + &format!("type in generator with scope = {:?}, type = {:?}", scope, self.fcx.resolve_type_vars_if_possible(&ty))); + } else { + self.fcx.tcx.sess.span_warn(DUMMY_SP, + &format!("type in generator WITHOUT scope, type = {:?}", self.fcx.resolve_type_vars_if_possible(&ty))); + } + if let Some(e) = expr { + self.fcx.tcx.sess.span_warn(e.span, + &format!("type from expression: {:?}", e)); + } + } + self.types.insert(ty); + } else if self.fcx.tcx.sess.verbose() { + if let Some(e) = expr { + self.fcx.tcx.sess.span_warn(e.span, + &format!("NO type from expression: {:?}", e)); + } + } + } +} + +pub fn find_interior<'a, 'gcx, 'tcx>(fcx: &'a FnCtxt<'a, 'gcx, 'tcx>, def_id: DefId, body_id: hir::BodyId, witness: Ty<'tcx>) { + let body = fcx.tcx.hir.body(body_id); + let mut visitor = InteriorVisitor { + fcx, + types: FxHashSet(), + region_maps: fcx.tcx.region_maps(def_id), + }; + intravisit::walk_body(&mut visitor, body); + + // FIXME: Drop elaboration can insert bool types in the generator + visitor.types.insert(fcx.tcx.types.bool); + + // Deduplicate types + let set: FxHashSet<_> = visitor.types.into_iter().map(|t| fcx.resolve_type_vars_if_possible(&t)).collect(); + let types: Vec<_> = set.into_iter().collect(); + + let tuple = fcx.tcx.intern_tup(&types, false); + + if fcx.tcx.sess.verbose() { + fcx.tcx.sess.span_warn(body.value.span, + &format!("Types in generator {:?}", tuple)); + } + + // Unify the tuple with the witness + match fcx.at(&fcx.misc(body.value.span), fcx.param_env).eq(witness, tuple) { + Ok(ok) => fcx.register_infer_ok_obligations(ok), + _ => bug!(), + } +} + +impl<'a, 'gcx, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'gcx, 'tcx> { + fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> { + NestedVisitorMap::None + } + + fn visit_body(&mut self, _body: &'tcx Body) { + // Closures inside are not considered part of the generator interior + } + + fn visit_pat(&mut self, pat: &'tcx Pat) { + if let PatKind::Binding(..) = pat.node { + let scope = self.region_maps.var_scope(pat.id); + let ty = self.fcx.tables.borrow().pat_ty(pat); + self.record(ty, Some(scope), None); + } + + intravisit::walk_pat(self, pat); + } + + fn visit_expr(&mut self, expr: &'tcx Expr) { + let scope = self.region_maps.temporary_scope(expr.id); + let ty = self.fcx.tables.borrow().expr_ty_adjusted(expr); + self.record(ty, scope, Some(expr)); + + intravisit::walk_expr(self, expr); + } +} diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index dfc5cd00b6eab..ae1724549d9fd 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -706,6 +706,8 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { self.assemble_closure_candidates(import_id, trait_def_id, item.clone())?; + self.assemble_generator_candidates(import_id, trait_def_id, item.clone())?; + self.assemble_projection_candidates(import_id, trait_def_id, item.clone()); self.assemble_where_clause_candidates(import_id, trait_def_id, item.clone()); @@ -847,6 +849,48 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { Ok(()) } + fn assemble_generator_candidates(&mut self, + import_id: Option, + trait_def_id: DefId, + item: ty::AssociatedItem) + -> Result<(), MethodError<'tcx>> { + // Check if this is the Generator trait. + let tcx = self.tcx; + if Some(trait_def_id) != tcx.lang_items.gen_trait() { + return Ok(()); + } + + // Check if there is an generator self-type in the list of receivers. + // If so, add "synthetic impls". + let steps = self.steps.clone(); + for step in steps.iter() { + match step.self_ty.sty { + ty::TyGenerator(..) => (), + _ => continue, + }; + + // create some substitutions for the argument/return type; + // for the purposes of our method lookup, we only take + // receiver type into account, so we can just substitute + // fresh types here to use during substitution and subtyping. + let substs = Substs::for_item(self.tcx, + trait_def_id, + |def, _| self.region_var_for_def(self.span, def), + |def, substs| { + if def.index == 0 { + step.self_ty + } else { + self.type_var_for_def(self.span, def, substs) + } + }); + + let xform_self_ty = self.xform_self_ty(&item, step.self_ty, substs); + self.push_inherent_candidate(xform_self_ty, item, TraitCandidate, import_id); + } + + Ok(()) + } + fn assemble_projection_candidates(&mut self, import_id: Option, trait_def_id: DefId, diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 7f69885047b93..c763639d6057a 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -146,6 +146,7 @@ mod cast; mod closure; mod callee; mod compare_method; +mod generator_interior; mod intrinsic; mod op; @@ -205,6 +206,8 @@ pub struct Inherited<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { deferred_cast_checks: RefCell>>, + deferred_generator_interiors: RefCell)>>, + // Anonymized types found in explicit return types and their // associated fresh inference variable. Writeback resolves these // variables to get the concrete type, which can be used to @@ -503,6 +506,9 @@ pub struct FnCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { ret_coercion: Option>>, + suspend_ty: Option>, + impl_arg_ty: Option>, + ps: RefCell, /// Whether the last checked node generates a divergence (e.g., @@ -606,6 +612,7 @@ impl<'a, 'gcx, 'tcx> Inherited<'a, 'gcx, 'tcx> { locals: RefCell::new(NodeMap()), deferred_call_resolutions: RefCell::new(DefIdMap()), deferred_cast_checks: RefCell::new(Vec::new()), + deferred_generator_interiors: RefCell::new(Vec::new()), anon_types: RefCell::new(NodeMap()), implicit_region_bound, body_id, @@ -726,11 +733,19 @@ pub fn provide(providers: &mut Providers) { typeck_tables_of, has_typeck_tables, closure_kind, + generator_sig, adt_destructor, ..*providers }; } +fn generator_sig<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + def_id: DefId) + -> Option> { + let node_id = tcx.hir.as_local_node_id(def_id).unwrap(); + tcx.typeck_tables_of(def_id).generator_sigs[&node_id].map(|s| ty::Binder(s)) +} + fn closure_kind<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> ty::ClosureKind { @@ -856,7 +871,7 @@ fn typeck_tables_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, param_env, &fn_sig); - check_fn(&inh, param_env, fn_sig, decl, id, body) + check_fn(&inh, param_env, fn_sig, decl, id, body).0 } else { let fcx = FnCtxt::new(&inh, param_env, body.value.id); let expected_type = tcx.type_of(def_id); @@ -878,6 +893,7 @@ fn typeck_tables_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, fcx.closure_analyze(body); fcx.select_obligations_where_possible(); fcx.check_casts(); + fcx.find_generator_interiors(def_id); fcx.select_all_obligations_or_error(); if fn_decl.is_some() { @@ -972,7 +988,7 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>, decl: &'gcx hir::FnDecl, fn_id: ast::NodeId, body: &'gcx hir::Body) - -> FnCtxt<'a, 'gcx, 'tcx> + -> (FnCtxt<'a, 'gcx, 'tcx>, Option>) { let mut fn_sig = fn_sig.clone(); @@ -995,6 +1011,27 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>, fn_sig.abi ); + let def_id = fcx.tcx.hir.local_def_id(fn_id); + let span = body.value.span; + + if let Some(ref impl_arg) = body.impl_arg { + let impl_arg_ty = fcx.infcx.type_var_for_impl_arg(span, def_id); + + // Require impl_arg: 'static + let cause = traits::ObligationCause::new(span, body.value.id, traits::MiscObligation);; + fcx.fulfillment_cx.borrow_mut() + .register_region_obligation(impl_arg_ty, + fcx.tcx.types.re_static, + cause); + + fcx.impl_arg_ty = Some(impl_arg_ty); + + // Write the type to the impl arg id + fcx.write_ty(impl_arg.id, impl_arg_ty); + + fcx.suspend_ty = Some(fcx.next_ty_var(TypeVariableOrigin::TypeInference(span))); + } + GatherLocalsVisitor { fcx: &fcx, }.visit_body(body); // Add formal parameters. @@ -1013,6 +1050,25 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>, fcx.write_ty(arg.id, arg_ty); } + let gen_ty = if body.is_generator() { + let gen_sig = ty::GenSig { + impl_arg_ty: fcx.impl_arg_ty.unwrap(), + suspend_ty: fcx.suspend_ty.unwrap(), + return_ty: ret_ty, + }; + inherited.tables.borrow_mut().generator_sigs.insert(fn_id, Some(gen_sig)); + + let witness = fcx.next_ty_var(TypeVariableOrigin::MiscVariable(span)); + fcx.deferred_generator_interiors.borrow_mut().push((body.id(), witness)); + let interior = ty::GeneratorInterior::new(witness); + + inherited.tables.borrow_mut().generator_interiors.insert(fn_id, interior); + + Some(interior) + } else { + inherited.tables.borrow_mut().generator_sigs.insert(fn_id, None); + None + }; inherited.tables.borrow_mut().liberated_fn_sigs.insert(fn_id, fn_sig); fcx.check_return_expr(&body.value); @@ -1044,11 +1100,11 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>, let mut actual_return_ty = coercion.complete(&fcx); if actual_return_ty.is_never() { actual_return_ty = fcx.next_diverging_ty_var( - TypeVariableOrigin::DivergingFn(body.value.span)); + TypeVariableOrigin::DivergingFn(span)); } - fcx.demand_suptype(body.value.span, ret_ty, actual_return_ty); + fcx.demand_suptype(span, ret_ty, actual_return_ty); - fcx + (fcx, gen_ty) } fn check_struct<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, @@ -1685,6 +1741,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { param_env, err_count_on_creation: inh.tcx.sess.err_count(), ret_coercion: None, + suspend_ty: None, + impl_arg_ty: None, ps: RefCell::new(UnsafetyState::function(hir::Unsafety::Normal, ast::CRATE_NODE_ID)), diverges: Cell::new(Diverges::Maybe), @@ -2066,6 +2124,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } + fn find_generator_interiors(&self, def_id: DefId) { + let mut deferred_generator_interiors = self.deferred_generator_interiors.borrow_mut(); + for (body_id, witness) in deferred_generator_interiors.drain(..) { + generator_interior::find_interior(self, def_id, body_id, witness); + } + } + /// Apply "fallbacks" to some types /// unconstrained types get replaced with ! or () (depending on whether /// feature(never_type) is enabled), unconstrained ints with i32, and @@ -2502,7 +2567,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } let is_closure = match arg.node { - hir::ExprClosure(..) => true, + // TODO: Should this be applied for generators? + hir::ExprClosure(.., None) => true, _ => false }; @@ -2629,8 +2695,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } pub fn check_expr_has_type_or_error(&self, - expr: &'gcx hir::Expr, - expected: Ty<'tcx>) -> Ty<'tcx> { + expr: &'gcx hir::Expr, + expected: Ty<'tcx>) -> Ty<'tcx> { self.check_expr_meets_expectation_or_error(expr, ExpectHasType(expected)) } @@ -3063,13 +3129,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { return field_ty; } - if tuple_like { + if tuple_like { type_error_struct!(self.tcx().sess, expr.span, expr_t, E0612, "attempted out-of-bounds tuple index `{}` on type `{}`", idx.node, expr_t).emit(); - } else { + } else { self.no_such_field_err(expr.span, idx.node, expr_t).emit(); - } + } self.tcx().types.err } @@ -3135,7 +3201,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let adt_ty_hint = self.expected_inputs_for_expected_output(span, expected, adt_ty, &[adt_ty]) - .get(0).cloned().unwrap_or(adt_ty); + .get(0).cloned().unwrap_or(adt_ty); // re-link the regions that EIfEO can erase. self.demand_eqtype(span, adt_ty_hint, adt_ty); @@ -3173,10 +3239,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { error_happened = true; if let Some(_) = variant.find_field_named(field.name.node) { let mut err = struct_span_err!(self.tcx.sess, - field.name.span, - E0062, - "field `{}` specified more than once", - field.name.node); + field.name.span, + E0062, + "field `{}` specified more than once", + field.name.node); err.span_label(field.name.span, "used more than once"); @@ -3224,15 +3290,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { .join(", "); struct_span_err!(tcx.sess, span, E0063, - "missing field{} {}{} in initializer of `{}`", + "missing field{} {}{} in initializer of `{}`", if remaining_fields.len() == 1 { "" } else { "s" }, - remaining_fields_names, - truncated_fields_error, - adt_ty) - .span_label(span, format!("missing {}{}", - remaining_fields_names, - truncated_fields_error)) - .emit(); + remaining_fields_names, + truncated_fields_error, + adt_ty) + .span_label(span, format!("missing {}{}", + remaining_fields_names, + truncated_fields_error)) + .emit(); } } @@ -3649,14 +3715,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Only check this if not in an `if` condition, as the // mistyped comparison help is more appropriate. if !self.tcx.expr_is_lval(&lhs) { - struct_span_err!( + struct_span_err!( self.tcx.sess, expr.span, E0070, - "invalid left-hand side expression") - .span_label( - expr.span, - "left-hand of expression not valid") - .emit(); - } + "invalid left-hand side expression") + .span_label( + expr.span, + "left-hand of expression not valid") + .emit(); + } } } @@ -3730,7 +3796,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { hir::ExprMatch(ref discrim, ref arms, match_src) => { self.check_match(expr, &discrim, arms, expected, match_src) } - hir::ExprClosure(capture, ref decl, body_id, _) => { + hir::ExprClosure(capture, ref decl, body_id, _, _) => { self.check_expr_closure(expr, capture, &decl, body_id, expected) } hir::ExprBlock(ref body) => { @@ -3921,6 +3987,30 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } } + hir::ExprImplArg(_) => { + match self.impl_arg_ty { + Some(ty) => { + ty + } + None => { + struct_span_err!(self.tcx.sess, expr.span, E0803, + "impl arg expression outside of function body").emit(); + tcx.types.err + } + } + } + hir::ExprSuspend(ref value) => { + match self.suspend_ty { + Some(ty) => { + self.check_expr_coercable_to_type(&value, ty); + } + None => { + struct_span_err!(self.tcx.sess, expr.span, E0802, + "yield statement outside of function body").emit(); + } + } + tcx.mk_nil() + } } } diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index 82207428efc4f..3413144b4fe78 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -823,7 +823,7 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for RegionCtxt<'a, 'gcx, 'tcx> { intravisit::walk_expr(self, expr); } - hir::ExprClosure(.., body_id, _) => { + hir::ExprClosure(.., body_id, _, _) => { self.check_expr_fn_block(expr, body_id); } diff --git a/src/librustc_typeck/check/upvar.rs b/src/librustc_typeck/check/upvar.rs index 59ca896b347f1..bf7bbfa16b2d1 100644 --- a/src/librustc_typeck/check/upvar.rs +++ b/src/librustc_typeck/check/upvar.rs @@ -75,10 +75,10 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for InferBorrowKindVisitor<'a, 'gcx, 'tcx> { fn visit_expr(&mut self, expr: &'gcx hir::Expr) { match expr.node { - hir::ExprClosure(cc, _, body_id, _) => { + hir::ExprClosure(cc, _, body_id, _, gen) => { let body = self.fcx.tcx.hir.body(body_id); self.visit_body(body); - self.fcx.analyze_closure(expr.id, expr.span, body, cc); + self.fcx.analyze_closure(expr.id, expr.span, body, cc, gen.is_some()); } _ => { } @@ -93,19 +93,22 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { id: ast::NodeId, span: Span, body: &hir::Body, - capture_clause: hir::CaptureClause) { + capture_clause: hir::CaptureClause, + gen: bool) { /*! * Analysis starting point. */ debug!("analyze_closure(id={:?}, body.id={:?})", id, body.id()); - let infer_kind = match self.tables.borrow_mut().closure_kinds.entry(id) { - Entry::Occupied(_) => false, - Entry::Vacant(entry) => { - debug!("check_closure: adding closure {:?} as Fn", id); - entry.insert((ty::ClosureKind::Fn, None)); - true + let infer_kind = if gen { false } else { + match self.tables.borrow_mut().closure_kinds.entry(id) { + Entry::Occupied(_) => false, + Entry::Vacant(entry) => { + debug!("check_closure: adding closure {:?} as Fn", id); + entry.insert((ty::ClosureKind::Fn, None)); + true + } } }; @@ -173,7 +176,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Extract the type variables UV0...UVn. let (def_id, closure_substs) = match self.node_ty(id).sty { - ty::TyClosure(def_id, substs) => (def_id, substs), + ty::TyClosure(def_id, substs) | + ty::TyGenerator(def_id, substs, _) => (def_id, substs), ref t => { span_bug!( span, diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index 81e5dae5477eb..2b166d2418b74 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -36,6 +36,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { for arg in &body.arguments { wbcx.visit_node_id(arg.pat.span, arg.id); } + if let Some(ref impl_arg) = body.impl_arg { + wbcx.visit_node_id(impl_arg.span, impl_arg.id); + } wbcx.visit_body(body); wbcx.visit_upvar_borrow_map(); wbcx.visit_closures(); @@ -45,6 +48,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { wbcx.visit_cast_types(); wbcx.visit_lints(); wbcx.visit_free_region_map(); + wbcx.visit_generator_sigs(); + wbcx.visit_generator_interiors(); let used_trait_imports = mem::replace(&mut self.tables.borrow_mut().used_trait_imports, DefIdSet()); @@ -160,8 +165,9 @@ impl<'cx, 'gcx, 'tcx> Visitor<'gcx> for WritebackCx<'cx, 'gcx, 'tcx> { self.visit_node_id(e.span, e.id); - if let hir::ExprClosure(_, _, body, _) = e.node { + if let hir::ExprClosure(_, _, body, _, _) = e.node { let body = self.fcx.tcx.hir.body(body); + // FIXME: Why visit the args here? for arg in &body.arguments { self.visit_node_id(e.span, arg.id); } @@ -312,6 +318,24 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { } } + fn visit_generator_interiors(&mut self) { + for (&node_id, interior) in self.fcx.tables.borrow().generator_interiors.iter() { + let interior = self.resolve(interior, &node_id); + self.tables.generator_interiors.insert(node_id, interior); + } + } + + fn visit_generator_sigs(&mut self) { + for (&node_id, gen_sig) in self.fcx.tables.borrow().generator_sigs.iter() { + let gen_sig = gen_sig.map(|s| ty::GenSig { + impl_arg_ty: self.resolve(&s.impl_arg_ty, &node_id), + suspend_ty: self.resolve(&s.suspend_ty, &node_id), + return_ty: self.resolve(&s.return_ty, &node_id), + }); + self.tables.generator_sigs.insert(node_id, gen_sig); + } + } + fn visit_liberated_fn_sigs(&mut self) { for (&node_id, fn_sig) in self.fcx.tables.borrow().liberated_fn_sigs.iter() { let fn_sig = self.resolve(fn_sig, &node_id); diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 8780131bbcc26..581a62d377de0 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1155,7 +1155,11 @@ fn type_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, NodeField(field) => icx.to_ty(&field.ty), - NodeExpr(&hir::Expr { node: hir::ExprClosure(..), .. }) => { + NodeExpr(&hir::Expr { node: hir::ExprClosure(.., gen), .. }) => { + if gen.is_some() { + return tcx.typeck_tables_of(def_id).node_id_to_type(node_id); + } + tcx.mk_closure(def_id, Substs::for_item( tcx, def_id, |def, _| { diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index 60f32408abba1..4313aa59202f9 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -4667,4 +4667,8 @@ register_diagnostics! { E0588, // packed struct cannot transitively contain a `[repr(align)]` struct E0592, // duplicate definitions with name `{}` // E0613, // Removed (merged with E0609) + E0801, // unexpected generator return + E0802, // yield statement outside of function body + E0803, // impl arg expression outside of function body + E0804, // cannot determine the type for the implicit argument of this generator } diff --git a/src/librustc_typeck/variance/constraints.rs b/src/librustc_typeck/variance/constraints.rs index 284c9c5cfc398..6e9e6137b4443 100644 --- a/src/librustc_typeck/variance/constraints.rs +++ b/src/librustc_typeck/variance/constraints.rs @@ -149,11 +149,11 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { // // See README.md for a detailed discussion // on dep-graph management. - let dep_node = def_id.to_dep_node(tcx, DepKind::ItemVarianceConstraints); - tcx.dep_graph.with_task(dep_node, - AssertDepGraphSafe(self), - def_id, - visit_item_task); + let dep_node = def_id.to_dep_node(tcx, DepKind::ItemVarianceConstraints); + tcx.dep_graph.with_task(dep_node, + AssertDepGraphSafe(self), + def_id, + visit_item_task); fn visit_item_task<'a, 'tcx>(ccx: AssertDepGraphSafe<&mut ConstraintContext<'a, 'tcx>>, def_id: DefId) @@ -202,9 +202,9 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { _ => { span_bug!(tcx.def_span(def_id), "`build_constraints_for_item` unsupported for this item"); - } } } + } fn add_constraint(&mut self, current: &CurrentItem, @@ -269,7 +269,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { let variance_i = self.invariant(variance); for ty in substs.types() { self.add_constraints_from_ty(current, ty, variance_i); - } + } for region in substs.regions() { self.add_constraints_from_region(current, region, variance_i); @@ -294,6 +294,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { } ty::TyFnDef(..) | + ty::TyGenerator(..) | ty::TyClosure(..) => { bug!("Unexpected closure type in variance computation"); } @@ -349,7 +350,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { ty::TyParam(ref data) => { self.add_constraint(current, data.idx, variance); - } + } ty::TyFnPtr(sig) => { self.add_constraints_from_sig(current, sig, variance); @@ -418,7 +419,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { self.add_constraints_from_region(current, r, variance_i); } else { bug!(); - } + } } } @@ -444,7 +445,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { match *region { ty::ReEarlyBound(ref data) => { self.add_constraint(current, data.index, variance); - } + } ty::ReStatic => {} diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 9d0b5b41a913f..d8364a24dec7a 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1935,7 +1935,7 @@ impl<'tcx> Clean for ty::Ty<'tcx> { }).collect()) } - ty::TyClosure(..) => Tuple(vec![]), // FIXME(pcwalton) + ty::TyClosure(..) | ty::TyGenerator(..) => Tuple(vec![]), // FIXME(pcwalton) ty::TyInfer(..) => panic!("TyInfer"), ty::TyError => panic!("TyError"), diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 4fc737873530e..1a2299bcf1f57 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -981,6 +981,12 @@ pub enum ExprKind { /// `expr?` Try(P), + + /// A `yield`, with an optional value to be yielded + Yield(Option>), + + /// A reference to the implicit argument of a generator + ImplArg, } /// The explicit Self type in a "qualified path". The actual diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index e8de8cf41c970..0f99761968ad7 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -361,6 +361,10 @@ declare_features! ( // Allows unsized tuple coercion. (active, unsized_tuple_coercion, "1.20.0", Some(42877)), + // Generators + (active, generators, "1.21.0", None), + + // global allocators and their internals (active, global_allocator, "1.20.0", None), (active, allocator_internals, "1.20.0", None), @@ -1326,6 +1330,16 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { ast::ExprKind::InPlace(..) => { gate_feature_post!(&self, placement_in_syntax, e.span, EXPLAIN_PLACEMENT_IN); } + ast::ExprKind::Yield(..) => { + gate_feature_post!(&self, generators, + e.span, + "yield syntax is experimental"); + } + ast::ExprKind::ImplArg => { + gate_feature_post!(&self, generators, + e.span, + "gen arg syntax is experimental"); + } ast::ExprKind::Lit(ref lit) => { if let ast::LitKind::Int(_, ref ty) = lit.node { match *ty { diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 8c616df858a49..4a86008bb336c 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -1303,6 +1303,8 @@ pub fn noop_fold_expr(Expr {id, node, span, attrs}: Expr, folder: &mu attrs: fold_attrs(attrs.into(), folder).into(), }; } + ExprKind::Yield(ex) => ExprKind::Yield(ex.map(|x| folder.fold_expr(x))), + ExprKind::ImplArg => ExprKind::ImplArg, ExprKind::Try(ex) => ExprKind::Try(folder.fold_expr(ex)), ExprKind::Catch(body) => ExprKind::Catch(folder.fold_block(body)), }, diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index d1591a219b325..c377a77d87fa9 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -2146,6 +2146,12 @@ impl<'a> Parser<'a> { assert!(self.eat_keyword(keywords::Catch)); return self.parse_catch_expr(lo, attrs); } + if self.is_gen_arg() { + assert!(self.eat_keyword(keywords::Gen)); + assert!(self.eat_keyword(keywords::Arg)); + let hi = self.prev_span; + return Ok(self.mk_expr(lo.to(hi), ExprKind::ImplArg, attrs)); + } if self.eat_keyword(keywords::Return) { if self.token.can_begin_expr() { let e = self.parse_expr()?; @@ -2175,6 +2181,14 @@ impl<'a> Parser<'a> { }; ex = ExprKind::Break(lt, e); hi = self.prev_span; + } else if self.eat_keyword(keywords::Yield) { + if self.token.can_begin_expr() { + let e = self.parse_expr()?; + hi = e.span; + ex = ExprKind::Yield(Some(e)); + } else { + ex = ExprKind::Yield(None); + } } else if self.token.is_keyword(keywords::Let) { // Catch this syntax error here, instead of in `parse_ident`, so // that we can explicitly mention that let is not to be used as an expression @@ -3696,6 +3710,11 @@ impl<'a> Parser<'a> { self.look_ahead(1, |t| t.is_ident() && !t.is_reserved_ident()) } + fn is_gen_arg(&self) -> bool { + self.token.is_keyword(keywords::Gen) && + self.look_ahead(1, |t| t.is_keyword(keywords::Arg)) + } + fn is_defaultness(&self) -> bool { // `pub` is included for better error messages self.token.is_keyword(keywords::Default) && @@ -3799,7 +3818,8 @@ impl<'a> Parser<'a> { // Starts like a simple path, but not a union item. } else if self.token.is_path_start() && !self.token.is_qpath_start() && - !self.is_union_item() { + !self.is_union_item() && + !self.is_gen_arg() { let pth = self.parse_path(PathStyle::Expr)?; if !self.eat(&token::Not) { diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index 834ac38af9870..d39f11bc3eef1 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -106,6 +106,7 @@ fn ident_can_begin_expr(ident: ast::Ident) -> bool { keywords::True.name(), keywords::Unsafe.name(), keywords::While.name(), + keywords::Yield.name(), ].contains(&ident.name) } diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index b052b2cdbbb5a..114cabe26d150 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -2280,6 +2280,21 @@ impl<'a> State<'a> { self.print_expr(e)?; self.pclose()?; }, + ast::ExprKind::Yield(ref e) => { + word(&mut self.s, "yield")?; + match *e { + Some(ref expr) => { + word(&mut self.s, " ")?; + self.print_expr(&expr)?; + } + _ => () + } + } + ast::ExprKind::ImplArg => { + word(&mut self.s, "impl")?; + space(&mut self.s)?; + word(&mut self.s, "arg")?; + } ast::ExprKind::Try(ref e) => { self.print_expr(e)?; self.s.word("?")? diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index f4ac7e341ce4b..cd8a2f1534b93 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -784,6 +784,10 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) { visitor.visit_expr(&output.expr) } } + ExprKind::Yield(ref optional_expression) => { + walk_list!(visitor, visit_expr, optional_expression); + } + ExprKind::ImplArg => (), ExprKind::Try(ref subexpression) => { visitor.visit_expr(subexpression) } diff --git a/src/libsyntax_pos/symbol.rs b/src/libsyntax_pos/symbol.rs index debac70545a99..1123c33c0c28b 100644 --- a/src/libsyntax_pos/symbol.rs +++ b/src/libsyntax_pos/symbol.rs @@ -307,6 +307,8 @@ declare_keywords! { (56, StaticLifetime, "'static") (57, Union, "union") (58, Catch, "catch") + (59, Arg, "arg") + (60, Gen, "gen") } // If an interner exists in TLS, return it. Otherwise, prepare a fresh one. diff --git a/src/test/compile-fail/feature-gate-generators.rs b/src/test/compile-fail/feature-gate-generators.rs new file mode 100644 index 0000000000000..8371ff4f57918 --- /dev/null +++ b/src/test/compile-fail/feature-gate-generators.rs @@ -0,0 +1,14 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main() { + yield true; //~ ERROR yield syntax is experimental + gen arg; //~ ERROR gen arg syntax is experimental +} diff --git a/src/test/compile-fail/generator/const-yield.rs b/src/test/compile-fail/generator/const-yield.rs new file mode 100644 index 0000000000000..fa99e8553a0b4 --- /dev/null +++ b/src/test/compile-fail/generator/const-yield.rs @@ -0,0 +1,16 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(generators)] + +const A: u8 = { yield 3u8; 3u8}; //~ ERROR yield statement outside of function body +static B: u8 = { yield 3u8; 3u8}; //~ ERROR yield statement outside of function body + +fn main() {} \ No newline at end of file diff --git a/src/test/compile-fail/generator/generator-not-fnmut.rs b/src/test/compile-fail/generator/generator-not-fnmut.rs new file mode 100644 index 0000000000000..e33924c28949d --- /dev/null +++ b/src/test/compile-fail/generator/generator-not-fnmut.rs @@ -0,0 +1,25 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(generators)] + +fn main() { + let mut a = Vec::::new(); + + let mut test = || { + let _: () = gen arg; + yield 3; + a.push(true); + 2 + }; + + let a1 = test(); + let a2 = test(); //~ ERROR use of moved value +} diff --git a/src/test/run-pass/generator/iterator-count.rs b/src/test/run-pass/generator/iterator-count.rs new file mode 100644 index 0000000000000..39a43690d943d --- /dev/null +++ b/src/test/run-pass/generator/iterator-count.rs @@ -0,0 +1,44 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(generators, generator_trait, conservative_impl_trait)] + +use std::ops::{State, Generator}; + +struct W(T); + +impl> Iterator for W { + type Item = T::Yield; + + fn next(&mut self) -> Option { + match self.0.resume(()) { + State::Complete(..) => None, + State::Yielded(v) => Some(v), + } + } +} + +fn test() -> impl Generator { + for i in 1..6 { + yield i + } +} + +fn main() { + let end = 11; + + let closure_test = |start| { + for i in start..end { + yield i + } + }; + + assert!(W(test()).chain(W(closure_test(6))).eq(1..11)); +} From 17c749f3eee953e204462870e68b64712a5c3576 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 5 Jul 2017 14:57:26 -0700 Subject: [PATCH 002/113] Fix tidy warnings --- src/libcore/ops/generator.rs | 2 +- src/librustc/hir/lowering.rs | 2 +- src/librustc/hir/print.rs | 2 +- .../infer/error_reporting/need_type_info.rs | 3 +- src/librustc/middle/region.rs | 9 +++--- src/librustc/mir/mod.rs | 3 +- src/librustc/mir/tcx.rs | 5 +++- src/librustc/mir/visit.rs | 2 +- src/librustc/traits/select.rs | 2 +- src/librustc/traits/util.rs | 2 +- src/librustc/ty/context.rs | 2 +- src/librustc/ty/maps.rs | 4 ++- src/librustc/ty/structural_impls.rs | 23 +++++++++------ .../borrowck/gather_loans/mod.rs | 2 +- src/librustc_mir/build/mod.rs | 4 +-- src/librustc_mir/build/scope.rs | 14 ++++++--- src/librustc_mir/transform/generator.rs | 29 ++++++++++++------- src/librustc_mir/transform/type_check.rs | 5 +++- src/librustc_mir/util/liveness.rs | 8 +++-- src/librustc_passes/mir_stats.rs | 8 +++-- src/librustc_trans/mir/constant.rs | 2 +- src/librustc_trans/mir/mod.rs | 2 +- src/librustc_typeck/check/closure.rs | 2 +- .../check/generator_interior.rs | 16 +++++++--- src/librustc_typeck/check/mod.rs | 2 +- src/librustc_typeck/collect.rs | 2 +- src/libsyntax/parse/parser.rs | 2 +- .../generator/generator-not-fnmut.rs | 18 ++++++------ src/test/run-pass/generator/iterator-count.rs | 20 ++++++------- 29 files changed, 122 insertions(+), 75 deletions(-) diff --git a/src/libcore/ops/generator.rs b/src/libcore/ops/generator.rs index 92330ad6333a2..2a88c842a8f73 100644 --- a/src/libcore/ops/generator.rs +++ b/src/libcore/ops/generator.rs @@ -33,6 +33,6 @@ pub trait Generator { /// The type of value this generator returns. type Return; - /// This resumes the execution of the generator. + /// This resumes the execution of the generator. fn resume(&mut self, arg: Arg) -> State; } diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 410f5e8d5ef40..8b092ff727ebf 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -2109,7 +2109,7 @@ impl<'a> LoweringContext<'a> { ExprKind::ImplArg => { hir::ExprImplArg(self.impl_arg_id()) } - + // Desugar ExprIfLet // From: `if let = []` ExprKind::IfLet(ref pat, ref sub_expr, ref body, ref else_opt) => { diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs index 4be48708bb3a1..272e442cfcd29 100644 --- a/src/librustc/hir/print.rs +++ b/src/librustc/hir/print.rs @@ -1317,7 +1317,7 @@ impl<'a> State<'a> { self.head("gen")?; space(&mut self.s)?; } - + self.print_capture_clause(capture_clause)?; self.print_closure_args(&decl, body)?; diff --git a/src/librustc/infer/error_reporting/need_type_info.rs b/src/librustc/infer/error_reporting/need_type_info.rs index a4b83af194d04..3fa13d7ab9efe 100644 --- a/src/librustc/infer/error_reporting/need_type_info.rs +++ b/src/librustc/infer/error_reporting/need_type_info.rs @@ -146,7 +146,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } if local_visitor.found_impl_arg { - labels.push((DUMMY_SP, format!("consider giving a type to the implicit generator argument"))); + labels.push((DUMMY_SP, format!("consider giving a type to the \ + implicit generator argument"))); } let mut err = struct_span_err!(self.tcx.sess, diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index 2e4d7b3b722da..2d0269e5845fa 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -1075,7 +1075,7 @@ impl<'a, 'tcx> Visitor<'tcx> for RegionResolutionVisitor<'a, 'tcx> { if let Some(ref impl_arg) = body.impl_arg { record_var_lifetime(self, impl_arg.id, impl_arg.span); } - + // The body of the every fn is a root scope. self.cx.parent = self.cx.var_parent; self.visit_expr(&body.value); @@ -1161,12 +1161,13 @@ impl<'tcx> Visitor<'tcx> for YieldFinder { if let hir::ExprSuspend(..) = expr.node { self.0 = true; } - + intravisit::walk_expr(self, expr); } } -pub fn extent_has_yield<'a, 'gcx: 'a+'tcx, 'tcx: 'a>(tcx: TyCtxt<'a, 'gcx, 'tcx>, extent: CodeExtent) -> bool { +pub fn extent_has_yield<'a, 'gcx: 'a+'tcx, 'tcx: 'a>(tcx: TyCtxt<'a, 'gcx, 'tcx>, + extent: CodeExtent) -> bool { let mut finder = YieldFinder(false); match extent { @@ -1181,7 +1182,7 @@ pub fn extent_has_yield<'a, 'gcx: 'a+'tcx, 'tcx: 'a>(tcx: TyCtxt<'a, 'gcx, 'tcx> } Node::NodeExpr(expr) => intravisit::walk_expr(&mut finder, expr), Node::NodeStmt(stmt) => intravisit::walk_stmt(&mut finder, stmt), - Node::NodeBlock(block) => intravisit::walk_block(&mut finder, block), + Node::NodeBlock(block) => intravisit::walk_block(&mut finder, block), _ => bug!(), } } diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index fe85bb1b6f782..9bfd7f175c275 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -1355,7 +1355,8 @@ impl<'tcx> Debug for Rvalue<'tcx> { } struct_fmt.field("$state", &lvs[freevars.len()]); for i in (freevars.len() + 1)..lvs.len() { - struct_fmt.field(&format!("${}", i - freevars.len() - 1), &lvs[i]); + struct_fmt.field(&format!("${}", i - freevars.len() - 1), + &lvs[i]); } }); diff --git a/src/librustc/mir/tcx.rs b/src/librustc/mir/tcx.rs index 252cf3e4f8064..12588edbea9c0 100644 --- a/src/librustc/mir/tcx.rs +++ b/src/librustc/mir/tcx.rs @@ -204,7 +204,10 @@ impl<'tcx> Rvalue<'tcx> { } AggregateKind::Generator(did, substs) => { let node_id = tcx.hir.as_local_node_id(did).unwrap(); - let interior = *tcx.typeck_tables_of(did).generator_interiors.get(&node_id).unwrap(); + let interior = *tcx.typeck_tables_of(did) + .generator_interiors + .get(&node_id) + .unwrap(); tcx.mk_generator(did, substs, interior.subst(tcx, substs.substs)) } } diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs index 6032dad46eb03..bd162c090f75b 100644 --- a/src/librustc/mir/visit.rs +++ b/src/librustc/mir/visit.rs @@ -399,7 +399,7 @@ macro_rules! make_mir_visitor { } TerminatorKind::Resume | - TerminatorKind::Return | + TerminatorKind::Return | TerminatorKind::GeneratorDrop | TerminatorKind::Unreachable => { } diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index dc12bf100ecd6..887edc5036490 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -2583,7 +2583,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { value: trait_ref, obligations } = self.generator_trait_ref(obligation, closure_def_id, substs); - + debug!("confirm_generator_candidate(closure_def_id={:?}, trait_ref={:?}, obligations={:?})", closure_def_id, trait_ref, diff --git a/src/librustc/traits/util.rs b/src/librustc/traits/util.rs index 957e6e9bc5ec7..dd3c0d66a9cc2 100644 --- a/src/librustc/traits/util.rs +++ b/src/librustc/traits/util.rs @@ -525,7 +525,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { }; ty::Binder((trait_ref, sig.skip_binder().suspend_ty, sig.skip_binder().return_ty)) } - + pub fn impl_is_default(self, node_item_def_id: DefId) -> bool { match self.hir.as_local_node_id(node_item_def_id) { Some(node_id) => { diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 6f276afc1025b..5e9caab60c11e 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -1401,7 +1401,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { self.mk_ty(TyClosure(closure_id, closure_substs)) } - pub fn mk_generator(self, + pub fn mk_generator(self, id: DefId, closure_substs: ClosureSubsts<'tcx>, interior: GeneratorInterior<'tcx>) diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs index 1d436834b22e5..2a9480ab06ab2 100644 --- a/src/librustc/ty/maps.rs +++ b/src/librustc/ty/maps.rs @@ -541,7 +541,9 @@ macro_rules! define_maps { impl<$tcx> Query<$tcx> { pub fn describe(&self, tcx: TyCtxt) -> String { let (r, name) = match *self { - $(Query::$name(key) => (queries::$name::describe(tcx, key), stringify!($name))),* + $(Query::$name(key) => { + (queries::$name::describe(tcx, key), stringify!($name)) + })* }; if tcx.sess.verbose() { format!("{} [{}]", r, name) diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 63a09435feaa9..2555288962076 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -304,13 +304,14 @@ impl<'a, 'tcx> Lift<'tcx> for ty::adjustment::AutoBorrow<'a> { impl<'a, 'tcx> Lift<'tcx> for ty::GenSig<'a> { type Lifted = ty::GenSig<'tcx>; fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option { - tcx.lift(&(self.impl_arg_ty, self.suspend_ty, self.return_ty)).map(|(impl_arg_ty, suspend_ty, return_ty)| { - ty::GenSig { - impl_arg_ty, - suspend_ty, - return_ty, - } - }) + tcx.lift(&(self.impl_arg_ty, self.suspend_ty, self.return_ty)) + .map(|(impl_arg_ty, suspend_ty, return_ty)| { + ty::GenSig { + impl_arg_ty, + suspend_ty, + return_ty, + } + }) } } @@ -572,7 +573,9 @@ impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> { ty::TyRef(ref r, tm) => { ty::TyRef(r.fold_with(folder), tm.fold_with(folder)) } - ty::TyGenerator(did, substs, interior) => ty::TyGenerator(did, substs.fold_with(folder), interior.fold_with(folder)), + ty::TyGenerator(did, substs, interior) => { + ty::TyGenerator(did, substs.fold_with(folder), interior.fold_with(folder)) + } ty::TyClosure(did, substs) => ty::TyClosure(did, substs.fold_with(folder)), ty::TyProjection(ref data) => ty::TyProjection(data.fold_with(folder)), ty::TyAnon(did, substs) => ty::TyAnon(did, substs.fold_with(folder)), @@ -604,7 +607,9 @@ impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> { ty::TyFnDef(_, substs) => substs.visit_with(visitor), ty::TyFnPtr(ref f) => f.visit_with(visitor), ty::TyRef(r, ref tm) => r.visit_with(visitor) || tm.visit_with(visitor), - ty::TyGenerator(_did, ref substs, ref interior) => substs.visit_with(visitor) || interior.visit_with(visitor), + ty::TyGenerator(_did, ref substs, ref interior) => { + substs.visit_with(visitor) || interior.visit_with(visitor) + } ty::TyClosure(_did, ref substs) => substs.visit_with(visitor), ty::TyProjection(ref data) => data.visit_with(visitor), ty::TyAnon(_, ref substs) => substs.visit_with(visitor), diff --git a/src/librustc_borrowck/borrowck/gather_loans/mod.rs b/src/librustc_borrowck/borrowck/gather_loans/mod.rs index 6fbe954b9c64e..cd0b19980957a 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/mod.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/mod.rs @@ -144,7 +144,7 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for GatherLoanCtxt<'a, 'tcx> { }, _ => false, }; - + if borrows_impl_arg { span_err!(self.bccx.tcx.sess, borrow_span, diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index 09e891021b1c1..c0bf46dd0fa7c 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -118,14 +118,14 @@ pub fn mir_build<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Mir<'t }); let arguments = implicit_argument.into_iter().chain(explicit_arguments); - + let (suspend_ty, impl_arg_ty, return_ty) = if body.is_generator() { let gen_sig = cx.tables().generator_sigs[&id].clone().unwrap(); (Some(gen_sig.suspend_ty), Some(gen_sig.impl_arg_ty), gen_sig.return_ty) } else { (None, None, fn_sig.output()) }; - + build::construct_fn(cx, id, arguments, abi, return_ty, suspend_ty, impl_arg_ty, body) } else { build::construct_const(cx, body_id) diff --git a/src/librustc_mir/build/scope.rs b/src/librustc_mir/build/scope.rs index 3ee33fbe16260..296d7c19e0e4a 100644 --- a/src/librustc_mir/build/scope.rs +++ b/src/librustc_mir/build/scope.rs @@ -502,7 +502,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { block, self.arg_count, true)); - + // End all regions for scopes out of which we are breaking. self.cfg.push_end_region(block, src_info, scope.extent); @@ -513,7 +513,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { block = next; } } - + self.cfg.terminate(block, src_info, TerminatorKind::GeneratorDrop); Some(result) @@ -778,7 +778,13 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { }; for scope in scopes.iter_mut() { - target = build_diverge_scope(hir.tcx(), cfg, &unit_temp, span, scope, target, generator_drop); + target = build_diverge_scope(hir.tcx(), + cfg, + &unit_temp, + span, + scope, + target, + generator_drop); } Some(target) } @@ -858,7 +864,7 @@ fn build_scope_drops<'tcx>(cfg: &mut CFG<'tcx>, arg_count: usize, generator_drop: bool) -> BlockAnd<()> { - + let mut iter = scope.drops(generator_drop).iter().rev().peekable(); while let Some(drop_data) = iter.next() { let source_info = scope.source_info(drop_data.span); diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs index 5f77096e0c361..5e33eb95d403f 100644 --- a/src/librustc_mir/transform/generator.rs +++ b/src/librustc_mir/transform/generator.rs @@ -327,7 +327,8 @@ fn locals_live_across_suspend_points<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } } - // The implicit argument is defined after each suspend point so it can never be live in a suspend point. + // The implicit argument is defined after each suspend point so it can never + // be live in a suspend point. set.remove(&Local::new(2)); // The generator argument is ignored @@ -340,7 +341,9 @@ fn compute_layout<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId, source: MirSource, interior: GeneratorInterior<'tcx>, - mir: &mut Mir<'tcx>) -> (HashMap, usize)>, GeneratorLayout<'tcx>) { + mir: &mut Mir<'tcx>) + -> (HashMap, usize)>, GeneratorLayout<'tcx>) +{ let source_info = SourceInfo { span: mir.span, scope: ARGUMENT_VISIBILITY_SCOPE, @@ -349,7 +352,7 @@ fn compute_layout<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let mut live_locals = locals_live_across_suspend_points(tcx, mir, source); let allowed = tcx.erase_regions(&interior.as_slice()); - + for (local, decl) in mir.local_decls.iter_enumerated() { if !live_locals.contains(&local) { continue; @@ -363,7 +366,10 @@ fn compute_layout<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } let upvar_len = mir.upvar_decls.len(); - let live_decls : Vec<_> = mir.local_decls.iter_enumerated_mut().filter(|&(local, _)| live_locals.contains(&local)).collect(); + let live_decls : Vec<_> = mir.local_decls + .iter_enumerated_mut() + .filter(|&(local, _)| live_locals.contains(&local)) + .collect(); let mut remap = HashMap::new(); let unit = tcx.mk_nil(); @@ -383,7 +389,7 @@ fn compute_layout<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let layout = GeneratorLayout { fields: vars }; - + (remap, layout) } @@ -421,7 +427,7 @@ fn elaborate_generator_drops<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, _ => continue, }; let unwind = if let Some(unwind) = unwind { - Unwind::To(unwind) + Unwind::To(unwind) } else { Unwind::InCleanup }; @@ -503,7 +509,7 @@ fn generate_drop<'a, 'tcx>( // Remove the implicit argument mir.arg_count = 1; mir.local_decls.raw.pop(); - + // Replace the return variable let source_info = SourceInfo { span: mir.span, @@ -524,7 +530,7 @@ fn generate_drop<'a, 'tcx>( mutability: Mutability::Mut, ty: tcx.mk_ptr(ty::TypeAndMut { ty: gen_ty, - mutbl: hir::Mutability::MutMutable, + mutbl: hir::Mutability::MutMutable, }), name: None, source_info, @@ -650,7 +656,10 @@ fn generate_resume<'a, 'tcx>( values: Cow::from(transform.bb_targets.values().map(|&i| { ConstInt::U32(i) }).collect::>()), - targets: transform.bb_targets.keys().map(|&(k, _)| k).chain(once(transform.return_block)).collect(), + targets: transform.bb_targets.keys() + .map(|&(k, _)| k) + .chain(once(transform.return_block)) + .collect(), }; insert_entry_point(mir, BasicBlockData { @@ -661,7 +670,7 @@ fn generate_resume<'a, 'tcx>( }), is_cleanup: false, }); - + // Make sure we remove dead blocks to remove // unrelated code from the drop part of the function simplify::remove_dead_blocks(mir); diff --git a/src/librustc_mir/transform/type_check.rs b/src/librustc_mir/transform/type_check.rs index b3cbe62321a15..b196d8aca1f4d 100644 --- a/src/librustc_mir/transform/type_check.rs +++ b/src/librustc_mir/transform/type_check.rs @@ -34,7 +34,10 @@ fn mirbug(tcx: TyCtxt, span: Span, msg: &str) { macro_rules! span_mirbug { ($context:expr, $elem:expr, $($message:tt)*) => ({ mirbug($context.tcx(), $context.last_span, - &format!("broken MIR in {:?} ({:?}): {}", $context.body_id, $elem, format!($($message)*))) + &format!("broken MIR in {:?} ({:?}): {}", + $context.body_id, + $elem, + format_args!($($message)*))) }) } diff --git a/src/librustc_mir/util/liveness.rs b/src/librustc_mir/util/liveness.rs index be13472dba32a..79293cfde251f 100644 --- a/src/librustc_mir/util/liveness.rs +++ b/src/librustc_mir/util/liveness.rs @@ -10,7 +10,8 @@ //! Liveness analysis. -// FIXME: Make sure this analysis uses proper MIR semantics. Also find out what the MIR semantics are. +// FIXME: Make sure this analysis uses proper MIR semantics. Also find out what +// the MIR semantics are. use rustc::mir::*; use rustc::mir::visit::{LvalueContext, Visitor}; @@ -188,7 +189,10 @@ pub fn write_mir_fn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, write_mir_intro(tcx, src, mir, w)?; for block in mir.basic_blocks().indices() { let print = |w: &mut Write, prefix, result: &IndexVec| { - let live: Vec = mir.local_decls.indices().filter(|i| result[block].contains(i)).map(|i| format!("{:?}", i)).collect(); + let live: Vec = mir.local_decls.indices() + .filter(|i| result[block].contains(i)) + .map(|i| format!("{:?}", i)) + .collect(); writeln!(w, "{} {{{}}}", prefix, live.join(", ")) }; print(w, " ", &result.ins)?; diff --git a/src/librustc_passes/mir_stats.rs b/src/librustc_passes/mir_stats.rs index 8df4559a01f31..cc7df7acb499f 100644 --- a/src/librustc_passes/mir_stats.rs +++ b/src/librustc_passes/mir_stats.rs @@ -171,8 +171,12 @@ impl<'a, 'tcx> mir_visit::Visitor<'tcx> for StatCollector<'a, 'tcx> { self.record(match *msg { AssertMessage::BoundsCheck { .. } => "AssertMessage::BoundsCheck", AssertMessage::Math(..) => "AssertMessage::Math", - AssertMessage::GeneratorResumedAfterReturn => "AssertMessage::GeneratorResumedAfterReturn", - AssertMessage::GeneratorResumedAfterPanic => "AssertMessage::GeneratorResumedAfterPanic", + AssertMessage::GeneratorResumedAfterReturn => { + "AssertMessage::GeneratorResumedAfterReturn" + } + AssertMessage::GeneratorResumedAfterPanic => { + "AssertMessage::GeneratorResumedAfterPanic" + } }, msg); self.super_assert_message(msg, location); } diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs index 6f03a806a4148..b938dc66e3c08 100644 --- a/src/librustc_trans/mir/constant.rs +++ b/src/librustc_trans/mir/constant.rs @@ -323,7 +323,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { ErrKind::Math(err.clone()) } mir::AssertMessage::GeneratorResumedAfterReturn | - mir::AssertMessage::GeneratorResumedAfterPanic => + mir::AssertMessage::GeneratorResumedAfterPanic => span_bug!(span, "{:?} should not appear in constants?", msg), }; diff --git a/src/librustc_trans/mir/mod.rs b/src/librustc_trans/mir/mod.rs index ba27f684ab3f3..3c38619cf5dd4 100644 --- a/src/librustc_trans/mir/mod.rs +++ b/src/librustc_trans/mir/mod.rs @@ -528,7 +528,7 @@ fn arg_local_refs<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, ty::TyRef(_, mt) | ty::TyRawPtr(mt) => (mt.ty, true), _ => (arg_ty, false) }; - + let upvar_tys = match closure_ty.sty { ty::TyClosure(def_id, substs) | ty::TyGenerator(def_id, substs, _) => substs.upvar_tys(def_id, tcx), diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index 4884c811a1b3c..ae64db88d8c5f 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -33,7 +33,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { expr, expected); // FIXME: See if expected_kind here can impact generators - + // It's always helpful for inference if we know the kind of // closure sooner rather than later, so first examine the expected // type, and see if can glean a closure kind from there. diff --git a/src/librustc_typeck/check/generator_interior.rs b/src/librustc_typeck/check/generator_interior.rs index 3b6708470a142..44bd2c26b3723 100644 --- a/src/librustc_typeck/check/generator_interior.rs +++ b/src/librustc_typeck/check/generator_interior.rs @@ -31,10 +31,13 @@ impl<'a, 'gcx, 'tcx> InteriorVisitor<'a, 'gcx, 'tcx> { if self.fcx.tcx.sess.verbose() { if let Some(s) = scope { self.fcx.tcx.sess.span_warn(s.span(&self.fcx.tcx.hir).unwrap_or(DUMMY_SP), - &format!("type in generator with scope = {:?}, type = {:?}", scope, self.fcx.resolve_type_vars_if_possible(&ty))); + &format!("type in generator with scope = {:?}, type = {:?}", + scope, + self.fcx.resolve_type_vars_if_possible(&ty))); } else { self.fcx.tcx.sess.span_warn(DUMMY_SP, - &format!("type in generator WITHOUT scope, type = {:?}", self.fcx.resolve_type_vars_if_possible(&ty))); + &format!("type in generator WITHOUT scope, type = {:?}", + self.fcx.resolve_type_vars_if_possible(&ty))); } if let Some(e) = expr { self.fcx.tcx.sess.span_warn(e.span, @@ -51,7 +54,10 @@ impl<'a, 'gcx, 'tcx> InteriorVisitor<'a, 'gcx, 'tcx> { } } -pub fn find_interior<'a, 'gcx, 'tcx>(fcx: &'a FnCtxt<'a, 'gcx, 'tcx>, def_id: DefId, body_id: hir::BodyId, witness: Ty<'tcx>) { +pub fn find_interior<'a, 'gcx, 'tcx>(fcx: &'a FnCtxt<'a, 'gcx, 'tcx>, + def_id: DefId, + body_id: hir::BodyId, + witness: Ty<'tcx>) { let body = fcx.tcx.hir.body(body_id); let mut visitor = InteriorVisitor { fcx, @@ -64,7 +70,9 @@ pub fn find_interior<'a, 'gcx, 'tcx>(fcx: &'a FnCtxt<'a, 'gcx, 'tcx>, def_id: De visitor.types.insert(fcx.tcx.types.bool); // Deduplicate types - let set: FxHashSet<_> = visitor.types.into_iter().map(|t| fcx.resolve_type_vars_if_possible(&t)).collect(); + let set: FxHashSet<_> = visitor.types.into_iter() + .map(|t| fcx.resolve_type_vars_if_possible(&t)) + .collect(); let types: Vec<_> = set.into_iter().collect(); let tuple = fcx.tcx.intern_tup(&types, false); diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index c763639d6057a..cf8b1d9c8f268 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -2567,7 +2567,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } let is_closure = match arg.node { - // TODO: Should this be applied for generators? + // FIXME: Should this be applied for generators? hir::ExprClosure(.., None) => true, _ => false }; diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 581a62d377de0..fb1c9ea5a9246 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1159,7 +1159,7 @@ fn type_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, if gen.is_some() { return tcx.typeck_tables_of(def_id).node_id_to_type(node_id); } - + tcx.mk_closure(def_id, Substs::for_item( tcx, def_id, |def, _| { diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index c377a77d87fa9..6b825a9d4012e 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -3714,7 +3714,7 @@ impl<'a> Parser<'a> { self.token.is_keyword(keywords::Gen) && self.look_ahead(1, |t| t.is_keyword(keywords::Arg)) } - + fn is_defaultness(&self) -> bool { // `pub` is included for better error messages self.token.is_keyword(keywords::Default) && diff --git a/src/test/compile-fail/generator/generator-not-fnmut.rs b/src/test/compile-fail/generator/generator-not-fnmut.rs index e33924c28949d..460db8e381996 100644 --- a/src/test/compile-fail/generator/generator-not-fnmut.rs +++ b/src/test/compile-fail/generator/generator-not-fnmut.rs @@ -11,15 +11,15 @@ #![feature(generators)] fn main() { - let mut a = Vec::::new(); + let mut a = Vec::::new(); - let mut test = || { - let _: () = gen arg; - yield 3; - a.push(true); - 2 - }; + let mut test = || { + let _: () = gen arg; + yield 3; + a.push(true); + 2 + }; - let a1 = test(); - let a2 = test(); //~ ERROR use of moved value + let a1 = test(); + let a2 = test(); //~ ERROR use of moved value } diff --git a/src/test/run-pass/generator/iterator-count.rs b/src/test/run-pass/generator/iterator-count.rs index 39a43690d943d..52f82873d4c0c 100644 --- a/src/test/run-pass/generator/iterator-count.rs +++ b/src/test/run-pass/generator/iterator-count.rs @@ -26,19 +26,19 @@ impl> Iterator for W { } fn test() -> impl Generator { - for i in 1..6 { - yield i - } + for i in 1..6 { + yield i + } } fn main() { - let end = 11; + let end = 11; - let closure_test = |start| { - for i in start..end { - yield i - } - }; + let closure_test = |start| { + for i in start..end { + yield i + } + }; - assert!(W(test()).chain(W(closure_test(6))).eq(1..11)); + assert!(W(test()).chain(W(closure_test(6))).eq(1..11)); } From 81030176dd36ad1efc0149ff8d57626bf42006d1 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 5 Jul 2017 15:02:30 -0700 Subject: [PATCH 003/113] std: Add forwarding impls of `Generator` trait --- src/liballoc/boxed.rs | 13 ++++++++++++- src/liballoc/lib.rs | 1 + src/libcore/ops/generator.rs | 17 +++++++++++++---- src/libcore/ops/mod.rs | 6 +----- 4 files changed, 27 insertions(+), 10 deletions(-) diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index 6318d22059f96..079a525f95126 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -66,7 +66,7 @@ use core::hash::{self, Hash}; use core::iter::FusedIterator; use core::marker::{self, Unsize}; use core::mem; -use core::ops::{CoerceUnsized, Deref, DerefMut}; +use core::ops::{CoerceUnsized, Deref, DerefMut, Generator, State}; use core::ops::{BoxPlace, Boxed, InPlace, Place, Placer}; use core::ptr::{self, Unique}; use core::convert::From; @@ -784,3 +784,14 @@ impl AsMut for Box { &mut **self } } + +#[unstable(feature = "generator_trait", issue = "0")] +impl Generator for Box + where T: Generator + ?Sized +{ + type Yield = T::Yield; + type Return = T::Return; + fn resume(&mut self, arg: U) -> State { + (**self).resume(arg) + } +} diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index 227fcfabcf11d..1252be447c302 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -97,6 +97,7 @@ #![feature(fundamental)] #![feature(fused)] #![feature(generic_param_attrs)] +#![feature(generator_trait)] #![feature(i128_type)] #![feature(inclusive_range)] #![feature(lang_items)] diff --git a/src/libcore/ops/generator.rs b/src/libcore/ops/generator.rs index 2a88c842a8f73..1e54eaaaa280e 100644 --- a/src/libcore/ops/generator.rs +++ b/src/libcore/ops/generator.rs @@ -10,8 +10,7 @@ /// The result of a generator resumption. #[derive(Debug)] -#[cfg(not(stage0))] -#[lang = "generator_state"] +#[cfg_attr(not(stage0), lang = "generator_state")] #[unstable(feature = "generator_trait", issue = "0")] pub enum State { /// The generator suspended with a value. @@ -22,8 +21,7 @@ pub enum State { } /// The trait implemented by builtin generator types. -#[cfg(not(stage0))] -#[lang = "generator"] +#[cfg_attr(not(stage0), lang = "generator")] #[unstable(feature = "generator_trait", issue = "0")] #[fundamental] pub trait Generator { @@ -36,3 +34,14 @@ pub trait Generator { /// This resumes the execution of the generator. fn resume(&mut self, arg: Arg) -> State; } + +#[unstable(feature = "generator_trait", issue = "0")] +impl<'a, T, U> Generator for &'a mut T + where T: Generator + ?Sized +{ + type Yield = T::Yield; + type Return = T::Return; + fn resume(&mut self, arg: U) -> State { + (**self).resume(arg) + } +} diff --git a/src/libcore/ops/mod.rs b/src/libcore/ops/mod.rs index 36b0a3c8a3472..a51b19110280e 100644 --- a/src/libcore/ops/mod.rs +++ b/src/libcore/ops/mod.rs @@ -191,11 +191,7 @@ pub use self::range::{RangeInclusive, RangeToInclusive}; pub use self::try::Try; #[unstable(feature = "generator_trait", issue = "0")] -#[cfg(not(stage0))] -pub use self::generator::State; -#[unstable(feature = "generator_trait", issue = "0")] -#[cfg(not(stage0))] -pub use self::generator::Generator; +pub use self::generator::{Generator, State}; #[unstable(feature = "placement_new_protocol", issue = "27779")] pub use self::place::{Place, Placer, InPlace, Boxed, BoxPlace}; From b5449b73e65e4e9622a4558e84774cc22755a17d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Thu, 6 Jul 2017 22:08:45 +0200 Subject: [PATCH 004/113] Ban explicit arguments on generators --- src/librustc/hir/lowering.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 8b092ff727ebf..50c8763600fa5 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -1958,6 +1958,11 @@ impl<'a> LoweringContext<'a> { gen = this.impl_arg.map(|_| hir::GeneratorClause::Movable); e }); + if gen.is_some() && !decl.inputs.is_empty() { + this.sess.span_fatal( + fn_decl_span, + &format!("generators cannot have explicit arguments")); + } hir::ExprClosure(this.lower_capture_clause(capture_clause), this.lower_fn_decl(decl), body_id, From 0b5b0122ae283df567d1b2fddd7fc4ad17125fb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Fri, 7 Jul 2017 00:02:35 +0200 Subject: [PATCH 005/113] Consider all implementations of Generator, not just built in ones --- src/librustc/traits/select.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 887edc5036490..3fcd79f706b78 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -1305,9 +1305,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { &mut candidates)?; } else if self.tcx().lang_items.unsize_trait() == Some(def_id) { self.assemble_candidates_for_unsizing(obligation, &mut candidates); - } else if self.tcx().lang_items.gen_trait() == Some(def_id) { - self.assemble_generator_candidates(obligation, &mut candidates)?; } else { + self.assemble_generator_candidates(obligation, &mut candidates)?; self.assemble_closure_candidates(obligation, &mut candidates)?; self.assemble_fn_pointer_candidates(obligation, &mut candidates)?; self.assemble_candidates_from_impls(obligation, &mut candidates)?; @@ -1497,6 +1496,10 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { candidates: &mut SelectionCandidateSet<'tcx>) -> Result<(),SelectionError<'tcx>> { + if self.tcx().lang_items.gen_trait() != Some(obligation.predicate.def_id()) { + return Ok(()); + } + let self_ty = *obligation.self_ty().skip_binder(); let (closure_def_id, substs) = match self_ty.sty { ty::TyGenerator(id, substs, _) => (id, substs), From cc40f58b8ba7019f52acd4e8da015ddd249db86a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Sat, 8 Jul 2017 00:58:33 +0200 Subject: [PATCH 006/113] Added some tests --- .../generator/invalid-positions.rs | 23 ++++++++++++++++++ ...yield.rs => no-arguments-on-generators.rs} | 9 +++---- .../implicit-argument-dead-when-suspended.rs} | 24 ++++++++++++------- 3 files changed, 44 insertions(+), 12 deletions(-) create mode 100644 src/test/compile-fail/generator/invalid-positions.rs rename src/test/compile-fail/generator/{const-yield.rs => no-arguments-on-generators.rs} (72%) rename src/test/{compile-fail/generator/generator-not-fnmut.rs => run-pass/generator/implicit-argument-dead-when-suspended.rs} (64%) diff --git a/src/test/compile-fail/generator/invalid-positions.rs b/src/test/compile-fail/generator/invalid-positions.rs new file mode 100644 index 0000000000000..c2f5b20d5758f --- /dev/null +++ b/src/test/compile-fail/generator/invalid-positions.rs @@ -0,0 +1,23 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(generators)] + +const A: u8 = { yield 3u8; gen arg; 3u8}; +//~^ ERROR yield statement outside +//~| ERROR gen arg expression outside + +static B: u8 = { yield 3u8; gen arg; 3u8}; +//~^ ERROR yield statement outside +//~| ERROR gen arg expression outside + +fn main() { yield; gen arg; } +//~^ ERROR yield statement outside +//~| ERROR gen arg expression outside diff --git a/src/test/compile-fail/generator/const-yield.rs b/src/test/compile-fail/generator/no-arguments-on-generators.rs similarity index 72% rename from src/test/compile-fail/generator/const-yield.rs rename to src/test/compile-fail/generator/no-arguments-on-generators.rs index fa99e8553a0b4..9c68fe4ceda80 100644 --- a/src/test/compile-fail/generator/const-yield.rs +++ b/src/test/compile-fail/generator/no-arguments-on-generators.rs @@ -10,7 +10,8 @@ #![feature(generators)] -const A: u8 = { yield 3u8; 3u8}; //~ ERROR yield statement outside of function body -static B: u8 = { yield 3u8; 3u8}; //~ ERROR yield statement outside of function body - -fn main() {} \ No newline at end of file +fn main() { + let gen = |start| { //~ ERROR generators cannot have explicit arguments + yield; + }; +} \ No newline at end of file diff --git a/src/test/compile-fail/generator/generator-not-fnmut.rs b/src/test/run-pass/generator/implicit-argument-dead-when-suspended.rs similarity index 64% rename from src/test/compile-fail/generator/generator-not-fnmut.rs rename to src/test/run-pass/generator/implicit-argument-dead-when-suspended.rs index 460db8e381996..722ec2477efbe 100644 --- a/src/test/compile-fail/generator/generator-not-fnmut.rs +++ b/src/test/run-pass/generator/implicit-argument-dead-when-suspended.rs @@ -10,16 +10,24 @@ #![feature(generators)] +use std::cell::Cell; + +struct Flag<'a>(&'a Cell); + +impl<'a> Drop for Flag<'a> { + fn drop(&mut self) { + self.0.set(false) + } +} + fn main() { - let mut a = Vec::::new(); + let alive = Cell::new(true); - let mut test = || { - let _: () = gen arg; - yield 3; - a.push(true); - 2 + let gen = || { + yield; }; - let a1 = test(); - let a2 = test(); //~ ERROR use of moved value + gen.resume(Flag(&alive)); + + assert_eq!(alive.get(), false); } From 51bb31ad2551c0bf82a556792303ec1de5b76dbc Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 7 Jul 2017 15:31:03 -0700 Subject: [PATCH 007/113] Fix tests --- src/liballoc/lib.rs | 2 +- src/test/run-pass/generator/iterator-count.rs | 11 +++++++---- src/test/ui/resolve/token-error-correct.stderr | 4 ++-- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index 1252be447c302..6c852a13867a8 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -82,6 +82,7 @@ #![cfg_attr(not(test), feature(core_float))] #![cfg_attr(not(test), feature(exact_size_is_empty))] #![cfg_attr(not(test), feature(slice_rotate))] +#![cfg_attr(not(test), feature(generator_trait))] #![cfg_attr(test, feature(rand, test))] #![feature(allow_internal_unstable)] #![feature(box_patterns)] @@ -97,7 +98,6 @@ #![feature(fundamental)] #![feature(fused)] #![feature(generic_param_attrs)] -#![feature(generator_trait)] #![feature(i128_type)] #![feature(inclusive_range)] #![feature(lang_items)] diff --git a/src/test/run-pass/generator/iterator-count.rs b/src/test/run-pass/generator/iterator-count.rs index 52f82873d4c0c..c415ef2beb304 100644 --- a/src/test/run-pass/generator/iterator-count.rs +++ b/src/test/run-pass/generator/iterator-count.rs @@ -26,19 +26,22 @@ impl> Iterator for W { } fn test() -> impl Generator { - for i in 1..6 { - yield i + || { + for i in 1..6 { + yield i + } } } fn main() { + let start = 6; let end = 11; - let closure_test = |start| { + let closure_test = || { for i in start..end { yield i } }; - assert!(W(test()).chain(W(closure_test(6))).eq(1..11)); + assert!(W(test()).chain(W(closure_test)).eq(1..11)); } diff --git a/src/test/ui/resolve/token-error-correct.stderr b/src/test/ui/resolve/token-error-correct.stderr index 226fa6469bc74..281c21f6f85ee 100644 --- a/src/test/ui/resolve/token-error-correct.stderr +++ b/src/test/ui/resolve/token-error-correct.stderr @@ -28,11 +28,11 @@ error: expected expression, found `;` 14 | foo(bar(; | ^ -error: expected one of `)`, `,`, `.`, `<`, `?`, `break`, `continue`, `false`, `for`, `if`, `loop`, `match`, `move`, `return`, `true`, `unsafe`, `while`, or an operator, found `;` +error: expected one of `)`, `,`, `.`, `<`, `?`, `break`, `continue`, `false`, `for`, `if`, `loop`, `match`, `move`, `return`, `true`, `unsafe`, `while`, `yield`, or an operator, found `;` --> $DIR/token-error-correct.rs:14:13 | 14 | foo(bar(; - | ^ expected one of 18 possible tokens here + | ^ expected one of 19 possible tokens here error: expected expression, found `)` --> $DIR/token-error-correct.rs:23:1 From 5efb0cbe046127d074fd2c85b7cafb5a4d5aea44 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 7 Jul 2017 16:12:44 -0700 Subject: [PATCH 008/113] Add some generator pass/fail tests --- src/test/compile-fail/generator/borrowing.rs | 32 +++ .../compile-fail/generator/not-send-sync.rs | 34 ++++ src/test/run-pass/generator/control-flow.rs | 56 ++++++ src/test/run-pass/generator/drop-env.rs | 73 +++++++ src/test/run-pass/generator/panic-drops.rs | 58 ++++++ src/test/run-pass/generator/panic-safe.rs | 35 ++++ .../run-pass/generator/resume-after-return.rs | 33 ++++ src/test/run-pass/generator/smoke.rs | 187 ++++++++++++++++++ 8 files changed, 508 insertions(+) create mode 100644 src/test/compile-fail/generator/borrowing.rs create mode 100644 src/test/compile-fail/generator/not-send-sync.rs create mode 100644 src/test/run-pass/generator/control-flow.rs create mode 100644 src/test/run-pass/generator/drop-env.rs create mode 100644 src/test/run-pass/generator/panic-drops.rs create mode 100644 src/test/run-pass/generator/panic-safe.rs create mode 100644 src/test/run-pass/generator/resume-after-return.rs create mode 100644 src/test/run-pass/generator/smoke.rs diff --git a/src/test/compile-fail/generator/borrowing.rs b/src/test/compile-fail/generator/borrowing.rs new file mode 100644 index 0000000000000..c721ea04acf17 --- /dev/null +++ b/src/test/compile-fail/generator/borrowing.rs @@ -0,0 +1,32 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(generators, generator_trait)] + +use std::ops::{State, Generator}; +use std::cell::Cell; + +fn main() { + let _b = { + let a = 3; + (|| yield &a).resume(()) + //~^ ERROR: `a` does not live long enough + }; + + let _b = { + let a = 3; + || { + let _: () = gen arg; // TODO: shouldn't be needed for inference + yield &a + //~^ ERROR: `a` does not live long enough + } + }; +} + diff --git a/src/test/compile-fail/generator/not-send-sync.rs b/src/test/compile-fail/generator/not-send-sync.rs new file mode 100644 index 0000000000000..6cfc8dd333ef3 --- /dev/null +++ b/src/test/compile-fail/generator/not-send-sync.rs @@ -0,0 +1,34 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(generators, generator_trait)] + +use std::ops::{State, Generator}; +use std::cell::Cell; + +fn main() { + fn assert_sync(_: T) {} + fn assert_send(_: T) {} + + assert_sync(|| { + //~^ ERROR: Sync` is not satisfied + let a = Cell::new(2); + yield; + let _: () = gen arg; + }); + + let a = Cell::new(2); + assert_send(|| { + //~^ ERROR: Sync` is not satisfied + drop(&a); + yield; + let _: () = gen arg; + }); +} diff --git a/src/test/run-pass/generator/control-flow.rs b/src/test/run-pass/generator/control-flow.rs new file mode 100644 index 0000000000000..911bb96b5827e --- /dev/null +++ b/src/test/run-pass/generator/control-flow.rs @@ -0,0 +1,56 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(generators, generator_trait)] + +use std::ops::{State, Generator}; + +fn finish(mut amt: usize, mut t: T) -> T::Return + where T: Generator<(), Yield = ()> +{ + loop { + match t.resume(()) { + State::Yielded(()) => amt = amt.checked_sub(1).unwrap(), + State::Complete(ret) => { + assert_eq!(amt, 0); + return ret + } + } + } + +} + +fn main() { + finish(1, || yield); + finish(8, || { + for _ in 0..8 { + yield; + } + }); + finish(1, || { + if true { + yield; + } else { + } + }); + finish(1, || { + if false { + } else { + yield; + } + }); + finish(2, || { + if { yield; false } { + yield; + panic!() + } + yield + }); +} diff --git a/src/test/run-pass/generator/drop-env.rs b/src/test/run-pass/generator/drop-env.rs new file mode 100644 index 0000000000000..43d0af7a07348 --- /dev/null +++ b/src/test/run-pass/generator/drop-env.rs @@ -0,0 +1,73 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(generators, generator_trait)] + +use std::ops::Generator; +use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering}; + +static A: AtomicUsize = ATOMIC_USIZE_INIT; + +struct B; + +impl Drop for B { + fn drop(&mut self) { + A.fetch_add(1, Ordering::SeqCst); + } +} + +fn main() { + t1(); + t2(); + t3(); +} + +fn t1() { + let b = B; + let mut foo = || { + yield; + drop(b); + }; + + let n = A.load(Ordering::SeqCst); + drop(foo.resume(())); + assert_eq!(A.load(Ordering::SeqCst), n); + drop(foo); + assert_eq!(A.load(Ordering::SeqCst), n + 1); +} + +fn t2() { + let b = B; + let mut foo = || { + yield b; + }; + + let n = A.load(Ordering::SeqCst); + drop(foo.resume(())); + assert_eq!(A.load(Ordering::SeqCst), n + 1); + drop(foo); + assert_eq!(A.load(Ordering::SeqCst), n + 1); +} + +fn t3() { + let b = B; + let mut foo = || { + let _: () = gen arg; // TODO: this line should not be necessary + yield; + drop(b); + }; + + let n = A.load(Ordering::SeqCst); + assert_eq!(A.load(Ordering::SeqCst), n); + drop(foo); + // TODO: we should assert n+1 here, not n + // assert_eq!(A.load(Ordering::SeqCst), n + 1); + assert_eq!(A.load(Ordering::SeqCst), n); +} diff --git a/src/test/run-pass/generator/panic-drops.rs b/src/test/run-pass/generator/panic-drops.rs new file mode 100644 index 0000000000000..6b9d7da197f10 --- /dev/null +++ b/src/test/run-pass/generator/panic-drops.rs @@ -0,0 +1,58 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(generators, generator_trait)] + +use std::ops::Generator; +use std::panic; +use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering}; + +static A: AtomicUsize = ATOMIC_USIZE_INIT; + +struct B; + +impl Drop for B { + fn drop(&mut self) { + A.fetch_add(1, Ordering::SeqCst); + } +} + +fn main() { + let b = B; + let mut foo = || { + if true { + panic!(); + } + drop(b); + yield; + }; + + assert_eq!(A.load(Ordering::SeqCst), 0); + let res = panic::catch_unwind(panic::AssertUnwindSafe(|| { + foo.resume(()) + })); + assert!(res.is_err()); + assert_eq!(A.load(Ordering::SeqCst), 1); + + let mut foo = || { + if true { + panic!(); + } + drop(B); + yield; + }; + + assert_eq!(A.load(Ordering::SeqCst), 1); + let res = panic::catch_unwind(panic::AssertUnwindSafe(|| { + foo.resume(()) + })); + assert!(res.is_err()); + assert_eq!(A.load(Ordering::SeqCst), 1); +} diff --git a/src/test/run-pass/generator/panic-safe.rs b/src/test/run-pass/generator/panic-safe.rs new file mode 100644 index 0000000000000..7d86d7b6d94ae --- /dev/null +++ b/src/test/run-pass/generator/panic-safe.rs @@ -0,0 +1,35 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(generators, generator_trait)] + +use std::ops::Generator; +use std::panic; + +fn main() { + let mut foo = || { + if true { + panic!(); + } + yield; + }; + + let res = panic::catch_unwind(panic::AssertUnwindSafe(|| { + foo.resume(()) + })); + assert!(res.is_err()); + + for _ in 0..10 { + let res = panic::catch_unwind(panic::AssertUnwindSafe(|| { + foo.resume(()) + })); + assert!(res.is_err()); + } +} diff --git a/src/test/run-pass/generator/resume-after-return.rs b/src/test/run-pass/generator/resume-after-return.rs new file mode 100644 index 0000000000000..ca85d2545c822 --- /dev/null +++ b/src/test/run-pass/generator/resume-after-return.rs @@ -0,0 +1,33 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(generators, generator_trait)] + +use std::ops::{State, Generator}; +use std::panic; + +fn main() { + let mut foo = || { + if true { + return + } + yield; + }; + + match foo.resume(()) { + State::Complete(()) => {} + s => panic!("bad state: {:?}", s), + } + + match panic::catch_unwind(move || foo.resume(())) { + Ok(_) => panic!("generator successfully resumed"), + Err(_) => {} + } +} diff --git a/src/test/run-pass/generator/smoke.rs b/src/test/run-pass/generator/smoke.rs new file mode 100644 index 0000000000000..daa32aa3213e0 --- /dev/null +++ b/src/test/run-pass/generator/smoke.rs @@ -0,0 +1,187 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: --test + +#![feature(generators, generator_trait)] + +use std::ops::{State, Generator}; +use std::thread; + +#[test] +fn simple() { + let mut foo = || { + if false { + yield; + } + }; + + match foo.resume(()) { + State::Complete(()) => {} + s => panic!("bad state: {:?}", s), + } +} + +#[test] +fn return_capture() { + let a = String::from("foo"); + let mut foo = || { + if false { + yield; + } + a + }; + + match foo.resume(()) { + State::Complete(ref s) if *s == "foo" => {} + s => panic!("bad state: {:?}", s), + } +} + +#[test] +fn simple_yield() { + let mut foo = || { + yield; + }; + + match foo.resume(()) { + State::Yielded(()) => {} + s => panic!("bad state: {:?}", s), + } + match foo.resume(()) { + State::Complete(()) => {} + s => panic!("bad state: {:?}", s), + } +} + +#[test] +fn yield_capture() { + let b = String::from("foo"); + let mut foo = || { + yield b; + }; + + match foo.resume(()) { + State::Yielded(ref s) if *s == "foo" => {} + s => panic!("bad state: {:?}", s), + } + match foo.resume(()) { + State::Complete(()) => {} + s => panic!("bad state: {:?}", s), + } +} + +#[test] +fn simple_yield_value() { + let mut foo = || { + yield String::from("bar"); + return String::from("foo") + }; + + match foo.resume(()) { + State::Yielded(ref s) if *s == "bar" => {} + s => panic!("bad state: {:?}", s), + } + match foo.resume(()) { + State::Complete(ref s) if *s == "foo" => {} + s => panic!("bad state: {:?}", s), + } +} + +#[test] +fn return_after_yield() { + let a = String::from("foo"); + let mut foo = || { + yield; + return a + }; + + match foo.resume(()) { + State::Yielded(()) => {} + s => panic!("bad state: {:?}", s), + } + match foo.resume(()) { + State::Complete(ref s) if *s == "foo" => {} + s => panic!("bad state: {:?}", s), + } +} + +#[test] +fn send_and_sync() { + assert_send_sync(|| { + let _: () = gen arg; + yield + }); + assert_send_sync(|| { + let _: () = gen arg; + yield String::from("foo"); + }); + assert_send_sync(|| { + let _: () = gen arg; + yield; + return String::from("foo"); + }); + let a = 3; + assert_send_sync(|| { + let _: () = gen arg; + yield a; + return + }); + let a = 3; + assert_send_sync(move || { + let _: () = gen arg; + yield a; + return + }); + let a = String::from("a"); + assert_send_sync(|| { + let _: () = gen arg; + yield ; + drop(a); + return + }); + let a = String::from("a"); + assert_send_sync(move || { + let _: () = gen arg; + yield ; + drop(a); + return + }); + + fn assert_send_sync(_: T) {} +} + +#[test] +fn send_over_threads() { + let mut foo = || { yield }; + thread::spawn(move || { + match foo.resume(()) { + State::Yielded(()) => {} + s => panic!("bad state: {:?}", s), + } + match foo.resume(()) { + State::Complete(()) => {} + s => panic!("bad state: {:?}", s), + } + }).join().unwrap(); + + let a = String::from("a"); + let mut foo = || { yield a }; + thread::spawn(move || { + match foo.resume(()) { + State::Yielded(ref s) if *s == "a" => {} + s => panic!("bad state: {:?}", s), + } + match foo.resume(()) { + State::Complete(()) => {} + s => panic!("bad state: {:?}", s), + } + }).join().unwrap(); +} From bc9b4deeb525235e9ac0d20d0bb00c88641540e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Sat, 8 Jul 2017 19:30:14 +0200 Subject: [PATCH 009/113] Make yield and gen arg outside generator literals an error and update tests --- src/librustc_typeck/check/closure.rs | 2 +- src/librustc_typeck/check/mod.rs | 41 +++++++++++-------- src/librustc_typeck/diagnostics.rs | 4 +- .../compile-fail/generator/yield-in-const.rs | 15 +++++++ .../generator/yield-in-function.rs | 15 +++++++ ...nvalid-positions.rs => yield-in-static.rs} | 8 ---- src/test/run-pass/generator/iterator-count.rs | 11 ++--- 7 files changed, 64 insertions(+), 32 deletions(-) create mode 100644 src/test/compile-fail/generator/yield-in-const.rs create mode 100644 src/test/compile-fail/generator/yield-in-function.rs rename src/test/compile-fail/generator/{invalid-positions.rs => yield-in-static.rs} (73%) diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index ae64db88d8c5f..0f68b15977848 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -82,7 +82,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.param_env, &fn_sig); - let interior = check_fn(self, self.param_env, fn_sig, decl, expr.id, body).1; + let interior = check_fn(self, self.param_env, fn_sig, decl, expr.id, body, true).1; if let Some(interior) = interior { let closure_substs = ty::ClosureSubsts { diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index cf8b1d9c8f268..1d1631c4fa7e7 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -871,7 +871,7 @@ fn typeck_tables_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, param_env, &fn_sig); - check_fn(&inh, param_env, fn_sig, decl, id, body).0 + check_fn(&inh, param_env, fn_sig, decl, id, body, false).0 } else { let fcx = FnCtxt::new(&inh, param_env, body.value.id); let expected_type = tcx.type_of(def_id); @@ -987,7 +987,8 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>, fn_sig: ty::FnSig<'tcx>, decl: &'gcx hir::FnDecl, fn_id: ast::NodeId, - body: &'gcx hir::Body) + body: &'gcx hir::Body, + can_be_generator: bool) -> (FnCtxt<'a, 'gcx, 'tcx>, Option>) { let mut fn_sig = fn_sig.clone(); @@ -1014,22 +1015,30 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>, let def_id = fcx.tcx.hir.local_def_id(fn_id); let span = body.value.span; + if fcx.tcx.sess.verbose() { + println!("checking body {} {}", fn_id, can_be_generator); + } + if let Some(ref impl_arg) = body.impl_arg { - let impl_arg_ty = fcx.infcx.type_var_for_impl_arg(span, def_id); + if can_be_generator { + let impl_arg_ty = fcx.infcx.type_var_for_impl_arg(span, def_id); - // Require impl_arg: 'static - let cause = traits::ObligationCause::new(span, body.value.id, traits::MiscObligation);; - fcx.fulfillment_cx.borrow_mut() - .register_region_obligation(impl_arg_ty, - fcx.tcx.types.re_static, - cause); + // Require impl_arg: 'static + let cause = traits::ObligationCause::new(span, + body.value.id, + traits::MiscObligation); + fcx.fulfillment_cx.borrow_mut() + .register_region_obligation(impl_arg_ty, + fcx.tcx.types.re_static, + cause); - fcx.impl_arg_ty = Some(impl_arg_ty); + fcx.impl_arg_ty = Some(impl_arg_ty); - // Write the type to the impl arg id - fcx.write_ty(impl_arg.id, impl_arg_ty); + // Write the type to the impl arg id + fcx.write_ty(impl_arg.id, impl_arg_ty); - fcx.suspend_ty = Some(fcx.next_ty_var(TypeVariableOrigin::TypeInference(span))); + fcx.suspend_ty = Some(fcx.next_ty_var(TypeVariableOrigin::TypeInference(span))); + } } GatherLocalsVisitor { fcx: &fcx, }.visit_body(body); @@ -1050,7 +1059,7 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>, fcx.write_ty(arg.id, arg_ty); } - let gen_ty = if body.is_generator() { + let gen_ty = if can_be_generator && body.is_generator() { let gen_sig = ty::GenSig { impl_arg_ty: fcx.impl_arg_ty.unwrap(), suspend_ty: fcx.suspend_ty.unwrap(), @@ -3994,7 +4003,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } None => { struct_span_err!(self.tcx.sess, expr.span, E0803, - "impl arg expression outside of function body").emit(); + "gen arg expression outside of generator literal").emit(); tcx.types.err } } @@ -4006,7 +4015,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } None => { struct_span_err!(self.tcx.sess, expr.span, E0802, - "yield statement outside of function body").emit(); + "yield statement outside of generator literal").emit(); } } tcx.mk_nil() diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index 4313aa59202f9..0463f82ccce25 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -4668,7 +4668,7 @@ register_diagnostics! { E0592, // duplicate definitions with name `{}` // E0613, // Removed (merged with E0609) E0801, // unexpected generator return - E0802, // yield statement outside of function body - E0803, // impl arg expression outside of function body + E0802, // yield statement outside of generator literal + E0803, // gen arg expression outside of generator literal E0804, // cannot determine the type for the implicit argument of this generator } diff --git a/src/test/compile-fail/generator/yield-in-const.rs b/src/test/compile-fail/generator/yield-in-const.rs new file mode 100644 index 0000000000000..5176f3c5f5687 --- /dev/null +++ b/src/test/compile-fail/generator/yield-in-const.rs @@ -0,0 +1,15 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(generators)] + +const A: u8 = { yield 3u8; gen arg; 3u8}; +//~^ ERROR yield statement outside +//~| ERROR gen arg expression outside diff --git a/src/test/compile-fail/generator/yield-in-function.rs b/src/test/compile-fail/generator/yield-in-function.rs new file mode 100644 index 0000000000000..95ec1224421f2 --- /dev/null +++ b/src/test/compile-fail/generator/yield-in-function.rs @@ -0,0 +1,15 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(generators)] + +fn main() { yield; gen arg; } +//~^ ERROR yield statement outside +//~| ERROR gen arg expression outside diff --git a/src/test/compile-fail/generator/invalid-positions.rs b/src/test/compile-fail/generator/yield-in-static.rs similarity index 73% rename from src/test/compile-fail/generator/invalid-positions.rs rename to src/test/compile-fail/generator/yield-in-static.rs index c2f5b20d5758f..f4cad13ce8eb5 100644 --- a/src/test/compile-fail/generator/invalid-positions.rs +++ b/src/test/compile-fail/generator/yield-in-static.rs @@ -10,14 +10,6 @@ #![feature(generators)] -const A: u8 = { yield 3u8; gen arg; 3u8}; -//~^ ERROR yield statement outside -//~| ERROR gen arg expression outside - static B: u8 = { yield 3u8; gen arg; 3u8}; //~^ ERROR yield statement outside //~| ERROR gen arg expression outside - -fn main() { yield; gen arg; } -//~^ ERROR yield statement outside -//~| ERROR gen arg expression outside diff --git a/src/test/run-pass/generator/iterator-count.rs b/src/test/run-pass/generator/iterator-count.rs index c415ef2beb304..e44aa05923571 100644 --- a/src/test/run-pass/generator/iterator-count.rs +++ b/src/test/run-pass/generator/iterator-count.rs @@ -34,14 +34,15 @@ fn test() -> impl Generator { } fn main() { - let start = 6; let end = 11; - let closure_test = || { - for i in start..end { - yield i + let closure_test = |start| { + || { + for i in start..end { + yield i + } } }; - assert!(W(test()).chain(W(closure_test)).eq(1..11)); + assert!(W(test()).chain(W(closure_test(6))).eq(1..11)); } From 55bb1c08d3baaae57777453f7c3b054f74059b88 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 10 Jul 2017 09:30:57 -0700 Subject: [PATCH 010/113] Add documentation for generators --- .../src/language-features/generators.md | 232 ++++++++++++++++++ src/libcore/ops/generator.rs | 92 ++++++- 2 files changed, 320 insertions(+), 4 deletions(-) create mode 100644 src/doc/unstable-book/src/language-features/generators.md diff --git a/src/doc/unstable-book/src/language-features/generators.md b/src/doc/unstable-book/src/language-features/generators.md new file mode 100644 index 0000000000000..8d9d9846a2332 --- /dev/null +++ b/src/doc/unstable-book/src/language-features/generators.md @@ -0,0 +1,232 @@ +# `generators` + +The tracking issue for this feature is: [#43122] + +[#34511]: https://github.com/rust-lang/rust/issues/43122 + +------------------------ + +The `generators` feature gate in Rust allows you to define generator or +coroutine literals. A generator is a "resumable function" that syntactically +resembles a closure but compiles to much different semantics in the compiler +itself. + +Generators are an extra-unstable feature in the compiler right now. Added in +[RFC 2033] they're mostly intended right now as a information/constraint +gathering phase. The intent is that experimentation can happen on the nightly +compiler before actual stabilization. A further RFC will be required to +stabilize generators/coroutines and will likely contain at least a few small +tweaks to the overall design. + +[RFC 2033]: https://github.com/rust-lang/rfcs/pull/2033 + +A syntactical example of a generator is: + +```rust +#![feature(generators, generator_trait)] + +use std::ops::{Generator, State}; + +fn main() { + let mut generator = || { + yield 1; + return "foo" + }; + + match generator.resume(()) { + State::Yielded(1) => {} + _ => panic!("unexpected return from resume"), + } + match generator.resume(()) { + State::Complete("foo") => {} + _ => panic!("unexpected return from resume"), + } +} +``` + +Generators are closure-like literals which can contain a `yield` statement. The +`yield` statement takes an optional expression of a value to yield out of the +generator. All generator literals implement the `Generator` trait in the +`std::ops` module. The `Generator` trait has one main method, `resume`, which +resumes execution of the closure at the previous suspension point. + +An example of the control flow of generators is that the following example +prints all numbers in order: + +```rust +#![feature(generators, generator_trait)] + +use std::ops::Generator; + +fn main() { + let mut generator = || { + println!("2"); + yield; + println!("4"); + }; + + println!("1"); + drop(generator.resume(())); + println!("3"); + drop(generator.resume(())); + println!("5"); +} +``` + +At this time the main intended use case of generators is an implementation +primitive for async/await syntax, but generators will likely be extended to +ergonomic implementations of iterators and other primitives in the future. +Feedback on the design and usage is always appreciated! + +### The `Generator` trait + +The `Generator` trait in `std::ops` currently looks like: + +``` +pub trait Generator { + type Yield; + type Return; + fn resume(&mut self, arg: Arg) -> State; +} +``` + +The `Generator::Yield` type is the type of values that can be yielded with the +`yield` statement. The `Generator::Return` type is the returned type of the +generator. This is typically the last expression in a generator's definition or +any value passed to `return` in a generator. The `resume` function is the entry +point for executing the `Generator` itself. + +The return value of `resume`, `State`, looks like: + +``` +pub enum State { + Yielded(Y), + Complete(R), +} +``` + +The `Yielded` variant indicates that the generator can later be resumed. This +corresponds to a `yield` point in a generator. The `Complete` variant indicates +that the generator is complete and cannot be resumed again. Calling `resume` +after a generator has returned `Complete` will likely result in a panic of the +program. + +### Closure-like semantics + +The closure-like syntax for generators alludes to the fact that they also have +closure-like semantics. Namely: + +* When created, a generator executes no code. A closure literal does not + actually execute any of the closure's code on construction, and similarly a + generator literal does not execute any code inside the generator when + constructed. + +* Generators can capture outer variables by reference or by move, and this can + be tweaked with the `move` keyword at the beginning of the closure. Like + closures all generators will have an implicit environment which is inferred by + the compiler. Outer variables can be moved into a generator for use as the + generator progresses. + +* Generator literals produce a value with a unique type which implements the + `std::ops::Generator` trait. This allows actual execution of the genrator + through the `Generator::resume` method as well as also naming it in return + types and such. + +* Traits like `Send` and `Sync` are automatically implemented for a `Generator` + depending on the captured variables of the environment. Note, though, that + generators, like closures, do not implement traits like `Copy` or `Clone` + automatically. + +* Whenever a generator is dropped it will drop all captured environment + variables. + +### Generators as state machines + +In the compiler generators are currently compiled as state machines. Each +`yield` expression will correspond to a different state that stores all live +variables over that suspension point. Resumption of a generator will dispatch on +the current state and then execute internally until a `yield` is reached, at +which point all state is saved off in the generator and a value is returned. + +Let's take a look at an example to see what's going on here: + +```rust +#![feature(generators, generator_trait)] + +use std::ops::Generator; + +fn main() { + let ret = "foo"; + let mut generator = move || { + yield 1; + return ret + }; + + drop(generator.resume(())) + drop(generator.resume(())) +} +``` + +This generator literal will compile down to something similar to: + +```rust +#![feature(generators, generator_trait)] + +use std::ops::{Generator, State}; + +fn main() { + let ret = "foo"; + let mut generator = { + enum __Generator { + Start(&'static str), + Yield1(&'static str), + Done, + } + + impl Generator for __Generator { + type Yield = i32; + type Return = &'static str; + + fn resume(&mut self, arg: ()) -> State { + use std::mem; + match mem::replace(self, __Generator::Done) { + __Generator::Start(s) => { + *self = __Generator::Yield1(s); + State::Yielded(1) + } + + __Generator::Yield1(s) => { + *self = __Generator::Done; + State::Complete(s) + } + + __Generator::Done => { + panic!("generator resumed after completion") + } + } + } + } + + __Generator::Start(ret) : impl Generator + }; + + drop(generator.resume(())) + drop(generator.resume(())) +} +``` + +Notably here we can see that the compiler is generating a fresh type, +`__Generator` in this case. This type has a number of states (represented here +as an `enum`) corresponding to each of the conceptual states of the generator. +At the beginning we're closing over our outer variable `foo` and then that +variable is also live over the `yield` point, so it's stored in both states. + +When the generator starts it'll immediately yield 1, but it saves off its state +just before it does so indicating that it has reached the yield point. Upon +resuming again we'll execute the `return ret` which returns the `Complete` +state. + +Here we can also note that the `Done` state, if resumed, panics immediately as +it's invalid to resume a completed generator. It's also worth noting that this +is just a rough desugaring, not a normative specification for what the compiler +does. diff --git a/src/libcore/ops/generator.rs b/src/libcore/ops/generator.rs index 1e54eaaaa280e..4d125573afce7 100644 --- a/src/libcore/ops/generator.rs +++ b/src/libcore/ops/generator.rs @@ -9,33 +9,117 @@ // except according to those terms. /// The result of a generator resumption. +/// +/// This enum is returned from the `Generator::resume` method and indicates the +/// possible return values of a generator. Currently this corresponds to either +/// a suspension point (`Yielded`) or a termination point (`Complete`). #[derive(Debug)] #[cfg_attr(not(stage0), lang = "generator_state")] -#[unstable(feature = "generator_trait", issue = "0")] +#[unstable(feature = "generator_trait", issue = "43122")] pub enum State { /// The generator suspended with a value. + /// + /// This state indicates that a generator has been suspended, and typically + /// corresponds to a `yield` statement. The value provided in this variant + /// corresponds to the expression passed to `yield` and allows generators to + /// provide a value each time they yield. Yielded(Y), /// The generator completed with a return value. + /// + /// This state indicates that a generator has finished execution with the + /// provided value. Once a generator has returned `Complete` it is + /// considered a programmer error to call `resume` again. Complete(R), } /// The trait implemented by builtin generator types. +/// +/// Generators, also commonly referred to as coroutines, are currently an +/// experimental language feature in Rust. Added in [RFC 2033] generators are +/// currently intended to primarily provide a building block for async/await +/// syntax but will likely extend to also providing an ergonomic definition for +/// iterators and other primitives. +/// +/// The syntax and semantics for generators is unstable and will require a +/// further RFC for stabilization. At this time, though, the syntax is +/// closure-like: +/// +/// ```rust +/// #![feature(generators, generator_trait)] +/// +/// use std::ops::{Generator, State}; +/// +/// fn main() { +/// let mut generator = || { +/// yield 1; +/// return "foo" +/// }; +/// +/// match generator.resume(()) { +/// State::Yielded(1) => {} +/// _ => panic!("unexpected return from resume"), +/// } +/// match generator.resume(()) { +/// State::Complete("foo") => {} +/// _ => panic!("unexpected return from resume"), +/// } +/// } +/// ``` +/// +/// More documentation of generators can be found in the unstable book. +/// +/// [RFC 2033]: https://github.com/rust-lang/rfcs/pull/2033 #[cfg_attr(not(stage0), lang = "generator")] -#[unstable(feature = "generator_trait", issue = "0")] +#[unstable(feature = "generator_trait", issue = "43122")] #[fundamental] pub trait Generator { /// The type of value this generator yields. + /// + /// This associated type corresponds to the `yield` expression and the + /// values which are allowed to be returned each time a generator yields. + /// For example an iterator-as-a-generator would likely have this type as + /// `T`, the type being iterated over. type Yield; /// The type of value this generator returns. + /// + /// This corresponds to the type returned from a generator either with a + /// `return` statement or implicitly as the last expression of a generator + /// literal. For example futures would use this as `Result` as it + /// represents a completed future. type Return; - /// This resumes the execution of the generator. + /// Resumes the execution of this generator. + /// + /// This function will resume execution of the generator or start execution + /// if it hasn't already. This call will return back into the generator's + /// last suspension point, resuming execution from the latest `yield`. The + /// generator will continue executing until it either yields or returns, at + /// which point this function will return. + /// + /// # Return value + /// + /// The `State` enum returned from this function indicates what state the + /// generator is in upon returning. If the `Yielded` variant is returned + /// then the generator has reached a suspension point and a value has been + /// yielded out. Generators in this state are available for resumption at a + /// later point. + /// + /// If `Complete` is returned then the generator has completely finished + /// with the value provided. It is invalid for the generator to be resumed + /// again. + /// + /// # Panics + /// + /// This function may panic if it is called after the `Complete` variant has + /// been returned previously. While generator literals in the language are + /// guaranteed to panic on resuming after `Complete`, this is not guaranteed + /// for all implementations of the `Generator` trait. fn resume(&mut self, arg: Arg) -> State; } -#[unstable(feature = "generator_trait", issue = "0")] +#[unstable(feature = "generator_trait", issue = "43122")] impl<'a, T, U> Generator for &'a mut T where T: Generator + ?Sized { From facabcb85ef4e49ecc83ca942c38ade3dd70a5cf Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 10 Jul 2017 09:33:54 -0700 Subject: [PATCH 011/113] Fill in generator tracking issue in a few more locations --- src/liballoc/boxed.rs | 2 +- src/libcore/ops/mod.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index 079a525f95126..eae8da8dab919 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -785,7 +785,7 @@ impl AsMut for Box { } } -#[unstable(feature = "generator_trait", issue = "0")] +#[unstable(feature = "generator_trait", issue = "43122")] impl Generator for Box where T: Generator + ?Sized { diff --git a/src/libcore/ops/mod.rs b/src/libcore/ops/mod.rs index a51b19110280e..0f415a60c807a 100644 --- a/src/libcore/ops/mod.rs +++ b/src/libcore/ops/mod.rs @@ -190,7 +190,7 @@ pub use self::range::{RangeInclusive, RangeToInclusive}; #[unstable(feature = "try_trait", issue = "42327")] pub use self::try::Try; -#[unstable(feature = "generator_trait", issue = "0")] +#[unstable(feature = "generator_trait", issue = "43122")] pub use self::generator::{Generator, State}; #[unstable(feature = "placement_new_protocol", issue = "27779")] From 075fd364d06d89f5cd79308938e3ed4a5893ec84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Mon, 10 Jul 2017 20:04:15 +0200 Subject: [PATCH 012/113] Ensure upvars are dropped when generators have never been resumed --- src/librustc_mir/transform/generator.rs | 158 +++++++++++++----- .../generator/no-arguments-on-generators.rs | 2 +- src/test/run-pass/generator/drop-env.rs | 6 +- 3 files changed, 118 insertions(+), 48 deletions(-) diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs index 5e33eb95d403f..a2c1cf415974d 100644 --- a/src/librustc_mir/transform/generator.rs +++ b/src/librustc_mir/transform/generator.rs @@ -83,7 +83,7 @@ impl<'tcx> MutVisitor<'tcx> for DerefArgVisitor { lvalue: &mut Lvalue<'tcx>, context: LvalueContext<'tcx>, location: Location) { - if *lvalue == Lvalue::Local(Local::new(2)) { + if *lvalue == Lvalue::Local(Local::new(1)) { *lvalue = Lvalue::Projection(Box::new(Projection { base: lvalue.clone(), elem: ProjectionElem::Deref, @@ -114,10 +114,6 @@ impl<'a, 'tcx> TransformVisitor<'a, 'tcx> { fn make_field(&self, idx: usize, ty: Ty<'tcx>) -> Lvalue<'tcx> { let base = Lvalue::Local(Local::new(1)); - let base = Lvalue::Projection(Box::new(Projection { - base: base, - elem: ProjectionElem::Deref, - })); let field = Projection { base: base, elem: ProjectionElem::Field(Field::new(idx), ty), @@ -258,6 +254,23 @@ fn ensure_generator_state_argument<'a, 'tcx>( let gen_ty = mir.local_decls.raw[2].ty; + // Swap generator and implicit argument + SwapLocalVisitor { + a: Local::new(1), + b: Local::new(2), + }.visit_mir(mir); + + mir.local_decls.raw[..].swap(1, 2); + + (gen_ty, interior) +} + +fn make_generator_state_argument_indirect<'a, 'tcx>( + tcx: TyCtxt<'a, 'tcx, 'tcx>, + def_id: DefId, + mir: &mut Mir<'tcx>) { + let gen_ty = mir.local_decls.raw[1].ty; + let region = ty::ReFree(ty::FreeRegion { scope: def_id, bound_region: ty::BoundRegion::BrEnv, @@ -271,20 +284,10 @@ fn ensure_generator_state_argument<'a, 'tcx>( }); // Replace the by value generator argument - mir.local_decls.raw[2].ty = ref_gen_ty; + mir.local_decls.raw[1].ty = ref_gen_ty; - // Add a deref to accesses of the generator state for upvars + // Add a deref to accesses of the generator state DerefArgVisitor.visit_mir(mir); - - // Swap generator and implicit argument - SwapLocalVisitor { - a: Local::new(1), - b: Local::new(2), - }.visit_mir(mir); - - mir.local_decls.raw[..].swap(1, 2); - - (gen_ty, interior) } fn replace_result_variable<'tcx>(ret_ty: Ty<'tcx>, @@ -412,7 +415,7 @@ fn elaborate_generator_drops<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, use shim::DropShimElaborator; let param_env = tcx.param_env(def_id); - let gen = Local::new(2); + let gen = Local::new(1); for block in mir.basic_blocks().indices() { let (target, unwind, source_info) = match mir.basic_blocks()[block].terminator() { @@ -460,12 +463,14 @@ fn generate_drop<'a, 'tcx>( def_id: DefId, source: MirSource, gen_ty: Ty<'tcx>, - mir: &mut Mir<'tcx>) { + mir: &mut Mir<'tcx>, + drop_clean: BasicBlock) { let source_info = SourceInfo { span: mir.span, scope: ARGUMENT_VISIBILITY_SCOPE, }; + let return_block = BasicBlock::new(mir.basic_blocks().len()); mir.basic_blocks_mut().push(BasicBlockData { statements: Vec::new(), terminator: Some(Terminator { @@ -475,10 +480,12 @@ fn generate_drop<'a, 'tcx>( is_cleanup: false, }); - let cases: Vec<_> = transform.bb_targets.iter().filter_map(|(&(r, u), &s)| { + let mut cases: Vec<_> = transform.bb_targets.iter().filter_map(|(&(r, u), &s)| { u.map(|d| (s, d)) }).collect(); + cases.insert(0, (0, drop_clean)); + // The poisoned state 1 falls through to the default case which is just to return let switch = TerminatorKind::SwitchInt { @@ -487,7 +494,7 @@ fn generate_drop<'a, 'tcx>( values: Cow::from(cases.iter().map(|&(i, _)| { ConstInt::U32(i) }).collect::>()), - targets: cases.iter().map(|&(_, d)| d).chain(once(transform.return_block)).collect(), + targets: cases.iter().map(|&(_, d)| d).chain(once(return_block)).collect(), }; insert_entry_point(mir, BasicBlockData { @@ -525,6 +532,8 @@ fn generate_drop<'a, 'tcx>( is_user_variable: false, }; + make_generator_state_argument_indirect(tcx, def_id, mir); + // Change the generator argument from &mut to *mut mir.local_decls[Local::new(1)] = LocalDecl { mutability: Mutability::Mut, @@ -544,21 +553,9 @@ fn generate_drop<'a, 'tcx>( dump_mir(tcx, None, "generator_drop", &0, source, mir); } -fn generate_resume<'a, 'tcx>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, - mut transform: TransformVisitor<'a, 'tcx>, - node_id: NodeId, - def_id: DefId, - source: MirSource, - mir: &mut Mir<'tcx>) { - // Poison the generator when it unwinds - for block in mir.basic_blocks_mut() { - let source_info = block.terminator().source_info; - if let &TerminatorKind::Resume = &block.terminator().kind { - block.statements.push(transform.set_state(1, source_info)); - } - } - +fn insert_resume_after_return<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + def_id: DefId, + mir: &mut Mir<'tcx>) -> Option { let drop_arg = mir.local_decls.raw[2].ty.needs_drop(tcx, tcx.param_env(def_id)); let cleanup = if drop_arg { @@ -567,6 +564,7 @@ fn generate_resume<'a, 'tcx>( None }; + let assert_block = BasicBlock::new(mir.basic_blocks().len()); let term = TerminatorKind::Assert { cond: Operand::Constant(box Constant { span: mir.span, @@ -577,7 +575,7 @@ fn generate_resume<'a, 'tcx>( }), expected: true, msg: AssertMessage::GeneratorResumedAfterReturn, - target: transform.return_block, + target: assert_block, cleanup: cleanup, }; @@ -623,6 +621,30 @@ fn generate_resume<'a, 'tcx>( }); } + cleanup +} + +fn generate_resume<'a, 'tcx>( + tcx: TyCtxt<'a, 'tcx, 'tcx>, + mut transform: TransformVisitor<'a, 'tcx>, + node_id: NodeId, + def_id: DefId, + source: MirSource, + cleanup: Option, + mir: &mut Mir<'tcx>) { + // Poison the generator when it unwinds + for block in mir.basic_blocks_mut() { + let source_info = block.terminator().source_info; + if let &TerminatorKind::Resume = &block.terminator().kind { + block.statements.push(transform.set_state(1, source_info)); + } + } + + let source_info = SourceInfo { + span: mir.span, + scope: ARGUMENT_VISIBILITY_SCOPE, + }; + let poisoned_block = BasicBlock::new(mir.basic_blocks().len()); let term = TerminatorKind::Assert { @@ -671,6 +693,8 @@ fn generate_resume<'a, 'tcx>( is_cleanup: false, }); + make_generator_state_argument_indirect(tcx, def_id, mir); + // Make sure we remove dead blocks to remove // unrelated code from the drop part of the function simplify::remove_dead_blocks(mir); @@ -678,6 +702,41 @@ fn generate_resume<'a, 'tcx>( dump_mir(tcx, None, "generator_resume", &0, source, mir); } +fn insert_clean_drop<'a, 'tcx>(mir: &mut Mir<'tcx>) -> (BasicBlock, BasicBlock) { + let source_info = SourceInfo { + span: mir.span, + scope: ARGUMENT_VISIBILITY_SCOPE, + }; + + let return_block = BasicBlock::new(mir.basic_blocks().len()); + mir.basic_blocks_mut().push(BasicBlockData { + statements: Vec::new(), + terminator: Some(Terminator { + source_info, + kind: TerminatorKind::Return, + }), + is_cleanup: false, + }); + + // Create a block to destroy an unresumed generators. This can only destroy upvars. + let drop_clean = BasicBlock::new(mir.basic_blocks().len()); + let term = TerminatorKind::Drop { + location: Lvalue::Local(Local::new(1)), + target: return_block, + unwind: None, + }; + mir.basic_blocks_mut().push(BasicBlockData { + statements: Vec::new(), + terminator: Some(Terminator { + source_info, + kind: term, + }), + is_cleanup: false, + }); + + (return_block, drop_clean) +} + impl MirPass for StateTransform { fn run_pass<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, @@ -695,8 +754,6 @@ impl MirPass for StateTransform { let node_id = source.item_id(); let def_id = tcx.hir.local_def_id(source.item_id()); - elaborate_generator_drops(tcx, def_id, mir); - let (gen_ty, interior) = ensure_generator_state_argument(tcx, node_id, def_id, mir); let state_did = tcx.lang_items.gen_state().unwrap(); @@ -709,7 +766,7 @@ impl MirPass for StateTransform { let (remap, layout) = compute_layout(tcx, def_id, source, interior, mir); - let return_block = BasicBlock::new(mir.basic_blocks().len()); + let tail_block = BasicBlock::new(mir.basic_blocks().len()); let state_field = mir.upvar_decls.len(); @@ -724,7 +781,7 @@ impl MirPass for StateTransform { bb_target_count: 2, bb_targets, new_ret_local, - return_block, + return_block: tail_block, state_field, }; transform.visit_mir(mir); @@ -735,14 +792,29 @@ impl MirPass for StateTransform { mir.spread_arg = None; mir.generator_layout = Some(layout); + let arg_cleanup = insert_resume_after_return(tcx, def_id, mir); + + let (_return_block, drop_clean) = insert_clean_drop(mir); + + dump_mir(tcx, None, "generator_pre-elab", &0, source, mir); + + elaborate_generator_drops(tcx, def_id, mir); + dump_mir(tcx, None, "generator_post-transform", &0, source, mir); let mut drop_impl = mir.clone(); - generate_drop(tcx, &transform, node_id, def_id, source, gen_ty, &mut drop_impl); + generate_drop(tcx, + &transform, + node_id, + def_id, + source, + gen_ty, + &mut drop_impl, + drop_clean); mir.generator_drop = Some(box drop_impl); - generate_resume(tcx, transform, node_id, def_id, source, mir); + generate_resume(tcx, transform, node_id, def_id, source, arg_cleanup, mir); } } diff --git a/src/test/compile-fail/generator/no-arguments-on-generators.rs b/src/test/compile-fail/generator/no-arguments-on-generators.rs index 9c68fe4ceda80..0f8d29e5cabb7 100644 --- a/src/test/compile-fail/generator/no-arguments-on-generators.rs +++ b/src/test/compile-fail/generator/no-arguments-on-generators.rs @@ -13,5 +13,5 @@ fn main() { let gen = |start| { //~ ERROR generators cannot have explicit arguments yield; - }; + }; } \ No newline at end of file diff --git a/src/test/run-pass/generator/drop-env.rs b/src/test/run-pass/generator/drop-env.rs index 43d0af7a07348..1b0df6f87236e 100644 --- a/src/test/run-pass/generator/drop-env.rs +++ b/src/test/run-pass/generator/drop-env.rs @@ -58,7 +58,7 @@ fn t2() { fn t3() { let b = B; - let mut foo = || { + let foo = || { let _: () = gen arg; // TODO: this line should not be necessary yield; drop(b); @@ -67,7 +67,5 @@ fn t3() { let n = A.load(Ordering::SeqCst); assert_eq!(A.load(Ordering::SeqCst), n); drop(foo); - // TODO: we should assert n+1 here, not n - // assert_eq!(A.load(Ordering::SeqCst), n + 1); - assert_eq!(A.load(Ordering::SeqCst), n); + assert_eq!(A.load(Ordering::SeqCst), n + 1); } From 057b0adf47f61d9e9dd8c23fff6dac742e001f36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Mon, 10 Jul 2017 20:06:39 +0200 Subject: [PATCH 013/113] Don't print `gen` in HIR --- src/librustc/hir/print.rs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs index 272e442cfcd29..b076fb7ff8122 100644 --- a/src/librustc/hir/print.rs +++ b/src/librustc/hir/print.rs @@ -1312,12 +1312,7 @@ impl<'a> State<'a> { } self.bclose_(expr.span, indent_unit)?; } - hir::ExprClosure(capture_clause, ref decl, body, _fn_decl_span, gen) => { - if gen.is_some() { - self.head("gen")?; - space(&mut self.s)?; - } - + hir::ExprClosure(capture_clause, ref decl, body, _fn_decl_span, _gen) => { self.print_capture_clause(capture_clause)?; self.print_closure_args(&decl, body)?; From 66fc6dfbb6dd947426951aac0ed01ff9afed391a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Mon, 10 Jul 2017 20:25:32 +0200 Subject: [PATCH 014/113] Update error codes --- src/librustc_borrowck/borrowck/gather_loans/mod.rs | 4 ++-- src/librustc_borrowck/diagnostics.rs | 4 ++-- src/librustc_typeck/check/mod.rs | 4 ++-- src/librustc_typeck/diagnostics.rs | 6 ++---- 4 files changed, 8 insertions(+), 10 deletions(-) diff --git a/src/librustc_borrowck/borrowck/gather_loans/mod.rs b/src/librustc_borrowck/borrowck/gather_loans/mod.rs index cd0b19980957a..bcfc9db56fcc7 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/mod.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/mod.rs @@ -148,7 +148,7 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for GatherLoanCtxt<'a, 'tcx> { if borrows_impl_arg { span_err!(self.bccx.tcx.sess, borrow_span, - E0805, + E0623, "cannot borrow the implicit argument of a generator"); } @@ -226,7 +226,7 @@ fn check_yields<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, if extent_has_yield(bccx.tcx, extent) { span_err!(bccx.tcx.sess, borrow_span, - E0806, + E0624, "cannot borrow this value across the suspend point of a generator"); } } diff --git a/src/librustc_borrowck/diagnostics.rs b/src/librustc_borrowck/diagnostics.rs index 415b633a623a2..2ae9498d63cfd 100644 --- a/src/librustc_borrowck/diagnostics.rs +++ b/src/librustc_borrowck/diagnostics.rs @@ -1191,6 +1191,6 @@ register_diagnostics! { E0594, // cannot assign to {} E0595, // closure cannot assign to {} E0598, // lifetime of {} is too short to guarantee its contents can be... - E0805, // borrow of the implicit argument of a generator - E0806, // borrow across a suspend point + E0623, // borrow of the implicit argument of a generator + E0624, // borrow across a suspend point } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 1d1631c4fa7e7..40693d4d0ea70 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -4002,7 +4002,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { ty } None => { - struct_span_err!(self.tcx.sess, expr.span, E0803, + struct_span_err!(self.tcx.sess, expr.span, E0626, "gen arg expression outside of generator literal").emit(); tcx.types.err } @@ -4014,7 +4014,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.check_expr_coercable_to_type(&value, ty); } None => { - struct_span_err!(self.tcx.sess, expr.span, E0802, + struct_span_err!(self.tcx.sess, expr.span, E0625, "yield statement outside of generator literal").emit(); } } diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index 0463f82ccce25..45ae8df387b0f 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -4667,8 +4667,6 @@ register_diagnostics! { E0588, // packed struct cannot transitively contain a `[repr(align)]` struct E0592, // duplicate definitions with name `{}` // E0613, // Removed (merged with E0609) - E0801, // unexpected generator return - E0802, // yield statement outside of generator literal - E0803, // gen arg expression outside of generator literal - E0804, // cannot determine the type for the implicit argument of this generator + E0625, // yield statement outside of generator literal + E0626, // gen arg expression outside of generator literal } From df608e710c3f592574d3dfa0d2f8402aa4d33dcb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Mon, 10 Jul 2017 21:11:31 +0200 Subject: [PATCH 015/113] Rename suspend to yield --- src/librustc/cfg/construct.rs | 2 +- src/librustc/hir/intravisit.rs | 2 +- src/librustc/hir/lowering.rs | 2 +- src/librustc/hir/mod.rs | 4 +-- src/librustc/hir/print.rs | 4 +-- src/librustc/ich/impls_hir.rs | 4 +-- src/librustc/ich/impls_mir.rs | 4 +-- src/librustc/ich/impls_ty.rs | 2 +- src/librustc/middle/expr_use_visitor.rs | 2 +- src/librustc/middle/liveness.rs | 6 ++-- src/librustc/middle/mem_categorization.rs | 2 +- src/librustc/middle/region.rs | 2 +- src/librustc/mir/mod.rs | 34 +++++++++---------- src/librustc/mir/visit.rs | 2 +- src/librustc/traits/project.rs | 4 +-- src/librustc/traits/util.rs | 2 +- src/librustc/ty/mod.rs | 2 +- src/librustc/ty/structural_impls.rs | 10 +++--- src/librustc/ty/sty.rs | 6 ++-- src/librustc_mir/build/expr/as_lvalue.rs | 2 +- src/librustc_mir/build/expr/as_rvalue.rs | 4 +-- src/librustc_mir/build/expr/category.rs | 2 +- src/librustc_mir/build/expr/into.rs | 2 +- src/librustc_mir/build/mod.rs | 14 ++++---- .../dataflow/drop_flag_effects.rs | 2 +- src/librustc_mir/dataflow/mod.rs | 4 +-- src/librustc_mir/dataflow/move_paths/mod.rs | 2 +- src/librustc_mir/hair/cx/expr.rs | 2 +- src/librustc_mir/hair/mod.rs | 2 +- src/librustc_mir/transform/elaborate_drops.rs | 4 +-- src/librustc_mir/transform/generator.rs | 12 +++---- src/librustc_mir/transform/inline.rs | 4 +-- src/librustc_mir/transform/no_landing_pads.rs | 2 +- src/librustc_mir/transform/qualify_consts.rs | 2 +- src/librustc_mir/transform/type_check.rs | 12 +++---- src/librustc_passes/consts.rs | 2 +- src/librustc_passes/mir_stats.rs | 2 +- src/librustc_trans/collector.rs | 2 +- src/librustc_trans/common.rs | 2 +- src/librustc_trans/mir/analyze.rs | 2 +- src/librustc_trans/mir/block.rs | 2 +- src/librustc_typeck/check/mod.rs | 12 +++---- src/librustc_typeck/check/writeback.rs | 2 +- 43 files changed, 97 insertions(+), 97 deletions(-) diff --git a/src/librustc/cfg/construct.rs b/src/librustc/cfg/construct.rs index 36aeaba0c5ec6..fb205655df29c 100644 --- a/src/librustc/cfg/construct.rs +++ b/src/librustc/cfg/construct.rs @@ -389,7 +389,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { hir::ExprUnary(_, ref e) | hir::ExprField(ref e, _) | hir::ExprTupField(ref e, _) | - hir::ExprSuspend(ref e) | + hir::ExprYield(ref e) | hir::ExprRepeat(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 47a0f67a64074..9e4117033724f 100644 --- a/src/librustc/hir/intravisit.rs +++ b/src/librustc/hir/intravisit.rs @@ -1045,7 +1045,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) { visitor.visit_expr(input) } } - ExprSuspend(ref subexpression) => { + ExprYield(ref subexpression) => { visitor.visit_expr(subexpression); } ExprImplArg(id) => { diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 50c8763600fa5..3aa7149933cba 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -2108,7 +2108,7 @@ impl<'a> LoweringContext<'a> { let expr = opt_expr.as_ref().map(|x| self.lower_expr(x)).unwrap_or_else(|| { self.expr(e.span, hir::ExprTup(hir_vec![]), ThinVec::new()) }); - hir::ExprSuspend(P(expr)) + hir::ExprYield(P(expr)) } ExprKind::ImplArg => { diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 28d5cf2472d7a..40a745bcebfb3 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -1069,8 +1069,8 @@ pub enum Expr_ { /// to be repeated; the second is the number of times to repeat it. ExprRepeat(P, BodyId), - /// A suspension point for generators - ExprSuspend(P), + /// A suspension point for generators. This is `yield ` in Rust. + ExprYield(P), /// The argument to a generator ExprImplArg(NodeId), diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs index b076fb7ff8122..d513719146282 100644 --- a/src/librustc/hir/print.rs +++ b/src/librustc/hir/print.rs @@ -1461,8 +1461,8 @@ impl<'a> State<'a> { self.pclose()?; } - hir::ExprSuspend(ref expr) => { - word(&mut self.s, "suspend ")?; + hir::ExprYield(ref expr) => { + word(&mut self.s, "yield ")?; self.print_expr(&expr)?; } hir::ExprImplArg(_) => { diff --git a/src/librustc/ich/impls_hir.rs b/src/librustc/ich/impls_hir.rs index d2cc186bad433..39fa0cb44d09d 100644 --- a/src/librustc/ich/impls_hir.rs +++ b/src/librustc/ich/impls_hir.rs @@ -573,7 +573,7 @@ impl<'a, 'gcx, 'tcx> HashStable> for hir::E hir::ExprBreak(..) | hir::ExprAgain(..) | hir::ExprRet(..) | - hir::ExprSuspend(..) | + hir::ExprYield(..) | hir::ExprImplArg(..) | hir::ExprInlineAsm(..) | hir::ExprRepeat(..) | @@ -654,7 +654,7 @@ impl_stable_hash_for!(enum hir::Expr_ { ExprInlineAsm(asm, inputs, outputs), ExprStruct(path, fields, base), ExprRepeat(val, times), - ExprSuspend(val), + ExprYield(val), ExprImplArg(id) }); diff --git a/src/librustc/ich/impls_mir.rs b/src/librustc/ich/impls_mir.rs index d273c6c9c42f1..63100f4c11a2c 100644 --- a/src/librustc/ich/impls_mir.rs +++ b/src/librustc/ich/impls_mir.rs @@ -58,7 +58,7 @@ for mir::Terminator<'tcx> { mir::TerminatorKind::Unreachable | mir::TerminatorKind::Drop { .. } | mir::TerminatorKind::DropAndReplace { .. } | - mir::TerminatorKind::Suspend { .. } | + mir::TerminatorKind::Yield { .. } | mir::TerminatorKind::Call { .. } => false, }; @@ -164,7 +164,7 @@ for mir::TerminatorKind<'tcx> { target.hash_stable(hcx, hasher); unwind.hash_stable(hcx, hasher); } - mir::TerminatorKind::Suspend { ref value, + mir::TerminatorKind::Yield { ref value, resume, drop } => { value.hash_stable(hcx, hasher); diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index 22f202a35ecf7..29f201f84c995 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -144,7 +144,7 @@ for ty::UpvarCapture<'tcx> { impl_stable_hash_for!(struct ty::GenSig<'tcx> { impl_arg_ty, - suspend_ty, + yield_ty, return_ty }); diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 945b612027b9e..1154c82cd2edf 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -525,7 +525,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { self.consume_expr(&base); } - hir::ExprSuspend(ref value) => { + hir::ExprYield(ref value) => { self.consume_expr(&value); } diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index 1487ae5908e5d..98e742c694e9f 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -470,7 +470,7 @@ fn visit_expr<'a, 'tcx>(ir: &mut IrMaps<'a, 'tcx>, expr: &'tcx Expr) { hir::ExprAgain(_) | hir::ExprLit(_) | hir::ExprRet(..) | hir::ExprBlock(..) | hir::ExprAssign(..) | hir::ExprAssignOp(..) | hir::ExprStruct(..) | hir::ExprRepeat(..) | - hir::ExprInlineAsm(..) | hir::ExprBox(..) | hir::ExprSuspend(..) | + hir::ExprInlineAsm(..) | hir::ExprBox(..) | hir::ExprYield(..) | hir::ExprType(..) | hir::ExprPath(hir::QPath::TypeRelative(..)) => { intravisit::walk_expr(ir, expr); } @@ -1129,7 +1129,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { hir::ExprCast(ref e, _) | hir::ExprType(ref e, _) | hir::ExprUnary(_, ref e) | - hir::ExprSuspend(ref e) | + hir::ExprYield(ref e) | hir::ExprRepeat(ref e, _) => { self.propagate_through_expr(&e, succ) } @@ -1420,7 +1420,7 @@ fn check_expr<'a, 'tcx>(this: &mut Liveness<'a, 'tcx>, expr: &'tcx Expr) { hir::ExprBreak(..) | hir::ExprAgain(..) | hir::ExprLit(_) | hir::ExprBlock(..) | hir::ExprAddrOf(..) | hir::ExprStruct(..) | hir::ExprRepeat(..) | hir::ExprImplArg(_) | - hir::ExprClosure(..) | hir::ExprPath(_) | hir::ExprSuspend(..) | + hir::ExprClosure(..) | hir::ExprPath(_) | hir::ExprYield(..) | hir::ExprBox(..) | hir::ExprType(..) => { intravisit::walk_expr(this, expr); } diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index bf5263e75da28..92883ca1b11ae 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -620,7 +620,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { hir::ExprAddrOf(..) | hir::ExprCall(..) | hir::ExprAssign(..) | hir::ExprAssignOp(..) | hir::ExprClosure(..) | hir::ExprRet(..) | - hir::ExprUnary(..) | hir::ExprSuspend(..) | + hir::ExprUnary(..) | hir::ExprYield(..) | hir::ExprMethodCall(..) | hir::ExprCast(..) | hir::ExprArray(..) | hir::ExprTup(..) | hir::ExprIf(..) | hir::ExprBinary(..) | hir::ExprWhile(..) | diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index 2d0269e5845fa..b8b8476d54b46 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -1158,7 +1158,7 @@ impl<'tcx> Visitor<'tcx> for YieldFinder { } fn visit_expr(&mut self, expr: &'tcx hir::Expr) { - if let hir::ExprSuspend(..) = expr.node { + if let hir::ExprYield(..) = expr.node { self.0 = true; } diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index 9bfd7f175c275..2c500aa9c6fe9 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -104,8 +104,8 @@ pub struct Mir<'tcx> { /// Return type of the function. pub return_ty: Ty<'tcx>, - /// Suspend type of the function, if it is a generator. - pub suspend_ty: Option>, + /// Yield type of the function, if it is a generator. + pub yield_ty: Option>, /// Generator drop glue pub generator_drop: Option>>, @@ -153,7 +153,7 @@ impl<'tcx> Mir<'tcx> { visibility_scopes: IndexVec, promoted: IndexVec>, return_ty: Ty<'tcx>, - suspend_ty: Option>, + yield_ty: Option>, local_decls: IndexVec>, arg_count: usize, upvar_decls: Vec, @@ -169,7 +169,7 @@ impl<'tcx> Mir<'tcx> { visibility_scopes, promoted, return_ty, - suspend_ty, + yield_ty, generator_drop: None, generator_layout: None, local_decls, @@ -287,7 +287,7 @@ impl_stable_hash_for!(struct Mir<'tcx> { visibility_scopes, promoted, return_ty, - suspend_ty, + yield_ty, generator_drop, generator_layout, local_decls, @@ -590,7 +590,7 @@ pub enum TerminatorKind<'tcx> { }, /// A suspend point - Suspend { + Yield { /// The value to return value: Operand<'tcx>, /// Where to resume to @@ -638,8 +638,8 @@ impl<'tcx> TerminatorKind<'tcx> { slice::ref_slice(t).into_cow(), Call { destination: None, cleanup: Some(ref c), .. } => slice::ref_slice(c).into_cow(), Call { destination: None, cleanup: None, .. } => (&[]).into_cow(), - Suspend { resume: t, drop: Some(c), .. } => vec![t, c].into_cow(), - Suspend { resume: ref t, drop: None, .. } => slice::ref_slice(t).into_cow(), + Yield { resume: t, drop: Some(c), .. } => vec![t, c].into_cow(), + Yield { resume: ref t, drop: None, .. } => slice::ref_slice(t).into_cow(), DropAndReplace { target, unwind: Some(unwind), .. } | Drop { target, unwind: Some(unwind), .. } => { vec![target, unwind].into_cow() @@ -667,8 +667,8 @@ impl<'tcx> TerminatorKind<'tcx> { Call { destination: Some((_, ref mut t)), cleanup: None, .. } => vec![t], Call { destination: None, cleanup: Some(ref mut c), .. } => vec![c], Call { destination: None, cleanup: None, .. } => vec![], - Suspend { resume: ref mut t, drop: Some(ref mut c), .. } => vec![t, c], - Suspend { resume: ref mut t, drop: None, .. } => vec![t], + Yield { resume: ref mut t, drop: Some(ref mut c), .. } => vec![t, c], + Yield { resume: ref mut t, drop: None, .. } => vec![t], DropAndReplace { ref mut target, unwind: Some(ref mut unwind), .. } | Drop { ref mut target, unwind: Some(ref mut unwind), .. } => vec![target, unwind], DropAndReplace { ref mut target, unwind: None, .. } | @@ -750,7 +750,7 @@ impl<'tcx> TerminatorKind<'tcx> { Return => write!(fmt, "return"), GeneratorDrop => write!(fmt, "generator_drop"), Resume => write!(fmt, "resume"), - Suspend { ref value, .. } => write!(fmt, "_1 = suspend({:?})", value), + Yield { ref value, .. } => write!(fmt, "_1 = suspend({:?})", value), Unreachable => write!(fmt, "unreachable"), Drop { ref location, .. } => write!(fmt, "drop({:?})", location), DropAndReplace { ref location, ref value, .. } => @@ -818,9 +818,9 @@ impl<'tcx> TerminatorKind<'tcx> { Call { destination: Some(_), cleanup: None, .. } => vec!["return".into_cow()], Call { destination: None, cleanup: Some(_), .. } => vec!["unwind".into_cow()], Call { destination: None, cleanup: None, .. } => vec![], - Suspend { drop: Some(_), .. } => + Yield { drop: Some(_), .. } => vec!["resume".into_cow(), "drop".into_cow()], - Suspend { drop: None, .. } => vec!["resume".into_cow()], + Yield { drop: None, .. } => vec!["resume".into_cow()], DropAndReplace { unwind: None, .. } | Drop { unwind: None, .. } => vec!["return".into_cow()], DropAndReplace { unwind: Some(_), .. } | @@ -1526,7 +1526,7 @@ impl<'tcx> TypeFoldable<'tcx> for Mir<'tcx> { visibility_scopes: self.visibility_scopes.clone(), promoted: self.promoted.fold_with(folder), return_ty: self.return_ty.fold_with(folder), - suspend_ty: self.suspend_ty.fold_with(folder), + yield_ty: self.yield_ty.fold_with(folder), generator_drop: self.generator_drop.fold_with(folder), generator_layout: self.generator_layout.fold_with(folder), local_decls: self.local_decls.fold_with(folder), @@ -1542,7 +1542,7 @@ impl<'tcx> TypeFoldable<'tcx> for Mir<'tcx> { self.basic_blocks.visit_with(visitor) || self.generator_drop.visit_with(visitor) || self.generator_layout.visit_with(visitor) || - self.suspend_ty.visit_with(visitor) || + self.yield_ty.visit_with(visitor) || self.promoted.visit_with(visitor) || self.return_ty.visit_with(visitor) || self.local_decls.visit_with(visitor) @@ -1665,7 +1665,7 @@ impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> { target, unwind, }, - Suspend { ref value, resume, drop } => Suspend { + Yield { ref value, resume, drop } => Yield { value: value.fold_with(folder), resume: resume, drop: drop, @@ -1719,7 +1719,7 @@ impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> { Drop { ref location, ..} => location.visit_with(visitor), DropAndReplace { ref location, ref value, ..} => location.visit_with(visitor) || value.visit_with(visitor), - Suspend { ref value, ..} => + Yield { ref value, ..} => value.visit_with(visitor), Call { ref func, ref args, ref destination, .. } => { let dest = if let Some((ref loc, _)) = *destination { diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs index bd162c090f75b..325c87fded61a 100644 --- a/src/librustc/mir/visit.rs +++ b/src/librustc/mir/visit.rs @@ -448,7 +448,7 @@ macro_rules! make_mir_visitor { cleanup.map(|t| self.visit_branch(block, t)); } - TerminatorKind::Suspend { ref $($mutability)* value, + TerminatorKind::Yield { ref $($mutability)* value, resume, drop } => { self.visit_operand(value, source_location); diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs index 35b8b93581551..91d6fac26f1bb 100644 --- a/src/librustc/traits/project.rs +++ b/src/librustc/traits/project.rs @@ -1156,7 +1156,7 @@ fn confirm_generator_candidate<'cx, 'gcx, 'tcx>( let gen_def_id = tcx.lang_items.gen_trait().unwrap(); // Note: we unwrap the binder here but re-create it below (1) - let ty::Binder((trait_ref, suspend_ty, return_ty)) = + let ty::Binder((trait_ref, yield_ty, return_ty)) = tcx.generator_trait_ref_and_outputs(gen_def_id, obligation.predicate.trait_ref.self_ty(), gen_sig); @@ -1165,7 +1165,7 @@ fn confirm_generator_candidate<'cx, 'gcx, 'tcx>( let ty = if name == Symbol::intern("Return") { return_ty } else if name == Symbol::intern("Yield") { - suspend_ty + yield_ty } else { bug!() }; diff --git a/src/librustc/traits/util.rs b/src/librustc/traits/util.rs index dd3c0d66a9cc2..f0b812ff9687d 100644 --- a/src/librustc/traits/util.rs +++ b/src/librustc/traits/util.rs @@ -523,7 +523,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { def_id: fn_trait_def_id, substs: self.mk_substs_trait(self_ty, &[sig.skip_binder().impl_arg_ty]), }; - ty::Binder((trait_ref, sig.skip_binder().suspend_ty, sig.skip_binder().return_ty)) + ty::Binder((trait_ref, sig.skip_binder().yield_ty, sig.skip_binder().return_ty)) } pub fn impl_is_default(self, node_item_def_id: DefId) -> bool { diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index cfcb0c062ad22..21a98bceedff3 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -2030,7 +2030,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { hir::ExprBox(..) | hir::ExprAddrOf(..) | hir::ExprBinary(..) | - hir::ExprSuspend(..) | + hir::ExprYield(..) | hir::ExprCast(..) => { false } diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 2555288962076..c70831cd551cf 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -304,11 +304,11 @@ impl<'a, 'tcx> Lift<'tcx> for ty::adjustment::AutoBorrow<'a> { impl<'a, 'tcx> Lift<'tcx> for ty::GenSig<'a> { type Lifted = ty::GenSig<'tcx>; fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option { - tcx.lift(&(self.impl_arg_ty, self.suspend_ty, self.return_ty)) - .map(|(impl_arg_ty, suspend_ty, return_ty)| { + tcx.lift(&(self.impl_arg_ty, self.yield_ty, self.return_ty)) + .map(|(impl_arg_ty, yield_ty, return_ty)| { ty::GenSig { impl_arg_ty, - suspend_ty, + yield_ty, return_ty, } }) @@ -638,14 +638,14 @@ impl<'tcx> TypeFoldable<'tcx> for ty::GenSig<'tcx> { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { ty::GenSig { impl_arg_ty: self.impl_arg_ty.fold_with(folder), - suspend_ty: self.suspend_ty.fold_with(folder), + yield_ty: self.yield_ty.fold_with(folder), return_ty: self.return_ty.fold_with(folder), } } fn super_visit_with>(&self, visitor: &mut V) -> bool { self.impl_arg_ty.visit_with(visitor) || - self.suspend_ty.visit_with(visitor) || + self.yield_ty.visit_with(visitor) || self.return_ty.visit_with(visitor) } } diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index 7d703ebc8541f..bd5f6a8e26254 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -643,7 +643,7 @@ impl<'a, 'tcx> ProjectionTy<'tcx> { #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] pub struct GenSig<'tcx> { pub impl_arg_ty: Ty<'tcx>, - pub suspend_ty: Ty<'tcx>, + pub yield_ty: Ty<'tcx>, pub return_ty: Ty<'tcx>, } @@ -652,8 +652,8 @@ pub type PolyGenSig<'tcx> = Binder>; #[allow(warnings)] impl<'tcx> PolyGenSig<'tcx> { - pub fn suspend_ty(&self) -> ty::Binder> { - self.map_bound_ref(|sig| sig.suspend_ty) + pub fn yield_ty(&self) -> ty::Binder> { + self.map_bound_ref(|sig| sig.yield_ty) } pub fn return_ty(&self) -> ty::Binder> { self.map_bound_ref(|sig| sig.return_ty) diff --git a/src/librustc_mir/build/expr/as_lvalue.rs b/src/librustc_mir/build/expr/as_lvalue.rs index 78175e0535101..659a5e60364bf 100644 --- a/src/librustc_mir/build/expr/as_lvalue.rs +++ b/src/librustc_mir/build/expr/as_lvalue.rs @@ -121,7 +121,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { ExprKind::Return { .. } | ExprKind::Literal { .. } | ExprKind::InlineAsm { .. } | - ExprKind::Suspend { .. } | + ExprKind::Yield { .. } | ExprKind::Call { .. } => { // these are not lvalues, so we need to make a temporary. debug_assert!(match Category::of(&expr.kind) { diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs index 6af7bd056b4a3..024b1a3483acf 100644 --- a/src/librustc_mir/build/expr/as_rvalue.rs +++ b/src/librustc_mir/build/expr/as_rvalue.rs @@ -239,7 +239,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { block = unpack!(this.stmt_expr(block, expr)); block.and(this.unit_rvalue()) } - ExprKind::Suspend { value } => { + ExprKind::Yield { value } => { let value = unpack!(block = this.as_operand(block, scope, value)); let impl_arg_ty = this.impl_arg_ty.unwrap(); block = unpack!(this.build_drop(block, @@ -248,7 +248,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { impl_arg_ty)); let resume = this.cfg.start_new_block(); let cleanup = this.generator_drop_cleanup(expr_span); - this.cfg.terminate(block, source_info, TerminatorKind::Suspend { + this.cfg.terminate(block, source_info, TerminatorKind::Yield { value: value, resume: resume, drop: cleanup, diff --git a/src/librustc_mir/build/expr/category.rs b/src/librustc_mir/build/expr/category.rs index 0208dbf70349f..7f576666dcdcf 100644 --- a/src/librustc_mir/build/expr/category.rs +++ b/src/librustc_mir/build/expr/category.rs @@ -78,7 +78,7 @@ impl Category { ExprKind::Borrow { .. } | ExprKind::Assign { .. } | ExprKind::AssignOp { .. } | - ExprKind::Suspend { .. } | + ExprKind::Yield { .. } | ExprKind::InlineAsm { .. } => Some(Category::Rvalue(RvalueFunc::AsRvalue)), diff --git a/src/librustc_mir/build/expr/into.rs b/src/librustc_mir/build/expr/into.rs index ee5b04d03be31..ef7533e8d49e7 100644 --- a/src/librustc_mir/build/expr/into.rs +++ b/src/librustc_mir/build/expr/into.rs @@ -284,7 +284,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { ExprKind::Index { .. } | ExprKind::Deref { .. } | ExprKind::Literal { .. } | - ExprKind::Suspend { .. } | + ExprKind::Yield { .. } | ExprKind::ImplArg | ExprKind::Field { .. } => { debug_assert!(match Category::of(&expr.kind).unwrap() { diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index c0bf46dd0fa7c..9a8c43e328638 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -119,14 +119,14 @@ pub fn mir_build<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Mir<'t let arguments = implicit_argument.into_iter().chain(explicit_arguments); - let (suspend_ty, impl_arg_ty, return_ty) = if body.is_generator() { + let (yield_ty, impl_arg_ty, return_ty) = if body.is_generator() { let gen_sig = cx.tables().generator_sigs[&id].clone().unwrap(); - (Some(gen_sig.suspend_ty), Some(gen_sig.impl_arg_ty), gen_sig.return_ty) + (Some(gen_sig.yield_ty), Some(gen_sig.impl_arg_ty), gen_sig.return_ty) } else { (None, None, fn_sig.output()) }; - build::construct_fn(cx, id, arguments, abi, return_ty, suspend_ty, impl_arg_ty, body) + build::construct_fn(cx, id, arguments, abi, return_ty, yield_ty, impl_arg_ty, body) } else { build::construct_const(cx, body_id) }; @@ -342,7 +342,7 @@ fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>, arguments: A, abi: Abi, return_ty: Ty<'gcx>, - suspend_ty: Option>, + yield_ty: Option>, impl_arg_ty: Option>, body: &'gcx hir::Body) -> Mir<'tcx> @@ -411,7 +411,7 @@ fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>, }).collect() }); - let mut mir = builder.finish(upvar_decls, return_ty, suspend_ty); + let mut mir = builder.finish(upvar_decls, return_ty, yield_ty); mir.spread_arg = spread_arg; mir } @@ -487,7 +487,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { fn finish(self, upvar_decls: Vec, return_ty: Ty<'tcx>, - suspend_ty: Option>) + yield_ty: Option>) -> Mir<'tcx> { for (index, block) in self.cfg.basic_blocks.iter().enumerate() { if block.terminator.is_none() { @@ -499,7 +499,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { self.visibility_scopes, IndexVec::new(), return_ty, - suspend_ty, + yield_ty, self.local_decls, self.arg_count, upvar_decls, diff --git a/src/librustc_mir/dataflow/drop_flag_effects.rs b/src/librustc_mir/dataflow/drop_flag_effects.rs index 2f8e932a7382a..0b740e5f02834 100644 --- a/src/librustc_mir/dataflow/drop_flag_effects.rs +++ b/src/librustc_mir/dataflow/drop_flag_effects.rs @@ -299,7 +299,7 @@ pub(crate) fn drop_flag_effects_for_location<'a, 'tcx, F>( move_data.rev_lookup.find(location), |moi| callback(moi, DropFlagState::Present)) } - mir::TerminatorKind::Suspend { .. } => { + mir::TerminatorKind::Yield { .. } => { on_lookup_result_bits(tcx, mir, move_data, move_data.rev_lookup.find(&Mir::impl_arg_lvalue()), |moi| callback(moi, DropFlagState::Present)) diff --git a/src/librustc_mir/dataflow/mod.rs b/src/librustc_mir/dataflow/mod.rs index 6eebe9da9f080..6392bde9eaeb4 100644 --- a/src/librustc_mir/dataflow/mod.rs +++ b/src/librustc_mir/dataflow/mod.rs @@ -456,14 +456,14 @@ impl<'a, 'tcx: 'a, D> DataflowAnalysis<'a, 'tcx, D> mir::TerminatorKind::Unreachable => {} mir::TerminatorKind::Goto { ref target } | mir::TerminatorKind::Assert { ref target, cleanup: None, .. } | - mir::TerminatorKind::Suspend { resume: ref target, drop: None, .. } | + mir::TerminatorKind::Yield { resume: ref target, drop: None, .. } | mir::TerminatorKind::Drop { ref target, location: _, unwind: None } | mir::TerminatorKind::DropAndReplace { ref target, value: _, location: _, unwind: None } => { self.propagate_bits_into_entry_set_for(in_out, changed, target); } - mir::TerminatorKind::Suspend { resume: ref target, drop: Some(ref drop), .. } => { + mir::TerminatorKind::Yield { resume: ref target, drop: Some(ref drop), .. } => { self.propagate_bits_into_entry_set_for(in_out, changed, target); self.propagate_bits_into_entry_set_for(in_out, changed, drop); } diff --git a/src/librustc_mir/dataflow/move_paths/mod.rs b/src/librustc_mir/dataflow/move_paths/mod.rs index cc12ae6abfc14..dba396e813980 100644 --- a/src/librustc_mir/dataflow/move_paths/mod.rs +++ b/src/librustc_mir/dataflow/move_paths/mod.rs @@ -474,7 +474,7 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> { // branching terminators - these don't move anything } - TerminatorKind::Suspend { ref value, .. } => { + TerminatorKind::Yield { ref value, .. } => { self.create_move_path(&Mir::impl_arg_lvalue()); self.gather_operand(loc, value); } diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index ca634ffef5446..4a223ce61f744 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -568,7 +568,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, hir::ExprTup(ref fields) => ExprKind::Tuple { fields: fields.to_ref() }, hir::ExprImplArg(_) => ExprKind::ImplArg, - hir::ExprSuspend(ref v) => ExprKind::Suspend { value: v.to_ref() }, + hir::ExprYield(ref v) => ExprKind::Yield { value: v.to_ref() }, }; Expr { diff --git a/src/librustc_mir/hair/mod.rs b/src/librustc_mir/hair/mod.rs index dece9a974f172..a2e9e5c40f945 100644 --- a/src/librustc_mir/hair/mod.rs +++ b/src/librustc_mir/hair/mod.rs @@ -250,7 +250,7 @@ pub enum ExprKind<'tcx> { inputs: Vec> }, ImplArg, - Suspend { + Yield { value: ExprRef<'tcx>, }, } diff --git a/src/librustc_mir/transform/elaborate_drops.rs b/src/librustc_mir/transform/elaborate_drops.rs index 387d769e01f67..472623ec20ab3 100644 --- a/src/librustc_mir/transform/elaborate_drops.rs +++ b/src/librustc_mir/transform/elaborate_drops.rs @@ -100,7 +100,7 @@ fn find_dead_unwinds<'a, 'tcx>( let location = match bb_data.terminator().kind { TerminatorKind::Drop { ref location, unwind: Some(_), .. } | TerminatorKind::DropAndReplace { ref location, unwind: Some(_), .. } => location, - TerminatorKind::Suspend { .. } => &impl_arg, + TerminatorKind::Yield { .. } => &impl_arg, _ => continue, }; @@ -348,7 +348,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { let location = match terminator.kind { TerminatorKind::Drop { ref location, .. } | TerminatorKind::DropAndReplace { ref location, .. } => location, - TerminatorKind::Suspend { .. } => &impl_arg, + TerminatorKind::Yield { .. } => &impl_arg, _ => continue }; diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs index a2c1cf415974d..fc5834d605332 100644 --- a/src/librustc_mir/transform/generator.rs +++ b/src/librustc_mir/transform/generator.rs @@ -159,7 +159,7 @@ impl<'a, 'tcx> MutVisitor<'tcx> for TransformVisitor<'a, 'tcx> { self.return_block, Operand::Consume(Lvalue::Local(self.new_ret_local)), None)), - TerminatorKind::Suspend { ref value, resume, drop } => Some((0, + TerminatorKind::Yield { ref value, resume, drop } => Some((0, resume, value.clone(), drop)), @@ -325,7 +325,7 @@ fn locals_live_across_suspend_points<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, liveness::dump_mir(tcx, "generator_liveness", source, mir, &result); for (block, data) in mir.basic_blocks().iter_enumerated() { - if let TerminatorKind::Suspend { .. } = data.terminator().kind { + if let TerminatorKind::Yield { .. } = data.terminator().kind { set.union(&result.outs[block]); } } @@ -742,8 +742,8 @@ impl MirPass for StateTransform { tcx: TyCtxt<'a, 'tcx, 'tcx>, source: MirSource, mir: &mut Mir<'tcx>) { - let suspend_ty = if let Some(suspend_ty) = mir.suspend_ty { - suspend_ty + let yield_ty = if let Some(yield_ty) = mir.yield_ty { + yield_ty } else { // This only applies to generators return @@ -758,7 +758,7 @@ impl MirPass for StateTransform { let state_did = tcx.lang_items.gen_state().unwrap(); let state_adt_ref = tcx.adt_def(state_did); - let state_substs = tcx.mk_substs([Kind::from(suspend_ty), + let state_substs = tcx.mk_substs([Kind::from(yield_ty), Kind::from(mir.return_ty)].iter()); let ret_ty = tcx.mk_adt(state_adt_ref, state_substs); @@ -787,7 +787,7 @@ impl MirPass for StateTransform { transform.visit_mir(mir); mir.return_ty = ret_ty; - mir.suspend_ty = None; + mir.yield_ty = None; mir.arg_count = 2; mir.spread_arg = None; mir.generator_layout = Some(layout); diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs index 1353be0046de3..e7ee68b104b41 100644 --- a/src/librustc_mir/transform/inline.rs +++ b/src/librustc_mir/transform/inline.rs @@ -176,7 +176,7 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { } // Cannot inline generators which haven't been transformed yet - if callee_mir.suspend_ty.is_some() { + if callee_mir.yield_ty.is_some() { return false; } @@ -657,7 +657,7 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Integrator<'a, 'tcx> { match *kind { TerminatorKind::GeneratorDrop | - TerminatorKind::Suspend { .. } => bug!(), + TerminatorKind::Yield { .. } => bug!(), TerminatorKind::Goto { ref mut target} => { *target = self.update_target(*target); } diff --git a/src/librustc_mir/transform/no_landing_pads.rs b/src/librustc_mir/transform/no_landing_pads.rs index d68d702696f51..fa6bb644871dc 100644 --- a/src/librustc_mir/transform/no_landing_pads.rs +++ b/src/librustc_mir/transform/no_landing_pads.rs @@ -44,7 +44,7 @@ impl<'tcx> MutVisitor<'tcx> for NoLandingPads { TerminatorKind::Return | TerminatorKind::Unreachable | TerminatorKind::GeneratorDrop | - TerminatorKind::Suspend { .. } | + TerminatorKind::Yield { .. } | TerminatorKind::SwitchInt { .. } => { /* nothing to do */ }, diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index cb75dd9a52999..3ae0f8f2e82a2 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -377,7 +377,7 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> { TerminatorKind::DropAndReplace { .. } | TerminatorKind::Resume | TerminatorKind::GeneratorDrop | - TerminatorKind::Suspend { .. } | + TerminatorKind::Yield { .. } | TerminatorKind::Unreachable => None, TerminatorKind::Return => { diff --git a/src/librustc_mir/transform/type_check.rs b/src/librustc_mir/transform/type_check.rs index b196d8aca1f4d..38b9454f8962b 100644 --- a/src/librustc_mir/transform/type_check.rs +++ b/src/librustc_mir/transform/type_check.rs @@ -512,14 +512,14 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { } } } - TerminatorKind::Suspend { ref value, .. } => { + TerminatorKind::Yield { ref value, .. } => { let value_ty = value.ty(mir, tcx); - match mir.suspend_ty { - None => span_mirbug!(self, term, "suspend in non-generator"), + match mir.yield_ty { + None => span_mirbug!(self, term, "yield in non-generator"), Some(ty) if ty != value_ty => { span_mirbug!(self, term, - "type of suspend value is ({:?}, but the suspend type is ({:?}", + "type of yield value is ({:?}, but the yield type is ({:?}", value_ty, ty); } @@ -657,9 +657,9 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { span_mirbug!(self, block, "generator_drop in cleanup block") } } - TerminatorKind::Suspend { resume, drop, .. } => { + TerminatorKind::Yield { resume, drop, .. } => { if is_cleanup { - span_mirbug!(self, block, "suspend in cleanup block") + span_mirbug!(self, block, "yield in cleanup block") } self.assert_iscleanup(mir, block, resume, is_cleanup); if let Some(drop) = drop { diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/consts.rs index e3d665c4bcb1b..b852183380652 100644 --- a/src/librustc_passes/consts.rs +++ b/src/librustc_passes/consts.rs @@ -436,7 +436,7 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node hir::ExprRet(_) | // Generator expressions - hir::ExprSuspend(_) | + hir::ExprYield(_) | hir::ExprImplArg(_) | // Expressions with side-effects. diff --git a/src/librustc_passes/mir_stats.rs b/src/librustc_passes/mir_stats.rs index cc7df7acb499f..2e3c594e43c59 100644 --- a/src/librustc_passes/mir_stats.rs +++ b/src/librustc_passes/mir_stats.rs @@ -159,7 +159,7 @@ impl<'a, 'tcx> mir_visit::Visitor<'tcx> for StatCollector<'a, 'tcx> { TerminatorKind::Call { .. } => "TerminatorKind::Call", TerminatorKind::Assert { .. } => "TerminatorKind::Assert", TerminatorKind::GeneratorDrop => "TerminatorKind::GeneratorDrop", - TerminatorKind::Suspend { .. } => "TerminatorKind::Suspend", + TerminatorKind::Yield { .. } => "TerminatorKind::Yield", }, kind); self.super_terminator_kind(block, kind, location); } diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs index 57edb14a42d41..559acd53a3602 100644 --- a/src/librustc_trans/collector.rs +++ b/src/librustc_trans/collector.rs @@ -630,7 +630,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { mir::TerminatorKind::Unreachable | mir::TerminatorKind::Assert { .. } => {} mir::TerminatorKind::GeneratorDrop | - mir::TerminatorKind::Suspend { .. } => bug!(), + mir::TerminatorKind::Yield { .. } => bug!(), } self.super_terminator_kind(block, kind, location); diff --git a/src/librustc_trans/common.rs b/src/librustc_trans/common.rs index ebadba51bcf28..8cf22e2e4fea5 100644 --- a/src/librustc_trans/common.rs +++ b/src/librustc_trans/common.rs @@ -538,7 +538,7 @@ pub fn ty_fn_sig<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, sig.map_bound(|sig| { let state_did = tcx.lang_items.gen_state().unwrap(); let state_adt_ref = tcx.adt_def(state_did); - let state_substs = tcx.mk_substs([Kind::from(sig.suspend_ty), + let state_substs = tcx.mk_substs([Kind::from(sig.yield_ty), Kind::from(sig.return_ty)].iter()); let ret_ty = tcx.mk_adt(state_adt_ref, state_substs); diff --git a/src/librustc_trans/mir/analyze.rs b/src/librustc_trans/mir/analyze.rs index 54f2af3c179bd..9ff32bb708801 100644 --- a/src/librustc_trans/mir/analyze.rs +++ b/src/librustc_trans/mir/analyze.rs @@ -218,7 +218,7 @@ pub fn cleanup_kinds<'a, 'tcx>(mir: &mir::Mir<'tcx>) -> IndexVec { + TerminatorKind::Yield { .. } => { /* nothing to do */ } TerminatorKind::Call { cleanup: unwind, .. } | diff --git a/src/librustc_trans/mir/block.rs b/src/librustc_trans/mir/block.rs index a0369b80df0d8..edf833a26307e 100644 --- a/src/librustc_trans/mir/block.rs +++ b/src/librustc_trans/mir/block.rs @@ -579,7 +579,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { cleanup); } mir::TerminatorKind::GeneratorDrop | - mir::TerminatorKind::Suspend { .. } => bug!("generator ops in trans"), + mir::TerminatorKind::Yield { .. } => bug!("generator ops in trans"), } } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 40693d4d0ea70..d8cedb81ac8ee 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -506,7 +506,7 @@ pub struct FnCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { ret_coercion: Option>>, - suspend_ty: Option>, + yield_ty: Option>, impl_arg_ty: Option>, ps: RefCell, @@ -1037,7 +1037,7 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>, // Write the type to the impl arg id fcx.write_ty(impl_arg.id, impl_arg_ty); - fcx.suspend_ty = Some(fcx.next_ty_var(TypeVariableOrigin::TypeInference(span))); + fcx.yield_ty = Some(fcx.next_ty_var(TypeVariableOrigin::TypeInference(span))); } } @@ -1062,7 +1062,7 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>, let gen_ty = if can_be_generator && body.is_generator() { let gen_sig = ty::GenSig { impl_arg_ty: fcx.impl_arg_ty.unwrap(), - suspend_ty: fcx.suspend_ty.unwrap(), + yield_ty: fcx.yield_ty.unwrap(), return_ty: ret_ty, }; inherited.tables.borrow_mut().generator_sigs.insert(fn_id, Some(gen_sig)); @@ -1750,7 +1750,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { param_env, err_count_on_creation: inh.tcx.sess.err_count(), ret_coercion: None, - suspend_ty: None, + yield_ty: None, impl_arg_ty: None, ps: RefCell::new(UnsafetyState::function(hir::Unsafety::Normal, ast::CRATE_NODE_ID)), @@ -4008,8 +4008,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } } - hir::ExprSuspend(ref value) => { - match self.suspend_ty { + hir::ExprYield(ref value) => { + match self.yield_ty { Some(ty) => { self.check_expr_coercable_to_type(&value, ty); } diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index 2b166d2418b74..5c397a9843716 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -329,7 +329,7 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { for (&node_id, gen_sig) in self.fcx.tables.borrow().generator_sigs.iter() { let gen_sig = gen_sig.map(|s| ty::GenSig { impl_arg_ty: self.resolve(&s.impl_arg_ty, &node_id), - suspend_ty: self.resolve(&s.suspend_ty, &node_id), + yield_ty: self.resolve(&s.yield_ty, &node_id), return_ty: self.resolve(&s.return_ty, &node_id), }); self.tables.generator_sigs.insert(node_id, gen_sig); From 8cd0595602feedb123abbed03714a56a43bcbbec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Mon, 10 Jul 2017 21:12:32 +0200 Subject: [PATCH 016/113] Use FIXME instead of TODO --- src/test/compile-fail/generator/borrowing.rs | 2 +- src/test/run-pass/generator/drop-env.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/compile-fail/generator/borrowing.rs b/src/test/compile-fail/generator/borrowing.rs index c721ea04acf17..ea2189d9f8117 100644 --- a/src/test/compile-fail/generator/borrowing.rs +++ b/src/test/compile-fail/generator/borrowing.rs @@ -23,7 +23,7 @@ fn main() { let _b = { let a = 3; || { - let _: () = gen arg; // TODO: shouldn't be needed for inference + let _: () = gen arg; // FIXME: shouldn't be needed for inference yield &a //~^ ERROR: `a` does not live long enough } diff --git a/src/test/run-pass/generator/drop-env.rs b/src/test/run-pass/generator/drop-env.rs index 1b0df6f87236e..be4e48f1f4cf8 100644 --- a/src/test/run-pass/generator/drop-env.rs +++ b/src/test/run-pass/generator/drop-env.rs @@ -59,7 +59,7 @@ fn t2() { fn t3() { let b = B; let foo = || { - let _: () = gen arg; // TODO: this line should not be necessary + let _: () = gen arg; // FIXME: this line should not be necessary yield; drop(b); }; From 2afd04c009c53d221d244c82a54daeb4c5d656f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Mon, 10 Jul 2017 21:24:22 +0200 Subject: [PATCH 017/113] Add some comments --- src/librustc/hir/mod.rs | 2 ++ src/librustc/ty/sty.rs | 8 +++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 40a745bcebfb3..39e17434fa1ed 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -1023,6 +1023,8 @@ pub enum Expr_ { /// A closure (for example, `move |a, b, c| {a + b + c}`). /// /// The final span is the span of the argument block `|...|` + /// + /// This may also be a generator literal, in that case there is an GeneratorClause. ExprClosure(CaptureClause, P, BodyId, Span, Option), /// A block (`{ ... }`) ExprBlock(P), diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index bd5f6a8e26254..0f0bcdb78b8ac 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -149,7 +149,8 @@ pub enum TypeVariants<'tcx> { /// `|a| a`. TyClosure(DefId, ClosureSubsts<'tcx>), - /// The anonymous type of a generator. Pairs with a TyClosure for closure generators. + /// The anonymous type of a generator. Used to represent the type of + /// `|a| yield a`. TyGenerator(DefId, ClosureSubsts<'tcx>, GeneratorInterior<'tcx>), /// The never type `!` @@ -279,6 +280,9 @@ impl<'a, 'gcx, 'acx, 'tcx> ClosureSubsts<'tcx> { } impl<'a, 'gcx, 'tcx> ClosureSubsts<'tcx> { + /// This returns the types of the MIR locals which had to be stored across suspension points. + /// It is calculated in rustc_mir::transform::generator::StateTransform. + /// All the types here must be in the tuple in GeneratorInterior. pub fn state_tys(self, def_id: DefId, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> impl Iterator> + 'tcx { @@ -287,6 +291,8 @@ impl<'a, 'gcx, 'tcx> ClosureSubsts<'tcx> { state.into_iter() } + /// This is the types of all the fields stored in a generator. + /// It includes the upvars, state types and the state discriminant which is u32. pub fn field_tys(self, def_id: DefId, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> impl Iterator> + 'tcx { From a88e7506a6419cb8d7ebc8c89188b0dba1c17d01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Mon, 10 Jul 2017 22:07:55 +0200 Subject: [PATCH 018/113] Fix whitespace --- src/librustc/hir/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 39e17434fa1ed..c90fb05615279 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -1023,7 +1023,7 @@ pub enum Expr_ { /// A closure (for example, `move |a, b, c| {a + b + c}`). /// /// The final span is the span of the argument block `|...|` - /// + /// /// This may also be a generator literal, in that case there is an GeneratorClause. ExprClosure(CaptureClause, P, BodyId, Span, Option), /// A block (`{ ... }`) From e62d9d5230535b1cd481c465f44a2c0aa666491f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Mon, 10 Jul 2017 23:13:52 +0200 Subject: [PATCH 019/113] Fix tests --- .../implicit-argument-dead-when-suspended.rs | 25 +++++++++++-------- src/test/run-pass/generator/iterator-count.rs | 2 +- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/src/test/run-pass/generator/implicit-argument-dead-when-suspended.rs b/src/test/run-pass/generator/implicit-argument-dead-when-suspended.rs index 722ec2477efbe..635d8fb3cdc63 100644 --- a/src/test/run-pass/generator/implicit-argument-dead-when-suspended.rs +++ b/src/test/run-pass/generator/implicit-argument-dead-when-suspended.rs @@ -8,26 +8,31 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(generators)] +#![feature(generators, generator_trait)] -use std::cell::Cell; +use std::ops::Generator; +use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering}; -struct Flag<'a>(&'a Cell); +static A: AtomicUsize = ATOMIC_USIZE_INIT; -impl<'a> Drop for Flag<'a> { +struct B; + +impl Drop for B { fn drop(&mut self) { - self.0.set(false) + A.fetch_add(1, Ordering::SeqCst); } } fn main() { - let alive = Cell::new(true); + let b = B; - let gen = || { + let mut gen = || { yield; }; - gen.resume(Flag(&alive)); - - assert_eq!(alive.get(), false); + assert_eq!(A.load(Ordering::SeqCst), 0); + gen.resume(b); + assert_eq!(A.load(Ordering::SeqCst), 1); + drop(gen); + assert_eq!(A.load(Ordering::SeqCst), 1); } diff --git a/src/test/run-pass/generator/iterator-count.rs b/src/test/run-pass/generator/iterator-count.rs index e44aa05923571..45ba663873b61 100644 --- a/src/test/run-pass/generator/iterator-count.rs +++ b/src/test/run-pass/generator/iterator-count.rs @@ -37,7 +37,7 @@ fn main() { let end = 11; let closure_test = |start| { - || { + move || { for i in start..end { yield i } From 5d174f0035da838e0fac2feb62904cc5303392e2 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 11 Jul 2017 07:26:44 -0700 Subject: [PATCH 020/113] Clarifying documentation for generator --- .../unstable-book/src/language-features/generators.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/doc/unstable-book/src/language-features/generators.md b/src/doc/unstable-book/src/language-features/generators.md index 8d9d9846a2332..36f6f567bd5d0 100644 --- a/src/doc/unstable-book/src/language-features/generators.md +++ b/src/doc/unstable-book/src/language-features/generators.md @@ -128,14 +128,17 @@ closure-like semantics. Namely: generator progresses. * Generator literals produce a value with a unique type which implements the - `std::ops::Generator` trait. This allows actual execution of the genrator + `std::ops::Generator` trait. This allows actual execution of the generator through the `Generator::resume` method as well as also naming it in return types and such. * Traits like `Send` and `Sync` are automatically implemented for a `Generator` - depending on the captured variables of the environment. Note, though, that - generators, like closures, do not implement traits like `Copy` or `Clone` - automatically. + depending on the captured variables of the environment. Unlike closures though + generators also depend on variables live across suspension points. This means + that although the ambient environment may be `Send` or `Sync`, the generator + itself may not be due to internal variables live across `yield` points being + not-`Send` or not-`Sync`. Note, though, that generators, like closures, do + not implement traits like `Copy` or `Clone` automatically. * Whenever a generator is dropped it will drop all captured environment variables. From 8bcafc5e171278caaaa39804392544f12ed7bccb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Tue, 11 Jul 2017 20:28:46 +0200 Subject: [PATCH 021/113] Fix hash impl for SimplifiedType --- src/librustc/ich/impls_ty.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index 29f201f84c995..bbd40c6b16848 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -696,6 +696,7 @@ impl_stable_hash_for!(enum ty::fast_reject::SimplifiedType { TupleSimplifiedType(size), TraitSimplifiedType(def_id), ClosureSimplifiedType(def_id), + GeneratorSimplifiedType(def_id), AnonSimplifiedType(def_id), FunctionSimplifiedType(params), ParameterSimplifiedType From bfd71c5b7044970ec34c7829b0ffaddb3b1dc4a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Tue, 11 Jul 2017 20:52:38 +0200 Subject: [PATCH 022/113] Fix examples --- .../src/language-features/generators.md | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/doc/unstable-book/src/language-features/generators.md b/src/doc/unstable-book/src/language-features/generators.md index 36f6f567bd5d0..ac72b4c7c21b7 100644 --- a/src/doc/unstable-book/src/language-features/generators.md +++ b/src/doc/unstable-book/src/language-features/generators.md @@ -83,6 +83,9 @@ Feedback on the design and usage is always appreciated! The `Generator` trait in `std::ops` currently looks like: ``` +# #![feature(generator_trait)] +# use std::ops::State; + pub trait Generator { type Yield; type Return; @@ -165,8 +168,8 @@ fn main() { return ret }; - drop(generator.resume(())) - drop(generator.resume(())) + drop(generator.resume(())); + drop(generator.resume(())); } ``` @@ -210,11 +213,11 @@ fn main() { } } - __Generator::Start(ret) : impl Generator + __Generator::Start(ret) }; - drop(generator.resume(())) - drop(generator.resume(())) + drop(generator.resume(())); + drop(generator.resume(())); } ``` From 66b8a12a6d2dd0e71781becedec0fe35729c2f41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Wed, 12 Jul 2017 01:26:31 +0200 Subject: [PATCH 023/113] Fix upstream changes --- src/librustc/traits/project.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs index 91d6fac26f1bb..b97c2b77d10e9 100644 --- a/src/librustc/traits/project.rs +++ b/src/librustc/traits/project.rs @@ -1158,10 +1158,10 @@ fn confirm_generator_candidate<'cx, 'gcx, 'tcx>( // Note: we unwrap the binder here but re-create it below (1) let ty::Binder((trait_ref, yield_ty, return_ty)) = tcx.generator_trait_ref_and_outputs(gen_def_id, - obligation.predicate.trait_ref.self_ty(), + obligation.predicate.self_ty(), gen_sig); - let name = obligation.predicate.item_name(tcx); + let name = tcx.associated_item(obligation.predicate.item_def_id).name; let ty = if name == Symbol::intern("Return") { return_ty } else if name == Symbol::intern("Yield") { @@ -1172,7 +1172,7 @@ fn confirm_generator_candidate<'cx, 'gcx, 'tcx>( let predicate = ty::Binder(ty::ProjectionPredicate { // (1) recreate binder here projection_ty: ty::ProjectionTy { - trait_ref: trait_ref, + substs: trait_ref.substs, item_def_id: obligation.predicate.item_def_id, }, ty: ty From 098d6f05971d68aa6e24a46a3505a4b9ec42d992 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Thu, 13 Jul 2017 02:25:43 +0200 Subject: [PATCH 024/113] Move a FIXME around --- src/librustc/ty/flags.rs | 2 -- src/librustc/ty/mod.rs | 2 ++ 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/librustc/ty/flags.rs b/src/librustc/ty/flags.rs index 72e4e20d70b4c..02d50ce29e4f1 100644 --- a/src/librustc/ty/flags.rs +++ b/src/librustc/ty/flags.rs @@ -86,8 +86,6 @@ impl FlagComputation { } &ty::TyGenerator(_, ref substs, ref interior) => { - // FIXME: Find out why TyClosure has HAS_TY_CLOSURE - // and see if the same reason applies here self.add_flags(TypeFlags::HAS_TY_CLOSURE); self.add_flags(TypeFlags::HAS_LOCAL_NAMES); self.add_substs(&substs.substs); diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 21a98bceedff3..648300f9cf429 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -406,6 +406,8 @@ bitflags! { const HAS_FREE_REGIONS = 1 << 6, const HAS_TY_ERR = 1 << 7, const HAS_PROJECTION = 1 << 8, + + // FIXME: Rename this to the actual property since it's used for generators too const HAS_TY_CLOSURE = 1 << 9, // true if there are "names" of types and regions and so forth From 75eb59895f0de231fd8fe66fd78518387c99b9fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Thu, 13 Jul 2017 02:32:36 +0200 Subject: [PATCH 025/113] Copy a comment --- src/librustc/traits/select.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 3fcd79f706b78..9d5494d1fbab6 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -1500,6 +1500,9 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { return Ok(()); } + // ok to skip binder because the substs on generator types never + // touch bound regions, they just capture the in-scope + // type/region parameters let self_ty = *obligation.self_ty().skip_binder(); let (closure_def_id, substs) = match self_ty.sty { ty::TyGenerator(id, substs, _) => (id, substs), From 21f2d259e0fc563edf8d9b076f156c8c2fcb886f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Thu, 13 Jul 2017 04:40:57 +0200 Subject: [PATCH 026/113] Consider StorageDead and StorageLive as gens for liveness analysis --- src/librustc_mir/util/liveness.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/librustc_mir/util/liveness.rs b/src/librustc_mir/util/liveness.rs index 79293cfde251f..c96e3ec057b48 100644 --- a/src/librustc_mir/util/liveness.rs +++ b/src/librustc_mir/util/liveness.rs @@ -46,7 +46,10 @@ impl<'tcx> Visitor<'tcx> for BlockInfoVisitor { location: Location) { if let Lvalue::Local(local) = *lvalue { match context { - LvalueContext::Store | LvalueContext::Call => { + LvalueContext::Store | + LvalueContext::Call | + LvalueContext::StorageLive | + LvalueContext::StorageDead => { self.defs.add(&local); } LvalueContext::Projection(..) | @@ -59,7 +62,6 @@ impl<'tcx> Visitor<'tcx> for BlockInfoVisitor { self.uses.add(&local); } } - LvalueContext::StorageLive | LvalueContext::StorageDead => (), } } From 05fcef0b3e2ac6e4eee5060439c5e7601b2625e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Thu, 13 Jul 2017 06:29:26 +0200 Subject: [PATCH 027/113] Fix printing --- src/librustc/hir/print.rs | 7 +++---- src/libsyntax/print/pprust.rs | 8 +++----- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs index d513719146282..f58981f616de2 100644 --- a/src/librustc/hir/print.rs +++ b/src/librustc/hir/print.rs @@ -1462,13 +1462,12 @@ impl<'a> State<'a> { self.pclose()?; } hir::ExprYield(ref expr) => { - word(&mut self.s, "yield ")?; + self.s.word("yield")?; + self.s.space()?; self.print_expr(&expr)?; } hir::ExprImplArg(_) => { - word(&mut self.s, "gen")?; - space(&mut self.s)?; - word(&mut self.s, "arg")?; + self.s.word("gen arg")?; } } self.ann.post(self, NodeExpr(expr))?; diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 114cabe26d150..1412f78b00d73 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -2281,19 +2281,17 @@ impl<'a> State<'a> { self.pclose()?; }, ast::ExprKind::Yield(ref e) => { - word(&mut self.s, "yield")?; + self.s.word("yield")?; match *e { Some(ref expr) => { - word(&mut self.s, " ")?; + self.s.space()?; self.print_expr(&expr)?; } _ => () } } ast::ExprKind::ImplArg => { - word(&mut self.s, "impl")?; - space(&mut self.s)?; - word(&mut self.s, "arg")?; + self.s.word("impl arg")?; } ast::ExprKind::Try(ref e) => { self.print_expr(e)?; From 6e66dccc44104b7411ee3b5fd0fea7e2d48b8d73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Fri, 14 Jul 2017 00:25:59 +0200 Subject: [PATCH 028/113] Remove a FIXME --- src/librustc/hir/map/blocks.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/librustc/hir/map/blocks.rs b/src/librustc/hir/map/blocks.rs index 7094bd5b2cc1f..a7cb1f3232b20 100644 --- a/src/librustc/hir/map/blocks.rs +++ b/src/librustc/hir/map/blocks.rs @@ -253,7 +253,6 @@ impl<'a> FnLikeNode<'a> { }, map::NodeExpr(e) => match e.node { ast::ExprClosure(_, ref decl, block, _fn_decl_span, _gen) => - // FIXME: Does this need handling for generators? closure(ClosureParts::new(&decl, block, e.id, e.span, &e.attrs)), _ => bug!("expr FnLikeNode that is not fn-like"), }, From 7eae8489fc0e08938eb91c5c9ed0f3af919280c1 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 13 Jul 2017 15:34:45 -0700 Subject: [PATCH 029/113] Touch up unstable docs for generators --- .../src/language-features/generators.md | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/doc/unstable-book/src/language-features/generators.md b/src/doc/unstable-book/src/language-features/generators.md index ac72b4c7c21b7..3182aa2dbd75c 100644 --- a/src/doc/unstable-book/src/language-features/generators.md +++ b/src/doc/unstable-book/src/language-features/generators.md @@ -9,7 +9,10 @@ The tracking issue for this feature is: [#43122] The `generators` feature gate in Rust allows you to define generator or coroutine literals. A generator is a "resumable function" that syntactically resembles a closure but compiles to much different semantics in the compiler -itself. +itself. The primary feature of a generator is that it can be suspended during +execution to be resumed at a later date. Generators use the `yield` keyword to +"return", and then the caller can `resume` a generator to resume execution just +after the `yield` keyword. Generators are an extra-unstable feature in the compiler right now. Added in [RFC 2033] they're mostly intended right now as a information/constraint @@ -48,7 +51,7 @@ Generators are closure-like literals which can contain a `yield` statement. The `yield` statement takes an optional expression of a value to yield out of the generator. All generator literals implement the `Generator` trait in the `std::ops` module. The `Generator` trait has one main method, `resume`, which -resumes execution of the closure at the previous suspension point. +resumes execution of the generator at the previous suspension point. An example of the control flow of generators is that the following example prints all numbers in order: @@ -86,10 +89,10 @@ The `Generator` trait in `std::ops` currently looks like: # #![feature(generator_trait)] # use std::ops::State; -pub trait Generator { +pub trait Generator { type Yield; type Return; - fn resume(&mut self, arg: Arg) -> State; + fn resume(&mut self) -> State; } ``` @@ -146,6 +149,10 @@ closure-like semantics. Namely: * Whenever a generator is dropped it will drop all captured environment variables. +Note that unlike closures generators at this time cannot take any arguments. +That is, generators must always look like `|| { ... }`. This restriction may be +lifted at a future date, the design is ongoing! + ### Generators as state machines In the compiler generators are currently compiled as state machines. Each From 77bf6e4461404dce1bb06a7804dcceaf4e819836 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Sat, 15 Jul 2017 00:01:20 +0200 Subject: [PATCH 030/113] Add a test --- .../compile-fail/generator/yield-in-args.rs | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 src/test/compile-fail/generator/yield-in-args.rs diff --git a/src/test/compile-fail/generator/yield-in-args.rs b/src/test/compile-fail/generator/yield-in-args.rs new file mode 100644 index 0000000000000..0d15fc0997f91 --- /dev/null +++ b/src/test/compile-fail/generator/yield-in-args.rs @@ -0,0 +1,20 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(generators)] + +fn foo(_b: &bool, _a: ()) {} + +fn main() { + || { + let b = true; + foo(&b, yield); // ERROR `b` does not live long enough + }; +} From 12bbcd3c294a96ea915048a9bd525ee9074390f1 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 14 Jul 2017 15:53:15 -0700 Subject: [PATCH 031/113] Add a test case for conditional drop --- .../run-pass/generator/conditional-drop.rs | 65 +++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 src/test/run-pass/generator/conditional-drop.rs diff --git a/src/test/run-pass/generator/conditional-drop.rs b/src/test/run-pass/generator/conditional-drop.rs new file mode 100644 index 0000000000000..8329684e1a39b --- /dev/null +++ b/src/test/run-pass/generator/conditional-drop.rs @@ -0,0 +1,65 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(generators, generator_trait)] + +use std::ops::Generator; +use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering}; + +static A: AtomicUsize = ATOMIC_USIZE_INIT; + +struct B; + +impl Drop for B { + fn drop(&mut self) { + A.fetch_add(1, Ordering::SeqCst); + } +} + + +fn test() -> bool { true } +fn test2() -> bool { false } + +fn main() { + t1(); + t2(); +} + +fn t1() { + let mut a = || { + let b = B; + if test() { + drop(b); + } + yield; + }; + + let n = A.load(Ordering::SeqCst); + a.resume(); + assert_eq!(A.load(Ordering::SeqCst), n + 1); + a.resume(); + assert_eq!(A.load(Ordering::SeqCst), n + 1); +} + +fn t2() { + let mut a = || { + let b = B; + if test2() { + drop(b); + } + yield; + }; + + let n = A.load(Ordering::SeqCst); + a.resume(); + assert_eq!(A.load(Ordering::SeqCst), n); + a.resume(); + assert_eq!(A.load(Ordering::SeqCst), n + 1); +} From 8e82b19c6b293aca9ad8bbcb755346803d1eb61d Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 14 Jul 2017 15:54:07 -0700 Subject: [PATCH 032/113] Convert tabs to spaces --- src/test/compile-fail/generator/yield-in-args.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/test/compile-fail/generator/yield-in-args.rs b/src/test/compile-fail/generator/yield-in-args.rs index 0d15fc0997f91..02106662b18fb 100644 --- a/src/test/compile-fail/generator/yield-in-args.rs +++ b/src/test/compile-fail/generator/yield-in-args.rs @@ -13,8 +13,8 @@ fn foo(_b: &bool, _a: ()) {} fn main() { - || { - let b = true; - foo(&b, yield); // ERROR `b` does not live long enough - }; + || { + let b = true; + foo(&b, yield); // ERROR `b` does not live long enough + }; } From 264c3f4952f1ff182502aa0885ca479c42cec17c Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 14 Jul 2017 19:02:07 -0400 Subject: [PATCH 033/113] add some tests of yielding with outstanding borrows No doubt there are more tests one might write, but it's a start. --- .../generator/yield-during-borrow.rs | 144 ++++++++++++++++++ 1 file changed, 144 insertions(+) create mode 100644 src/test/compile-fail/generator/yield-during-borrow.rs diff --git a/src/test/compile-fail/generator/yield-during-borrow.rs b/src/test/compile-fail/generator/yield-during-borrow.rs new file mode 100644 index 0000000000000..46732ce6599a7 --- /dev/null +++ b/src/test/compile-fail/generator/yield-during-borrow.rs @@ -0,0 +1,144 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(generators, generator_trait)] + +use std::ops::{State, Generator}; +use std::cell::Cell; + +fn borrow_local_inline() { + // Not OK to yield with a borrow of a temporary. + // + // (This error occurs because the region shows up in the type of + // `b` and gets extended by region inference.) + let mut b = move || { + let a = &3; + yield(); + println!("{}", a); + }; //~ ERROR E0597 + b.resume(); +} + +fn borrow_local_inline_done() { + // No error here -- `a` is not in scope at the point of `yield`. + let mut b = move || { + { + let a = &3; + } + yield(); + }; + b.resume(); +} + +fn borrow_local() { + // Not OK to yield with a borrow of a temporary. + // + // (This error occurs because the region shows up in the type of + // `b` and gets extended by region inference.) + let mut b = move || { + let a = 3; + { + let b = &a; + yield(); + println!("{}", b); + } + }; //~ ERROR E0597 + b.resume(); +} + +fn reborrow_shared_ref(x: &i32) { + // This is OK -- we have a borrow live over the yield, but it's of + // data that outlives the generator. + let mut b = move || { + let a = &*x; + yield(); + println!("{}", a); + }; + b.resume(); +} + +fn reborrow_mutable_ref(x: &mut i32) { + // This is OK -- we have a borrow live over the yield, but it's of + // data that outlives the generator. + let mut b = move || { + let a = &mut *x; + yield(); + println!("{}", a); + }; + b.resume(); +} + +fn reborrow_mutable_ref_2(x: &mut i32) { + // ...but not OK to go on using `x`. + let mut b = || { + let a = &mut *x; + yield(); + println!("{}", a); + }; + println!("{}", x); //~ ERROR E0501 + b.resume(); +} + +fn yield_during_iter_owned_data(x: Vec) { + // The generator owns `x`, so we error out when yielding with a + // reference to it. This winds up becoming a rather confusing + // regionck error -- in particular, we would freeze with the + // reference in scope, and it doesn't live long enough. + let _b = move || { + for p in &x { + yield(); + } + }; //~ ERROR E0597 +} + +fn yield_during_iter_borrowed_slice(x: &[i32]) { + let _b = move || { + for p in x { + yield(); + } + }; +} + +fn yield_during_iter_borrowed_slice_2() { + let mut x = vec![22_i32]; + let _b = || { + for p in &x { + yield(); + } + }; + println!("{:?}", x); +} + +fn yield_during_iter_borrowed_slice_3() { + // OK to take a mutable ref to `x` and yield + // up pointers from it: + let mut x = vec![22_i32]; + let mut b = || { + for p in &mut x { + yield p; + } + }; + b.resume(); +} + +fn yield_during_iter_borrowed_slice_4() { + // ...but not OK to do that while reading + // from `x` too + let mut x = vec![22_i32]; + let mut b = || { + for p in &mut x { + yield p; + } + }; + println!("{}", x[0]); //~ ERROR cannot borrow `x` as immutable + b.resume(); +} + +fn main() { } From d71fa9371ca392cc2daadbc01d4e4c13d056a103 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 14 Jul 2017 19:11:21 -0400 Subject: [PATCH 034/113] fix yields-in-args test and add a reverse one --- .../generator/yield-in-args-rev.rs | 24 +++++++++++++++++++ .../compile-fail/generator/yield-in-args.rs | 8 +++---- 2 files changed, 28 insertions(+), 4 deletions(-) create mode 100644 src/test/compile-fail/generator/yield-in-args-rev.rs diff --git a/src/test/compile-fail/generator/yield-in-args-rev.rs b/src/test/compile-fail/generator/yield-in-args-rev.rs new file mode 100644 index 0000000000000..2fadbfeb9d88d --- /dev/null +++ b/src/test/compile-fail/generator/yield-in-args-rev.rs @@ -0,0 +1,24 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(generators)] + +fn foo(_a: (), _b: &bool) {} + +// Some examples that probably *could* be accepted, but which we reject for now. + +fn bar() { + || { + let b = true; + foo(yield, &b); + }; //~ ERROR `b` does not live long enough +} + +fn main() { } diff --git a/src/test/compile-fail/generator/yield-in-args.rs b/src/test/compile-fail/generator/yield-in-args.rs index 02106662b18fb..c719baa5e2a39 100644 --- a/src/test/compile-fail/generator/yield-in-args.rs +++ b/src/test/compile-fail/generator/yield-in-args.rs @@ -13,8 +13,8 @@ fn foo(_b: &bool, _a: ()) {} fn main() { - || { - let b = true; - foo(&b, yield); // ERROR `b` does not live long enough - }; + || { + let b = true; + foo(&b, yield); + }; //~ ERROR `b` does not live long enough } From 2ad0f89e867df98b4be3573d58f99d3abcaf02e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Sat, 15 Jul 2017 00:21:59 +0200 Subject: [PATCH 035/113] Tweak docs --- .../src/language-features/generators.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/doc/unstable-book/src/language-features/generators.md b/src/doc/unstable-book/src/language-features/generators.md index 3182aa2dbd75c..231945db37bd7 100644 --- a/src/doc/unstable-book/src/language-features/generators.md +++ b/src/doc/unstable-book/src/language-features/generators.md @@ -38,11 +38,11 @@ fn main() { match generator.resume(()) { State::Yielded(1) => {} - _ => panic!("unexpected return from resume"), + _ => panic!("unexpected value from resume"), } match generator.resume(()) { State::Complete("foo") => {} - _ => panic!("unexpected return from resume"), + _ => panic!("unexpected value from resume"), } } ``` @@ -69,9 +69,9 @@ fn main() { }; println!("1"); - drop(generator.resume(())); + generator.resume(()); println!("3"); - drop(generator.resume(())); + generator.resume(()); println!("5"); } ``` @@ -175,8 +175,8 @@ fn main() { return ret }; - drop(generator.resume(())); - drop(generator.resume(())); + generator.resume(()); + generator.resume(()); } ``` @@ -223,8 +223,8 @@ fn main() { __Generator::Start(ret) }; - drop(generator.resume(())); - drop(generator.resume(())); + generator.resume(()); + generator.resume(()); } ``` From 10def9a6e0fc9ace09934f71a8eef0b556e9111f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Sat, 15 Jul 2017 01:22:13 +0200 Subject: [PATCH 036/113] Revert borrowck changes --- .../borrowck/gather_loans/mod.rs | 29 +++---------------- src/librustc_borrowck/diagnostics.rs | 1 - 2 files changed, 4 insertions(+), 26 deletions(-) diff --git a/src/librustc_borrowck/borrowck/gather_loans/mod.rs b/src/librustc_borrowck/borrowck/gather_loans/mod.rs index bcfc9db56fcc7..426eef5957075 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/mod.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/mod.rs @@ -21,7 +21,6 @@ use borrowck::move_data::MoveData; use rustc::middle::expr_use_visitor as euv; use rustc::middle::mem_categorization as mc; use rustc::middle::mem_categorization::Categorization; -use rustc::middle::region::extent_has_yield; use rustc::middle::region; use rustc::ty::{self, TyCtxt}; @@ -37,20 +36,19 @@ mod gather_moves; mod move_error; pub fn gather_loans_in_fn<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, - body_id: hir::BodyId) + body: hir::BodyId) -> (Vec>, move_data::MoveData<'tcx>) { - let def_id = bccx.tcx.hir.body_owner_def_id(body_id); + let def_id = bccx.tcx.hir.body_owner_def_id(body); let param_env = bccx.tcx.param_env(def_id); - let body = bccx.tcx.hir.body(body_id); let mut glcx = GatherLoanCtxt { bccx: bccx, all_loans: Vec::new(), - item_ub: region::CodeExtent::Misc(body_id.node_id), + item_ub: region::CodeExtent::Misc(body.node_id), move_data: MoveData::new(), move_error_collector: move_error::MoveErrorCollector::new(), - generator: body.is_generator(), }; + let body = glcx.bccx.tcx.hir.body(body); euv::ExprUseVisitor::new(&mut glcx, bccx.tcx, param_env, &bccx.region_maps, bccx.tables) .consume_body(body); @@ -67,7 +65,6 @@ struct GatherLoanCtxt<'a, 'tcx: 'a> { /// `item_ub` is used as an upper-bound on the lifetime whenever we /// ask for the scope of an expression categorized as an upvar. item_ub: region::CodeExtent, - generator: bool, } impl<'a, 'tcx> euv::Delegate<'tcx> for GatherLoanCtxt<'a, 'tcx> { @@ -219,19 +216,6 @@ fn check_aliasability<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, } } -fn check_yields<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, - borrow_span: Span, - loan_region: ty::Region<'tcx>) { - if let &ty::RegionKind::ReScope(extent) = loan_region { - if extent_has_yield(bccx.tcx, extent) { - span_err!(bccx.tcx.sess, - borrow_span, - E0624, - "cannot borrow this value across the suspend point of a generator"); - } - } -} - /// Implements the M-* rules in README.md. fn check_mutability<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, borrow_span: Span, @@ -343,11 +327,6 @@ impl<'a, 'tcx> GatherLoanCtxt<'a, 'tcx> { return; } - // Check that the region has no yields if this is in a generator - if self.generator { - check_yields(self.bccx, borrow_span, loan_region); - } - // Check that the lifetime of the borrow does not exceed // the lifetime of the data being borrowed. if lifetime::guarantee_lifetime(self.bccx, self.item_ub, diff --git a/src/librustc_borrowck/diagnostics.rs b/src/librustc_borrowck/diagnostics.rs index 2ae9498d63cfd..cc9bdf8c8a553 100644 --- a/src/librustc_borrowck/diagnostics.rs +++ b/src/librustc_borrowck/diagnostics.rs @@ -1192,5 +1192,4 @@ register_diagnostics! { E0595, // closure cannot assign to {} E0598, // lifetime of {} is too short to guarantee its contents can be... E0623, // borrow of the implicit argument of a generator - E0624, // borrow across a suspend point } From a602fc06bdc1570e48761542cf06e6b051e802d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Sat, 15 Jul 2017 01:37:43 +0200 Subject: [PATCH 037/113] Revert some whitespace changes --- src/librustc_typeck/variance/constraints.rs | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/librustc_typeck/variance/constraints.rs b/src/librustc_typeck/variance/constraints.rs index 6e9e6137b4443..aa334bc570a76 100644 --- a/src/librustc_typeck/variance/constraints.rs +++ b/src/librustc_typeck/variance/constraints.rs @@ -149,11 +149,11 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { // // See README.md for a detailed discussion // on dep-graph management. - let dep_node = def_id.to_dep_node(tcx, DepKind::ItemVarianceConstraints); - tcx.dep_graph.with_task(dep_node, - AssertDepGraphSafe(self), - def_id, - visit_item_task); + let dep_node = def_id.to_dep_node(tcx, DepKind::ItemVarianceConstraints); + tcx.dep_graph.with_task(dep_node, + AssertDepGraphSafe(self), + def_id, + visit_item_task); fn visit_item_task<'a, 'tcx>(ccx: AssertDepGraphSafe<&mut ConstraintContext<'a, 'tcx>>, def_id: DefId) @@ -202,9 +202,9 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { _ => { span_bug!(tcx.def_span(def_id), "`build_constraints_for_item` unsupported for this item"); + } } } - } fn add_constraint(&mut self, current: &CurrentItem, @@ -269,7 +269,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { let variance_i = self.invariant(variance); for ty in substs.types() { self.add_constraints_from_ty(current, ty, variance_i); - } + } for region in substs.regions() { self.add_constraints_from_region(current, region, variance_i); @@ -350,7 +350,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { ty::TyParam(ref data) => { self.add_constraint(current, data.idx, variance); - } + } ty::TyFnPtr(sig) => { self.add_constraints_from_sig(current, sig, variance); @@ -419,7 +419,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { self.add_constraints_from_region(current, r, variance_i); } else { bug!(); - } + } } } @@ -445,7 +445,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { match *region { ty::ReEarlyBound(ref data) => { self.add_constraint(current, data.index, variance); - } + } ty::ReStatic => {} From dcddd807297765b85f11c05f68f0845cc8d372aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Sat, 15 Jul 2017 03:50:43 +0200 Subject: [PATCH 038/113] Remove debug code --- src/librustc_typeck/check/mod.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index d8cedb81ac8ee..78168f8db7193 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1015,10 +1015,6 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>, let def_id = fcx.tcx.hir.local_def_id(fn_id); let span = body.value.span; - if fcx.tcx.sess.verbose() { - println!("checking body {} {}", fn_id, can_be_generator); - } - if let Some(ref impl_arg) = body.impl_arg { if can_be_generator { let impl_arg_ty = fcx.infcx.type_var_for_impl_arg(span, def_id); From 93172045c817ffa998d5e28a0899f33edf889f62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Sat, 15 Jul 2017 03:51:44 +0200 Subject: [PATCH 039/113] Fix a bug with yielding subtypes of the yield type. --- src/librustc_mir/transform/type_check.rs | 16 ++++++++------ src/test/run-pass/generator/yield-subtype.rs | 23 ++++++++++++++++++++ 2 files changed, 32 insertions(+), 7 deletions(-) create mode 100644 src/test/run-pass/generator/yield-subtype.rs diff --git a/src/librustc_mir/transform/type_check.rs b/src/librustc_mir/transform/type_check.rs index 38b9454f8962b..69f3d68df5718 100644 --- a/src/librustc_mir/transform/type_check.rs +++ b/src/librustc_mir/transform/type_check.rs @@ -516,14 +516,16 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { let value_ty = value.ty(mir, tcx); match mir.yield_ty { None => span_mirbug!(self, term, "yield in non-generator"), - Some(ty) if ty != value_ty => { - span_mirbug!(self, - term, - "type of yield value is ({:?}, but the yield type is ({:?}", - value_ty, - ty); + Some(ty) => { + if let Err(terr) = self.sub_types(value_ty, ty) { + span_mirbug!(self, + term, + "22 - type of yield value is {:?}, but the yield type is {:?}: {:?}", + value_ty, + ty, + terr); + } } - _ => (), } } } diff --git a/src/test/run-pass/generator/yield-subtype.rs b/src/test/run-pass/generator/yield-subtype.rs new file mode 100644 index 0000000000000..268add4974b0b --- /dev/null +++ b/src/test/run-pass/generator/yield-subtype.rs @@ -0,0 +1,23 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(generators)] + +fn bar<'a>() { + let a: &'static str = "hi"; + let b: &'a str = a; + + || { + yield a; + yield b; + }; +} + +fn main() {} \ No newline at end of file From 09a5d319ab8fbfd43530289bfff3899f9035e37f Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 11 Jul 2017 12:57:05 -0700 Subject: [PATCH 040/113] Remove support for `gen arg` --- .../src/language-features/generators.md | 18 +++---- src/liballoc/boxed.rs | 8 +-- src/libcore/ops/generator.rs | 16 +++--- src/librustc/cfg/construct.rs | 1 - src/librustc/hir/intravisit.rs | 6 --- src/librustc/hir/lowering.rs | 36 ++++--------- src/librustc/hir/map/collector.rs | 7 --- src/librustc/hir/map/mod.rs | 11 ---- src/librustc/hir/mod.rs | 24 ++------- src/librustc/hir/print.rs | 4 -- src/librustc/ich/impls_hir.rs | 17 ++----- src/librustc/ich/impls_ty.rs | 1 - .../infer/error_reporting/need_type_info.rs | 13 ----- src/librustc/infer/mod.rs | 19 ------- src/librustc/middle/expr_use_visitor.rs | 2 - src/librustc/middle/liveness.rs | 22 +------- src/librustc/middle/mem_categorization.rs | 11 ---- src/librustc/middle/region.rs | 3 -- src/librustc/mir/mod.rs | 4 -- src/librustc/traits/util.rs | 2 +- src/librustc/ty/mod.rs | 2 - src/librustc/ty/structural_impls.rs | 7 +-- src/librustc/ty/sty.rs | 1 - .../borrowck/gather_loans/mod.rs | 16 ------ src/librustc_borrowck/diagnostics.rs | 1 - src/librustc_mir/build/expr/as_lvalue.rs | 3 -- src/librustc_mir/build/expr/as_rvalue.rs | 6 --- src/librustc_mir/build/expr/as_temp.rs | 2 +- src/librustc_mir/build/expr/category.rs | 1 - src/librustc_mir/build/expr/into.rs | 1 - src/librustc_mir/build/matches/mod.rs | 2 +- src/librustc_mir/build/mod.rs | 48 ++++------------- src/librustc_mir/build/scope.rs | 33 ++---------- .../dataflow/drop_flag_effects.rs | 5 -- src/librustc_mir/dataflow/move_paths/mod.rs | 1 - src/librustc_mir/hair/cx/expr.rs | 3 +- src/librustc_mir/hair/mod.rs | 1 - src/librustc_mir/transform/elaborate_drops.rs | 4 -- src/librustc_mir/transform/generator.rs | 51 +------------------ src/librustc_passes/consts.rs | 1 - src/librustc_trans/common.rs | 2 +- src/librustc_typeck/check/mod.rs | 44 ++-------------- src/librustc_typeck/check/upvar.rs | 3 +- src/librustc_typeck/check/writeback.rs | 4 -- src/librustc_typeck/collect.rs | 2 +- src/librustc_typeck/diagnostics.rs | 3 +- src/libsyntax/ast.rs | 3 -- src/libsyntax/feature_gate.rs | 5 -- src/libsyntax/fold.rs | 1 - src/libsyntax/parse/parser.rs | 14 +---- src/libsyntax/print/pprust.rs | 3 -- src/libsyntax/visit.rs | 1 - src/libsyntax_pos/symbol.rs | 2 - .../compile-fail/feature-gate-generators.rs | 1 - src/test/compile-fail/generator/borrowing.rs | 3 +- .../generator/no-arguments-on-generators.rs | 2 +- .../compile-fail/generator/not-send-sync.rs | 2 - .../compile-fail/generator/yield-in-const.rs | 3 +- .../generator/yield-in-function.rs | 3 +- .../compile-fail/generator/yield-in-static.rs | 3 +- src/test/run-pass/generator/control-flow.rs | 4 +- src/test/run-pass/generator/drop-env.rs | 5 +- .../implicit-argument-dead-when-suspended.rs | 38 -------------- src/test/run-pass/generator/iterator-count.rs | 2 +- src/test/run-pass/generator/panic-drops.rs | 4 +- src/test/run-pass/generator/panic-safe.rs | 4 +- .../run-pass/generator/resume-after-return.rs | 4 +- src/test/run-pass/generator/smoke.rs | 35 +++++-------- 68 files changed, 106 insertions(+), 508 deletions(-) delete mode 100644 src/test/run-pass/generator/implicit-argument-dead-when-suspended.rs diff --git a/src/doc/unstable-book/src/language-features/generators.md b/src/doc/unstable-book/src/language-features/generators.md index 231945db37bd7..a8d449382eec4 100644 --- a/src/doc/unstable-book/src/language-features/generators.md +++ b/src/doc/unstable-book/src/language-features/generators.md @@ -36,11 +36,11 @@ fn main() { return "foo" }; - match generator.resume(()) { + match generator.resume() { State::Yielded(1) => {} _ => panic!("unexpected value from resume"), } - match generator.resume(()) { + match generator.resume() { State::Complete("foo") => {} _ => panic!("unexpected value from resume"), } @@ -69,9 +69,9 @@ fn main() { }; println!("1"); - generator.resume(()); + generator.resume(); println!("3"); - generator.resume(()); + generator.resume(); println!("5"); } ``` @@ -175,8 +175,8 @@ fn main() { return ret }; - generator.resume(()); - generator.resume(()); + generator.resume(); + generator.resume(); } ``` @@ -200,7 +200,7 @@ fn main() { type Yield = i32; type Return = &'static str; - fn resume(&mut self, arg: ()) -> State { + fn resume(&mut self) -> State { use std::mem; match mem::replace(self, __Generator::Done) { __Generator::Start(s) => { @@ -223,8 +223,8 @@ fn main() { __Generator::Start(ret) }; - generator.resume(()); - generator.resume(()); + generator.resume(); + generator.resume(); } ``` diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index eae8da8dab919..f9eeb74ea0035 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -786,12 +786,12 @@ impl AsMut for Box { } #[unstable(feature = "generator_trait", issue = "43122")] -impl Generator for Box - where T: Generator + ?Sized +impl Generator for Box + where T: Generator + ?Sized { type Yield = T::Yield; type Return = T::Return; - fn resume(&mut self, arg: U) -> State { - (**self).resume(arg) + fn resume(&mut self) -> State { + (**self).resume() } } diff --git a/src/libcore/ops/generator.rs b/src/libcore/ops/generator.rs index 4d125573afce7..44b9835daf5f2 100644 --- a/src/libcore/ops/generator.rs +++ b/src/libcore/ops/generator.rs @@ -56,11 +56,11 @@ pub enum State { /// return "foo" /// }; /// -/// match generator.resume(()) { +/// match generator.resume() { /// State::Yielded(1) => {} /// _ => panic!("unexpected return from resume"), /// } -/// match generator.resume(()) { +/// match generator.resume() { /// State::Complete("foo") => {} /// _ => panic!("unexpected return from resume"), /// } @@ -73,7 +73,7 @@ pub enum State { #[cfg_attr(not(stage0), lang = "generator")] #[unstable(feature = "generator_trait", issue = "43122")] #[fundamental] -pub trait Generator { +pub trait Generator { /// The type of value this generator yields. /// /// This associated type corresponds to the `yield` expression and the @@ -116,16 +116,16 @@ pub trait Generator { /// been returned previously. While generator literals in the language are /// guaranteed to panic on resuming after `Complete`, this is not guaranteed /// for all implementations of the `Generator` trait. - fn resume(&mut self, arg: Arg) -> State; + fn resume(&mut self) -> State; } #[unstable(feature = "generator_trait", issue = "43122")] -impl<'a, T, U> Generator for &'a mut T - where T: Generator + ?Sized +impl<'a, T> Generator for &'a mut T + where T: Generator + ?Sized { type Yield = T::Yield; type Return = T::Return; - fn resume(&mut self, arg: U) -> State { - (**self).resume(arg) + fn resume(&mut self) -> State { + (**self).resume() } } diff --git a/src/librustc/cfg/construct.rs b/src/librustc/cfg/construct.rs index fb205655df29c..e7e2c84fc4efa 100644 --- a/src/librustc/cfg/construct.rs +++ b/src/librustc/cfg/construct.rs @@ -402,7 +402,6 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { hir::ExprClosure(..) | hir::ExprLit(..) | - hir::ExprImplArg(_) | hir::ExprPath(_) => { self.straightline(expr, pred, None::.iter()) } diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs index 9e4117033724f..43496540c1177 100644 --- a/src/librustc/hir/intravisit.rs +++ b/src/librustc/hir/intravisit.rs @@ -399,9 +399,6 @@ pub fn walk_body<'v, V: Visitor<'v>>(visitor: &mut V, body: &'v Body) { visitor.visit_id(argument.id); visitor.visit_pat(&argument.pat); } - if let Some(ref impl_arg) = body.impl_arg { - visitor.visit_id(impl_arg.id); - } visitor.visit_expr(&body.value); } @@ -1048,9 +1045,6 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) { ExprYield(ref subexpression) => { visitor.visit_expr(subexpression); } - ExprImplArg(id) => { - visitor.visit_id(id); - }, } } diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 3aa7149933cba..32fa343e911ff 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -92,7 +92,7 @@ pub struct LoweringContext<'a> { trait_impls: BTreeMap>, trait_default_impl: BTreeMap, - impl_arg: Option, + is_generator: hir::IsGenerator, catch_scopes: Vec, loop_scopes: Vec, @@ -139,7 +139,6 @@ pub fn lower_crate(sess: &Session, trait_impls: BTreeMap::new(), trait_default_impl: BTreeMap::new(), exported_macros: Vec::new(), - impl_arg: None, catch_scopes: Vec::new(), loop_scopes: Vec::new(), is_in_loop_condition: false, @@ -147,6 +146,7 @@ pub fn lower_crate(sess: &Session, current_hir_id_owner: vec![(CRATE_DEF_INDEX, 0)], item_local_id_counters: NodeMap(), node_id_to_hir_id: IndexVec::new(), + is_generator: hir::IsGenerator::No, }.lower_crate(krate) } @@ -365,24 +365,13 @@ impl<'a> LoweringContext<'a> { }) } - fn impl_arg_id(&mut self) -> NodeId { - if self.impl_arg.is_none() { - self.impl_arg = Some(self.next_id()); - } - self.impl_arg.unwrap() - } - fn record_body(&mut self, value: hir::Expr, decl: Option<&FnDecl>) -> hir::BodyId { - let span = value.span; let body = hir::Body { arguments: decl.map_or(hir_vec![], |decl| { decl.inputs.iter().map(|x| self.lower_arg(x)).collect() }), - impl_arg: self.impl_arg.map(|id| hir::ImplArg { - id, - span, - }), + is_generator: self.is_generator == hir::IsGenerator::Yes, value, }; let id = body.id(); @@ -443,12 +432,11 @@ impl<'a> LoweringContext<'a> { fn lower_body(&mut self, decl: Option<&FnDecl>, f: F) -> hir::BodyId where F: FnOnce(&mut LoweringContext) -> hir::Expr { - let old_impl_arg = self.impl_arg; - self.impl_arg = None; + let prev = mem::replace(&mut self.is_generator, hir::IsGenerator::No); let result = f(self); let r = self.record_body(result, decl); - self.impl_arg = old_impl_arg; - r + self.is_generator = prev; + return r } fn with_loop_scope(&mut self, loop_id: NodeId, f: F) -> T @@ -1952,13 +1940,13 @@ impl<'a> LoweringContext<'a> { ExprKind::Closure(capture_clause, ref decl, ref body, fn_decl_span) => { self.with_new_scopes(|this| { this.with_parent_def(e.id, |this| { - let mut gen = None; + let mut gen = hir::IsGenerator::No; let body_id = this.lower_body(Some(decl), |this| { let e = this.lower_expr(body); - gen = this.impl_arg.map(|_| hir::GeneratorClause::Movable); + gen = this.is_generator; e }); - if gen.is_some() && !decl.inputs.is_empty() { + if gen == hir::IsGenerator::Yes && !decl.inputs.is_empty() { this.sess.span_fatal( fn_decl_span, &format!("generators cannot have explicit arguments")); @@ -2104,17 +2092,13 @@ impl<'a> LoweringContext<'a> { } ExprKind::Yield(ref opt_expr) => { - self.impl_arg_id(); + self.is_generator = hir::IsGenerator::Yes; let expr = opt_expr.as_ref().map(|x| self.lower_expr(x)).unwrap_or_else(|| { self.expr(e.span, hir::ExprTup(hir_vec![]), ThinVec::new()) }); hir::ExprYield(P(expr)) } - ExprKind::ImplArg => { - hir::ExprImplArg(self.impl_arg_id()) - } - // Desugar ExprIfLet // From: `if let = []` ExprKind::IfLet(ref pat, ref sub_expr, ref body, ref else_opt) => { diff --git a/src/librustc/hir/map/collector.rs b/src/librustc/hir/map/collector.rs index dfc1c7ad36132..d3ae3e0e8e8ac 100644 --- a/src/librustc/hir/map/collector.rs +++ b/src/librustc/hir/map/collector.rs @@ -182,13 +182,6 @@ impl<'hir> Visitor<'hir> for NodeCollector<'hir> { }); } - fn visit_body(&mut self, b: &'hir Body) { - if let Some(ref impl_arg) = b.impl_arg { - self.insert(impl_arg.id, NodeImplArg(impl_arg)); - } - intravisit::walk_body(self, b); - } - fn visit_fn(&mut self, fk: intravisit::FnKind<'hir>, fd: &'hir FnDecl, b: BodyId, s: Span, id: NodeId) { assert_eq!(self.parent_node, id); diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs index 9a04cef5ee0fa..6bbff608be426 100644 --- a/src/librustc/hir/map/mod.rs +++ b/src/librustc/hir/map/mod.rs @@ -55,7 +55,6 @@ pub enum Node<'hir> { NodeTraitRef(&'hir TraitRef), NodeLocal(&'hir Pat), NodePat(&'hir Pat), - NodeImplArg(&'hir ImplArg), NodeBlock(&'hir Block), /// NodeStructCtor represents a tuple struct. @@ -85,7 +84,6 @@ enum MapEntry<'hir> { EntryTy(NodeId, &'hir Ty), EntryTraitRef(NodeId, &'hir TraitRef), EntryLocal(NodeId, &'hir Pat), - EntryImplArg(NodeId, &'hir ImplArg), EntryPat(NodeId, &'hir Pat), EntryBlock(NodeId, &'hir Block), EntryStructCtor(NodeId, &'hir VariantData), @@ -117,7 +115,6 @@ impl<'hir> MapEntry<'hir> { NodeTy(n) => EntryTy(p, n), NodeTraitRef(n) => EntryTraitRef(p, n), NodeLocal(n) => EntryLocal(p, n), - NodeImplArg(n) => EntryImplArg(p, n), NodePat(n) => EntryPat(p, n), NodeBlock(n) => EntryBlock(p, n), NodeStructCtor(n) => EntryStructCtor(p, n), @@ -139,7 +136,6 @@ impl<'hir> MapEntry<'hir> { EntryStmt(id, _) => id, EntryTy(id, _) => id, EntryTraitRef(id, _) => id, - EntryImplArg(id, _) => id, EntryLocal(id, _) => id, EntryPat(id, _) => id, EntryBlock(id, _) => id, @@ -166,7 +162,6 @@ impl<'hir> MapEntry<'hir> { EntryTy(_, n) => NodeTy(n), EntryTraitRef(_, n) => NodeTraitRef(n), EntryLocal(_, n) => NodeLocal(n), - EntryImplArg(_, n) => NodeImplArg(n), EntryPat(_, n) => NodePat(n), EntryBlock(_, n) => NodeBlock(n), EntryStructCtor(_, n) => NodeStructCtor(n), @@ -327,7 +322,6 @@ impl<'hir> Map<'hir> { EntryTy(p, _) | EntryTraitRef(p, _) | EntryLocal(p, _) | - EntryImplArg(p, _) | EntryPat(p, _) | EntryBlock(p, _) | EntryStructCtor(p, _) | @@ -903,7 +897,6 @@ impl<'hir> Map<'hir> { Some(EntryTy(_, ty)) => ty.span, Some(EntryTraitRef(_, tr)) => tr.path.span, Some(EntryLocal(_, pat)) => pat.span, - Some(EntryImplArg(_, impl_arg)) => impl_arg.span, Some(EntryPat(_, pat)) => pat.span, Some(EntryBlock(_, block)) => block.span, Some(EntryStructCtor(_, _)) => self.expect_item(self.get_parent(id)).span, @@ -1113,7 +1106,6 @@ impl<'a> print::State<'a> { } NodeLifetime(a) => self.print_lifetime(&a), NodeVisibility(a) => self.print_visibility(&a), - NodeImplArg(_) => bug!("cannot print ImplArg"), NodeTyParam(_) => bug!("cannot print TyParam"), NodeField(_) => bug!("cannot print StructField"), // these cases do not carry enough information in the @@ -1215,9 +1207,6 @@ fn node_id_to_string(map: &Map, id: NodeId, include_id: bool) -> String { Some(NodeLocal(_)) => { format!("local {}{}", map.node_to_pretty_string(id), id_str) } - Some(NodeImplArg(_)) => { - format!("impl_arg {}{}", map.node_to_pretty_string(id), id_str) - } Some(NodePat(_)) => { format!("pat {}{}", map.node_to_pretty_string(id), id_str) } diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index c90fb05615279..8fb7ca643a7c9 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -925,13 +925,6 @@ pub enum UnsafeSource { UserProvided, } -/// represents an implicit argument of a generator -#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] -pub struct ImplArg { - pub id: NodeId, - pub span: Span, -} - #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, RustcEncodable, RustcDecodable, Hash, Debug)] pub struct BodyId { pub node_id: NodeId, @@ -942,7 +935,7 @@ pub struct BodyId { pub struct Body { pub arguments: HirVec, pub value: Expr, - pub impl_arg: Option, + pub is_generator: bool, } impl Body { @@ -951,10 +944,6 @@ impl Body { node_id: self.value.id } } - - pub fn is_generator(&self) -> bool { - self.impl_arg.is_some() - } } /// An expression @@ -1025,7 +1014,7 @@ pub enum Expr_ { /// The final span is the span of the argument block `|...|` /// /// This may also be a generator literal, in that case there is an GeneratorClause. - ExprClosure(CaptureClause, P, BodyId, Span, Option), + ExprClosure(CaptureClause, P, BodyId, Span, IsGenerator), /// A block (`{ ... }`) ExprBlock(P), @@ -1073,9 +1062,6 @@ pub enum Expr_ { /// A suspension point for generators. This is `yield ` in Rust. ExprYield(P), - - /// The argument to a generator - ExprImplArg(NodeId), } /// Optionally `Self`-qualified value/type path or associated extension. @@ -1205,9 +1191,9 @@ pub struct Destination { } #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)] -pub enum GeneratorClause { - Immovable, - Movable, +pub enum IsGenerator { + Yes, + No, } #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)] diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs index f58981f616de2..f4d7b101e9cc4 100644 --- a/src/librustc/hir/print.rs +++ b/src/librustc/hir/print.rs @@ -1463,12 +1463,8 @@ impl<'a> State<'a> { } hir::ExprYield(ref expr) => { self.s.word("yield")?; - self.s.space()?; self.print_expr(&expr)?; } - hir::ExprImplArg(_) => { - self.s.word("gen arg")?; - } } self.ann.post(self, NodeExpr(expr))?; self.end() diff --git a/src/librustc/ich/impls_hir.rs b/src/librustc/ich/impls_hir.rs index 39fa0cb44d09d..04e8cbeb7ff9f 100644 --- a/src/librustc/ich/impls_hir.rs +++ b/src/librustc/ich/impls_hir.rs @@ -574,7 +574,6 @@ impl<'a, 'gcx, 'tcx> HashStable> for hir::E hir::ExprAgain(..) | hir::ExprRet(..) | hir::ExprYield(..) | - hir::ExprImplArg(..) | hir::ExprInlineAsm(..) | hir::ExprRepeat(..) | hir::ExprTup(..) => { @@ -654,8 +653,7 @@ impl_stable_hash_for!(enum hir::Expr_ { ExprInlineAsm(asm, inputs, outputs), ExprStruct(path, fields, base), ExprRepeat(val, times), - ExprYield(val), - ExprImplArg(id) + ExprYield(val) }); impl_stable_hash_for!(enum hir::LocalSource { @@ -690,9 +688,9 @@ impl<'a, 'gcx, 'tcx> HashStable> for hir::M } } -impl_stable_hash_for!(enum hir::GeneratorClause { - Immovable, - Movable +impl_stable_hash_for!(enum hir::IsGenerator { + Yes, + No }); impl_stable_hash_for!(enum hir::CaptureClause { @@ -1031,15 +1029,10 @@ impl_stable_hash_for!(struct hir::Arg { id }); -impl_stable_hash_for!(struct hir::ImplArg { - id, - span -}); - impl_stable_hash_for!(struct hir::Body { arguments, value, - impl_arg + is_generator }); impl<'a, 'gcx, 'tcx> HashStable> for hir::BodyId { diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index bbd40c6b16848..7042f3993e12d 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -143,7 +143,6 @@ for ty::UpvarCapture<'tcx> { } impl_stable_hash_for!(struct ty::GenSig<'tcx> { - impl_arg_ty, yield_ty, return_ty }); diff --git a/src/librustc/infer/error_reporting/need_type_info.rs b/src/librustc/infer/error_reporting/need_type_info.rs index 3fa13d7ab9efe..a684881c0912a 100644 --- a/src/librustc/infer/error_reporting/need_type_info.rs +++ b/src/librustc/infer/error_reporting/need_type_info.rs @@ -16,7 +16,6 @@ use ty::{self, Ty, TyInfer, TyVar}; use syntax::ast::NodeId; use syntax_pos::Span; -use syntax_pos::DUMMY_SP; struct FindLocalByTypeVisitor<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, @@ -24,7 +23,6 @@ struct FindLocalByTypeVisitor<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { hir_map: &'a hir::map::Map<'gcx>, found_local_pattern: Option<&'gcx Pat>, found_arg_pattern: Option<&'gcx Pat>, - found_impl_arg: bool, } impl<'a, 'gcx, 'tcx> FindLocalByTypeVisitor<'a, 'gcx, 'tcx> { @@ -70,11 +68,6 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for FindLocalByTypeVisitor<'a, 'gcx, 'tcx> { self.found_arg_pattern = Some(&*argument.pat); } } - if let Some(ref impl_arg) = body.impl_arg { - if !self.found_impl_arg && self.node_matches_type(impl_arg.id) { - self.found_impl_arg = true; - } - } intravisit::walk_body(self, body); } } @@ -108,7 +101,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { hir_map: &self.tcx.hir, found_local_pattern: None, found_arg_pattern: None, - found_impl_arg: false, }; if let Some(body_id) = body_id { @@ -145,11 +137,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } } - if local_visitor.found_impl_arg { - labels.push((DUMMY_SP, format!("consider giving a type to the \ - implicit generator argument"))); - } - let mut err = struct_span_err!(self.tcx.sess, err_span, E0282, diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 59fab366eaf49..2d7ce4a82daee 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -992,25 +992,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { self.next_region_var(EarlyBoundRegion(span, def.name, def.issue_32330)) } - pub fn type_var_for_impl_arg(&self, - span: Span, - def_id: DefId) - -> Ty<'tcx> { - let default = Some(type_variable::Default { - ty: self.tcx.mk_nil(), - origin_span: span, - def_id: def_id, - }); - - let ty_var_id = self.type_variables - .borrow_mut() - .new_var(false, - TypeVariableOrigin::TypeInference(span), - default); - - self.tcx.mk_var(ty_var_id) - } - /// Create a type inference variable for the given /// type parameter definition. The substitutions are /// for actual parameters that may be referred to by diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 1154c82cd2edf..899068a2b3b61 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -528,8 +528,6 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { hir::ExprYield(ref value) => { self.consume_expr(&value); } - - hir::ExprImplArg(_) => { } } } diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index 98e742c694e9f..abb75c96c10a2 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -249,7 +249,6 @@ struct LocalInfo { #[derive(Copy, Clone, Debug)] enum VarKind { - ImplArg(NodeId), Arg(NodeId, ast::Name), Local(LocalInfo), CleanExit @@ -305,7 +304,7 @@ impl<'a, 'tcx> IrMaps<'a, 'tcx> { self.num_vars += 1; match vk { - Local(LocalInfo { id: node_id, .. }) | Arg(node_id, _) | ImplArg(node_id) => { + Local(LocalInfo { id: node_id, .. }) | Arg(node_id, _) => { self.variable_map.insert(node_id, v); }, CleanExit => {} @@ -330,7 +329,6 @@ impl<'a, 'tcx> IrMaps<'a, 'tcx> { Local(LocalInfo { name, .. }) | Arg(_, name) => { name.to_string() }, - ImplArg(_) => "".to_string(), CleanExit => "".to_string() } } @@ -367,10 +365,6 @@ fn visit_fn<'a, 'tcx: 'a>(ir: &mut IrMaps<'a, 'tcx>, }) }; - if let Some(ref impl_arg) = body.impl_arg { - fn_maps.add_variable(ImplArg(impl_arg.id)); - } - // gather up the various local variables, significant expressions, // and so forth: intravisit::walk_fn(&mut fn_maps, fk, decl, body_id, sp, id); @@ -423,10 +417,6 @@ fn visit_expr<'a, 'tcx>(ir: &mut IrMaps<'a, 'tcx>, expr: &'tcx Expr) { } intravisit::walk_expr(ir, expr); } - hir::ExprImplArg(_) => { - ir.add_live_node_for_node(expr.id, ExprNode(expr.span)); - intravisit::walk_expr(ir, expr); - } hir::ExprClosure(..) => { // Interesting control flow (for loops can contain labeled // breaks or continues) @@ -891,10 +881,6 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { match expr.node { // Interesting cases with control flow or which gen/kill - hir::ExprImplArg(arg_id) => { - self.access_var(expr.id, arg_id, succ, ACC_READ | ACC_USE, expr.span) - } - hir::ExprPath(hir::QPath::Resolved(_, ref path)) => { self.access_path(expr.id, path, succ, ACC_READ | ACC_USE) } @@ -1226,9 +1212,6 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { fn write_lvalue(&mut self, expr: &Expr, succ: LiveNode, acc: u32) -> LiveNode { match expr.node { - hir::ExprImplArg(arg_id) => { - self.access_var(expr.id, arg_id, succ, acc, expr.span) - } hir::ExprPath(hir::QPath::Resolved(_, ref path)) => { self.access_path(expr.id, path, succ, acc) } @@ -1419,7 +1402,7 @@ fn check_expr<'a, 'tcx>(this: &mut Liveness<'a, 'tcx>, expr: &'tcx Expr) { hir::ExprCast(..) | hir::ExprUnary(..) | hir::ExprRet(..) | hir::ExprBreak(..) | hir::ExprAgain(..) | hir::ExprLit(_) | hir::ExprBlock(..) | hir::ExprAddrOf(..) | - hir::ExprStruct(..) | hir::ExprRepeat(..) | hir::ExprImplArg(_) | + hir::ExprStruct(..) | hir::ExprRepeat(..) | hir::ExprClosure(..) | hir::ExprPath(_) | hir::ExprYield(..) | hir::ExprBox(..) | hir::ExprType(..) => { intravisit::walk_expr(this, expr); @@ -1442,7 +1425,6 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { self.warn_about_dead_assign(expr.span, expr.id, ln, var); } } - hir::ExprImplArg(_) => bug!(), _ => { // For other kinds of lvalues, no checks are required, // and any embedded expressions are actually rvalues diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 92883ca1b11ae..f06d4a3d9e3e7 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -602,17 +602,6 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { self.cat_def(expr.id, expr.span, expr_ty, def) } - hir::ExprImplArg(id) => { - Ok(Rc::new(cmt_ { - id: expr.id, - span: expr.span, - cat: Categorization::Local(id), - mutbl: MutabilityCategory::McDeclared, - ty: expr_ty, - note: NoteNone - })) - }, - hir::ExprType(ref e, _) => { self.cat_expr(&e) } diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index b8b8476d54b46..269522e826920 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -1072,9 +1072,6 @@ impl<'a, 'tcx> Visitor<'tcx> for RegionResolutionVisitor<'a, 'tcx> { for argument in &body.arguments { self.visit_pat(&argument.pat); } - if let Some(ref impl_arg) = body.impl_arg { - record_var_lifetime(self, impl_arg.id, impl_arg.span); - } // The body of the every fn is a root scope. self.cx.parent = self.cx.var_parent; diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index 2c500aa9c6fe9..a255221c87156 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -181,10 +181,6 @@ impl<'tcx> Mir<'tcx> { } } - pub fn impl_arg_lvalue() -> Lvalue<'tcx> { - Lvalue::Local(Local::new(1)) - } - #[inline] pub fn basic_blocks(&self) -> &IndexVec> { &self.basic_blocks diff --git a/src/librustc/traits/util.rs b/src/librustc/traits/util.rs index f0b812ff9687d..28abd1577dade 100644 --- a/src/librustc/traits/util.rs +++ b/src/librustc/traits/util.rs @@ -521,7 +521,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { { let trait_ref = ty::TraitRef { def_id: fn_trait_def_id, - substs: self.mk_substs_trait(self_ty, &[sig.skip_binder().impl_arg_ty]), + substs: self.mk_substs_trait(self_ty, &[]), }; ty::Binder((trait_ref, sig.skip_binder().yield_ty, sig.skip_binder().return_ty)) } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 648300f9cf429..85218c6baa577 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -1979,7 +1979,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { }, } }, - Some(hir_map::NodeImplArg(_)) => Symbol::intern("impl arg").as_str(), r => bug!("Variable id {} maps to {:?}, not local", id, r), } } @@ -2000,7 +1999,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { hir::ExprUnary(hir::UnDeref, _) | hir::ExprField(..) | hir::ExprTupField(..) | - hir::ExprImplArg(_) | hir::ExprIndex(..) => { true } diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index c70831cd551cf..f93626b7cb187 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -304,10 +304,9 @@ impl<'a, 'tcx> Lift<'tcx> for ty::adjustment::AutoBorrow<'a> { impl<'a, 'tcx> Lift<'tcx> for ty::GenSig<'a> { type Lifted = ty::GenSig<'tcx>; fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option { - tcx.lift(&(self.impl_arg_ty, self.yield_ty, self.return_ty)) - .map(|(impl_arg_ty, yield_ty, return_ty)| { + tcx.lift(&(self.yield_ty, self.return_ty)) + .map(|(yield_ty, return_ty)| { ty::GenSig { - impl_arg_ty, yield_ty, return_ty, } @@ -637,14 +636,12 @@ impl<'tcx> TypeFoldable<'tcx> for ty::TypeAndMut<'tcx> { impl<'tcx> TypeFoldable<'tcx> for ty::GenSig<'tcx> { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { ty::GenSig { - impl_arg_ty: self.impl_arg_ty.fold_with(folder), yield_ty: self.yield_ty.fold_with(folder), return_ty: self.return_ty.fold_with(folder), } } fn super_visit_with>(&self, visitor: &mut V) -> bool { - self.impl_arg_ty.visit_with(visitor) || self.yield_ty.visit_with(visitor) || self.return_ty.visit_with(visitor) } diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index 0f0bcdb78b8ac..9a180b3552da3 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -648,7 +648,6 @@ impl<'a, 'tcx> ProjectionTy<'tcx> { #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] pub struct GenSig<'tcx> { - pub impl_arg_ty: Ty<'tcx>, pub yield_ty: Ty<'tcx>, pub return_ty: Ty<'tcx>, } diff --git a/src/librustc_borrowck/borrowck/gather_loans/mod.rs b/src/librustc_borrowck/borrowck/gather_loans/mod.rs index 426eef5957075..21d6ebe568702 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/mod.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/mod.rs @@ -133,22 +133,6 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for GatherLoanCtxt<'a, 'tcx> { bk={:?}, loan_cause={:?})", borrow_id, cmt, loan_region, bk, loan_cause); - - let borrows_impl_arg = match cmt.cat { - Categorization::Local(id) => match self.bccx.tcx.hir.find(id) { - Some(hir::map::NodeImplArg(..)) => true, - _ => false, - }, - _ => false, - }; - - if borrows_impl_arg { - span_err!(self.bccx.tcx.sess, - borrow_span, - E0623, - "cannot borrow the implicit argument of a generator"); - } - self.guarantee_valid(borrow_id, borrow_span, cmt, diff --git a/src/librustc_borrowck/diagnostics.rs b/src/librustc_borrowck/diagnostics.rs index cc9bdf8c8a553..38dcc73123691 100644 --- a/src/librustc_borrowck/diagnostics.rs +++ b/src/librustc_borrowck/diagnostics.rs @@ -1191,5 +1191,4 @@ register_diagnostics! { E0594, // cannot assign to {} E0595, // closure cannot assign to {} E0598, // lifetime of {} is too short to guarantee its contents can be... - E0623, // borrow of the implicit argument of a generator } diff --git a/src/librustc_mir/build/expr/as_lvalue.rs b/src/librustc_mir/build/expr/as_lvalue.rs index 659a5e60364bf..72eeaca8b101f 100644 --- a/src/librustc_mir/build/expr/as_lvalue.rs +++ b/src/librustc_mir/build/expr/as_lvalue.rs @@ -80,9 +80,6 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { success.and(slice.index(idx)) } ExprKind::SelfRef => { - block.and(Lvalue::Local(Local::new(this.arg_offset + 1))) - } - ExprKind::ImplArg => { block.and(Lvalue::Local(Local::new(1))) } ExprKind::VarRef { id } => { diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs index 024b1a3483acf..c1209f4fbe25c 100644 --- a/src/librustc_mir/build/expr/as_rvalue.rs +++ b/src/librustc_mir/build/expr/as_rvalue.rs @@ -241,11 +241,6 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { } ExprKind::Yield { value } => { let value = unpack!(block = this.as_operand(block, scope, value)); - let impl_arg_ty = this.impl_arg_ty.unwrap(); - block = unpack!(this.build_drop(block, - expr_span, - Lvalue::Local(Local::new(1)), - impl_arg_ty)); let resume = this.cfg.start_new_block(); let cleanup = this.generator_drop_cleanup(expr_span); this.cfg.terminate(block, source_info, TerminatorKind::Yield { @@ -272,7 +267,6 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { ExprKind::Continue { .. } | ExprKind::Return { .. } | ExprKind::InlineAsm { .. } | - ExprKind::ImplArg | ExprKind::StaticRef { .. } => { // these do not have corresponding `Rvalue` variants, // so make an operand and then return that diff --git a/src/librustc_mir/build/expr/as_temp.rs b/src/librustc_mir/build/expr/as_temp.rs index 041e8fe475d00..9be306d2848b3 100644 --- a/src/librustc_mir/build/expr/as_temp.rs +++ b/src/librustc_mir/build/expr/as_temp.rs @@ -79,7 +79,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // anything because no values with a destructor can be created in // a constant at this time, even if the type may need dropping. if let Some(temp_lifetime) = temp_lifetime { - this.schedule_drop(expr_span, temp_lifetime, &temp, expr_ty, false); + this.schedule_drop(expr_span, temp_lifetime, &temp, expr_ty); } block.and(temp) diff --git a/src/librustc_mir/build/expr/category.rs b/src/librustc_mir/build/expr/category.rs index 7f576666dcdcf..f05411aacab19 100644 --- a/src/librustc_mir/build/expr/category.rs +++ b/src/librustc_mir/build/expr/category.rs @@ -50,7 +50,6 @@ impl Category { ExprKind::Index { .. } | ExprKind::SelfRef | ExprKind::VarRef { .. } | - ExprKind::ImplArg | ExprKind::StaticRef { .. } => Some(Category::Lvalue), diff --git a/src/librustc_mir/build/expr/into.rs b/src/librustc_mir/build/expr/into.rs index ef7533e8d49e7..e8fb918f76c6f 100644 --- a/src/librustc_mir/build/expr/into.rs +++ b/src/librustc_mir/build/expr/into.rs @@ -285,7 +285,6 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { ExprKind::Deref { .. } | ExprKind::Literal { .. } | ExprKind::Yield { .. } | - ExprKind::ImplArg | ExprKind::Field { .. } => { debug_assert!(match Category::of(&expr.kind).unwrap() { Category::Rvalue(RvalueFunc::Into) => false, diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs index 9e96ae474d0a8..54f285480ab53 100644 --- a/src/librustc_mir/build/matches/mod.rs +++ b/src/librustc_mir/build/matches/mod.rs @@ -203,7 +203,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let local_id = self.var_indices[&var]; let var_ty = self.local_decls[local_id].ty; let extent = self.hir.region_maps.var_scope(var); - self.schedule_drop(span, extent, &Lvalue::Local(local_id), var_ty, false); + self.schedule_drop(span, extent, &Lvalue::Local(local_id), var_ty); } pub fn visit_bindings(&mut self, pattern: &Pattern<'tcx>, mut f: &mut F) diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index 9a8c43e328638..d8d6c398b5195 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -119,14 +119,14 @@ pub fn mir_build<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Mir<'t let arguments = implicit_argument.into_iter().chain(explicit_arguments); - let (yield_ty, impl_arg_ty, return_ty) = if body.is_generator() { + let (yield_ty, return_ty) = if body.is_generator { let gen_sig = cx.tables().generator_sigs[&id].clone().unwrap(); - (Some(gen_sig.yield_ty), Some(gen_sig.impl_arg_ty), gen_sig.return_ty) + (Some(gen_sig.yield_ty), gen_sig.return_ty) } else { - (None, None, fn_sig.output()) + (None, fn_sig.output()) }; - build::construct_fn(cx, id, arguments, abi, return_ty, yield_ty, impl_arg_ty, body) + build::construct_fn(cx, id, arguments, abi, return_ty, yield_ty, body) } else { build::construct_const(cx, body_id) }; @@ -244,9 +244,6 @@ struct Builder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { fn_span: Span, arg_count: usize, - arg_offset: usize, - - impl_arg_ty: Option>, /// the current set of scopes, updated as we traverse; /// see the `scope` module for more details @@ -343,7 +340,6 @@ fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>, abi: Abi, return_ty: Ty<'gcx>, yield_ty: Option>, - impl_arg_ty: Option>, body: &'gcx hir::Body) -> Mir<'tcx> where A: Iterator, Option<&'gcx hir::Pat>)> @@ -352,12 +348,9 @@ fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>, let tcx = hir.tcx(); let span = tcx.hir.span(fn_id); - let arg_offset = if impl_arg_ty.is_some() { 1 } else { 0 }; let mut builder = Builder::new(hir.clone(), span, - arguments.len() + arg_offset, - arg_offset, - impl_arg_ty, + arguments.len(), return_ty); let call_site_extent = CodeExtent::CallSiteScope(body.id()); @@ -366,7 +359,7 @@ fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>, let source_info = builder.source_info(span); unpack!(block = builder.in_scope((call_site_extent, source_info), block, |builder| { unpack!(block = builder.in_scope((arg_extent, source_info), block, |builder| { - builder.args_and_body(block, &arguments, arg_extent, impl_arg_ty, &body.value) + builder.args_and_body(block, &arguments, arg_extent, &body.value) })); // Attribute epilogue to function's closing brace let fn_end = Span { lo: span.hi, ..span }; @@ -424,7 +417,7 @@ fn construct_const<'a, 'gcx, 'tcx>(hir: Cx<'a, 'gcx, 'tcx>, let ty = hir.tables().expr_ty_adjusted(ast_expr); let owner_id = tcx.hir.body_owner(body_id); let span = tcx.hir.span(owner_id); - let mut builder = Builder::new(hir.clone(), span, 0, 0, None, ty); + let mut builder = Builder::new(hir.clone(), span, 0, ty); let mut block = START_BLOCK; let expr = builder.hir.mirror(ast_expr); @@ -444,7 +437,7 @@ fn construct_error<'a, 'gcx, 'tcx>(hir: Cx<'a, 'gcx, 'tcx>, -> Mir<'tcx> { let span = hir.tcx().hir.span(hir.tcx().hir.body_owner(body_id)); let ty = hir.tcx().types.err; - let mut builder = Builder::new(hir, span, 0, 0, None, ty); + let mut builder = Builder::new(hir, span, 0, ty); let source_info = builder.source_info(span); builder.cfg.terminate(START_BLOCK, source_info, TerminatorKind::Unreachable); builder.finish(vec![], ty, None) @@ -454,8 +447,6 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { fn new(hir: Cx<'a, 'gcx, 'tcx>, span: Span, arg_count: usize, - arg_offset: usize, - impl_arg_ty: Option>, return_ty: Ty<'tcx>) -> Builder<'a, 'gcx, 'tcx> { let mut builder = Builder { @@ -463,8 +454,6 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { cfg: CFG { basic_blocks: IndexVec::new() }, fn_span: span, arg_count: arg_count, - arg_offset, - impl_arg_ty, scopes: vec![], visibility_scopes: IndexVec::new(), visibility_scope: ARGUMENT_VISIBILITY_SCOPE, @@ -511,26 +500,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { mut block: BasicBlock, arguments: &[(Ty<'gcx>, Option<&'gcx hir::Pat>)], argument_extent: CodeExtent, - impl_arg_ty: Option>, ast_body: &'gcx hir::Expr) -> BlockAnd<()> { - if let Some(impl_arg_ty) = impl_arg_ty { - self.local_decls.push(LocalDecl { - mutability: Mutability::Mut, - ty: impl_arg_ty, - is_user_variable: false, - source_info: SourceInfo { - scope: ARGUMENT_VISIBILITY_SCOPE, - span: self.fn_span, - }, - name: None, - }); - let lvalue = Lvalue::Local(Local::new(1)); - // Make sure we drop the argument on completion - self.schedule_drop(ast_body.span, argument_extent, &lvalue, impl_arg_ty, true); - }; - // Allocate locals for the function arguments for &(ty, pattern) in arguments.iter() { // If this is a simple binding pattern, give the local a nice name for debuginfo. @@ -557,7 +529,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // Bind the argument patterns for (index, &(ty, pattern)) in arguments.iter().enumerate() { // Function arguments always get the first Local indices after the return pointer - let lvalue = Lvalue::Local(Local::new(self.arg_offset + index + 1)); + let lvalue = Lvalue::Local(Local::new(index + 1)); if let Some(pattern) = pattern { let pattern = Pattern::from_hir(self.hir.tcx().global_tcx(), @@ -570,7 +542,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // Make sure we drop (parts of) the argument even when not matched on. self.schedule_drop(pattern.as_ref().map_or(ast_body.span, |pat| pat.span), - argument_extent, &lvalue, ty, false); + argument_extent, &lvalue, ty); } diff --git a/src/librustc_mir/build/scope.rs b/src/librustc_mir/build/scope.rs index 296d7c19e0e4a..32b429be4a677 100644 --- a/src/librustc_mir/build/scope.rs +++ b/src/librustc_mir/build/scope.rs @@ -124,9 +124,6 @@ pub struct Scope<'tcx> { /// end of the vector (top of the stack) first. drops: Vec>, - /// Is the first drop the drop of the implicit argument? - impl_arg_drop: bool, - /// A scope may only have one associated free, because: /// /// 1. We require a `free` to only be scheduled in the scope of @@ -254,28 +251,12 @@ impl<'tcx> Scope<'tcx> { } } - fn drops(&self, generator_drop: bool) -> &[DropData<'tcx>] { - if self.impl_arg_drop && generator_drop { - &self.drops[1..] - } else { - &self.drops[..] - } - } - - fn drops_mut(&mut self, generator_drop: bool) -> &mut [DropData<'tcx>] { - if self.impl_arg_drop && generator_drop { - &mut self.drops[1..] - } else { - &mut self.drops[..] - } - } - /// Returns the cached entrypoint for diverging exit from this scope. /// /// Precondition: the caches must be fully filled (i.e. diverge_cleanup is called) in order for /// this method to work correctly. fn cached_block(&self, generator_drop: bool) -> Option { - let mut drops = self.drops(generator_drop).iter().rev().filter_map(|data| { + let mut drops = self.drops.iter().rev().filter_map(|data| { match data.kind { DropKind::Value { cached_block } => { Some(cached_block.get(generator_drop)) @@ -375,7 +356,6 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { extent: extent, needs_cleanup: false, drops: vec![], - impl_arg_drop: false, free: None, cached_generator_drop: None, cached_exits: FxHashMap() @@ -617,8 +597,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { span: Span, extent: CodeExtent, lvalue: &Lvalue<'tcx>, - lvalue_ty: Ty<'tcx>, - impl_arg: bool) { + lvalue_ty: Ty<'tcx>) { let needs_drop = self.hir.needs_drop(lvalue_ty); let drop_kind = if needs_drop { DropKind::Value { cached_block: CachedBlock::default() } @@ -688,10 +667,6 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let extent_span = extent.span(&tcx.hir).unwrap(); // Attribute scope exit drops to scope's closing brace let scope_end = Span { lo: extent_span.hi, .. extent_span}; - if impl_arg { - assert!(scope.drops.is_empty()); - scope.impl_arg_drop = true; - } scope.drops.push(DropData { span: scope_end, location: lvalue.clone(), @@ -865,7 +840,7 @@ fn build_scope_drops<'tcx>(cfg: &mut CFG<'tcx>, generator_drop: bool) -> BlockAnd<()> { - let mut iter = scope.drops(generator_drop).iter().rev().peekable(); + let mut iter = scope.drops.iter().rev().peekable(); while let Some(drop_data) = iter.next() { let source_info = scope.source_info(drop_data.span); if let DropKind::Value { .. } = drop_data.kind { @@ -958,7 +933,7 @@ fn build_diverge_scope<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, // Next, build up the drops. Here we iterate the vector in // *forward* order, so that we generate drops[0] first (right to // left in diagram above). - for (j, drop_data) in scope.drops_mut(generator_drop).iter_mut().enumerate() { + for (j, drop_data) in scope.drops.iter_mut().enumerate() { debug!("build_diverge_scope drop_data[{}]: {:?}", j, drop_data); // Only full value drops are emitted in the diverging path, // not StorageDead. diff --git a/src/librustc_mir/dataflow/drop_flag_effects.rs b/src/librustc_mir/dataflow/drop_flag_effects.rs index 0b740e5f02834..daafbecc5dfa3 100644 --- a/src/librustc_mir/dataflow/drop_flag_effects.rs +++ b/src/librustc_mir/dataflow/drop_flag_effects.rs @@ -299,11 +299,6 @@ pub(crate) fn drop_flag_effects_for_location<'a, 'tcx, F>( move_data.rev_lookup.find(location), |moi| callback(moi, DropFlagState::Present)) } - mir::TerminatorKind::Yield { .. } => { - on_lookup_result_bits(tcx, mir, move_data, - move_data.rev_lookup.find(&Mir::impl_arg_lvalue()), - |moi| callback(moi, DropFlagState::Present)) - } _ => { // other terminators do not contain move-ins } diff --git a/src/librustc_mir/dataflow/move_paths/mod.rs b/src/librustc_mir/dataflow/move_paths/mod.rs index dba396e813980..4d4161d4c809c 100644 --- a/src/librustc_mir/dataflow/move_paths/mod.rs +++ b/src/librustc_mir/dataflow/move_paths/mod.rs @@ -475,7 +475,6 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> { } TerminatorKind::Yield { ref value, .. } => { - self.create_move_path(&Mir::impl_arg_lvalue()); self.gather_operand(loc, value); } diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index 4a223ce61f744..338c46a4c93b7 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -447,7 +447,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, closure_id: def_id, substs: substs, upvars: upvars, - generator: gen.is_some(), + generator: gen == hir::IsGenerator::Yes, } } @@ -567,7 +567,6 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, hir::ExprArray(ref fields) => ExprKind::Array { fields: fields.to_ref() }, hir::ExprTup(ref fields) => ExprKind::Tuple { fields: fields.to_ref() }, - hir::ExprImplArg(_) => ExprKind::ImplArg, hir::ExprYield(ref v) => ExprKind::Yield { value: v.to_ref() }, }; diff --git a/src/librustc_mir/hair/mod.rs b/src/librustc_mir/hair/mod.rs index a2e9e5c40f945..ff239a2adddd3 100644 --- a/src/librustc_mir/hair/mod.rs +++ b/src/librustc_mir/hair/mod.rs @@ -249,7 +249,6 @@ pub enum ExprKind<'tcx> { outputs: Vec>, inputs: Vec> }, - ImplArg, Yield { value: ExprRef<'tcx>, }, diff --git a/src/librustc_mir/transform/elaborate_drops.rs b/src/librustc_mir/transform/elaborate_drops.rs index 472623ec20ab3..f5a2b1b974c3d 100644 --- a/src/librustc_mir/transform/elaborate_drops.rs +++ b/src/librustc_mir/transform/elaborate_drops.rs @@ -96,11 +96,9 @@ fn find_dead_unwinds<'a, 'tcx>( MaybeInitializedLvals::new(tcx, mir, &env), |bd, p| &bd.move_data().move_paths[p]); for (bb, bb_data) in mir.basic_blocks().iter_enumerated() { - let impl_arg = Mir::impl_arg_lvalue(); let location = match bb_data.terminator().kind { TerminatorKind::Drop { ref location, unwind: Some(_), .. } | TerminatorKind::DropAndReplace { ref location, unwind: Some(_), .. } => location, - TerminatorKind::Yield { .. } => &impl_arg, _ => continue, }; @@ -344,11 +342,9 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { { for (bb, data) in self.mir.basic_blocks().iter_enumerated() { let terminator = data.terminator(); - let impl_arg = Mir::impl_arg_lvalue(); let location = match terminator.kind { TerminatorKind::Drop { ref location, .. } | TerminatorKind::DropAndReplace { ref location, .. } => location, - TerminatorKind::Yield { .. } => &impl_arg, _ => continue }; diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs index fc5834d605332..603e9d1849f8a 100644 --- a/src/librustc_mir/transform/generator.rs +++ b/src/librustc_mir/transform/generator.rs @@ -47,35 +47,6 @@ impl<'tcx> MutVisitor<'tcx> for RenameLocalVisitor { } } -struct SwapLocalVisitor { - a: Local, - b: Local, -} - -impl<'tcx> MutVisitor<'tcx> for SwapLocalVisitor { - fn visit_local(&mut self, - local: &mut Local) { - if *local == self.a { - *local = self.b; - } else if *local == self.b { - *local = self.a; - } - } -} - -struct InsertLocalVisitor { - local: Local, -} - -impl<'tcx> MutVisitor<'tcx> for InsertLocalVisitor { - fn visit_local(&mut self, - local: &mut Local) { - if local.index() >= self.local.index() { - *local = Local::new(local.index() + 1); - } - } -} - struct DerefArgVisitor; impl<'tcx> MutVisitor<'tcx> for DerefArgVisitor { @@ -251,17 +222,7 @@ fn ensure_generator_state_argument<'a, 'tcx>( def_id: DefId, mir: &mut Mir<'tcx>) -> (Ty<'tcx>, GeneratorInterior<'tcx>) { let interior = *tcx.typeck_tables_of(def_id).generator_interiors.get(&node_id).unwrap(); - - let gen_ty = mir.local_decls.raw[2].ty; - - // Swap generator and implicit argument - SwapLocalVisitor { - a: Local::new(1), - b: Local::new(2), - }.visit_mir(mir); - - mir.local_decls.raw[..].swap(1, 2); - + let gen_ty = mir.local_decls.raw[1].ty; (gen_ty, interior) } @@ -330,10 +291,6 @@ fn locals_live_across_suspend_points<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } } - // The implicit argument is defined after each suspend point so it can never - // be live in a suspend point. - set.remove(&Local::new(2)); - // The generator argument is ignored set.remove(&Local::new(1)); @@ -513,10 +470,6 @@ fn generate_drop<'a, 'tcx>( } } - // Remove the implicit argument - mir.arg_count = 1; - mir.local_decls.raw.pop(); - // Replace the return variable let source_info = SourceInfo { span: mir.span, @@ -788,7 +741,7 @@ impl MirPass for StateTransform { mir.return_ty = ret_ty; mir.yield_ty = None; - mir.arg_count = 2; + mir.arg_count = 1; mir.spread_arg = None; mir.generator_layout = Some(layout); diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/consts.rs index b852183380652..9bc198c59a9fe 100644 --- a/src/librustc_passes/consts.rs +++ b/src/librustc_passes/consts.rs @@ -437,7 +437,6 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node // Generator expressions hir::ExprYield(_) | - hir::ExprImplArg(_) | // Expressions with side-effects. hir::ExprAssign(..) | diff --git a/src/librustc_trans/common.rs b/src/librustc_trans/common.rs index 8cf22e2e4fea5..7bbaf50d21b24 100644 --- a/src/librustc_trans/common.rs +++ b/src/librustc_trans/common.rs @@ -542,7 +542,7 @@ pub fn ty_fn_sig<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, Kind::from(sig.return_ty)].iter()); let ret_ty = tcx.mk_adt(state_adt_ref, state_substs); - tcx.mk_fn_sig(iter::once(env_ty).chain(iter::once(sig.impl_arg_ty)), + tcx.mk_fn_sig(iter::once(env_ty), ret_ty, false, hir::Unsafety::Normal, diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 78168f8db7193..6125300fd2e6c 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -507,7 +507,6 @@ pub struct FnCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { ret_coercion: Option>>, yield_ty: Option>, - impl_arg_ty: Option>, ps: RefCell, @@ -1012,29 +1011,10 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>, fn_sig.abi ); - let def_id = fcx.tcx.hir.local_def_id(fn_id); let span = body.value.span; - if let Some(ref impl_arg) = body.impl_arg { - if can_be_generator { - let impl_arg_ty = fcx.infcx.type_var_for_impl_arg(span, def_id); - - // Require impl_arg: 'static - let cause = traits::ObligationCause::new(span, - body.value.id, - traits::MiscObligation); - fcx.fulfillment_cx.borrow_mut() - .register_region_obligation(impl_arg_ty, - fcx.tcx.types.re_static, - cause); - - fcx.impl_arg_ty = Some(impl_arg_ty); - - // Write the type to the impl arg id - fcx.write_ty(impl_arg.id, impl_arg_ty); - - fcx.yield_ty = Some(fcx.next_ty_var(TypeVariableOrigin::TypeInference(span))); - } + if body.is_generator && can_be_generator { + fcx.yield_ty = Some(fcx.next_ty_var(TypeVariableOrigin::TypeInference(span))); } GatherLocalsVisitor { fcx: &fcx, }.visit_body(body); @@ -1055,9 +1035,8 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>, fcx.write_ty(arg.id, arg_ty); } - let gen_ty = if can_be_generator && body.is_generator() { + let gen_ty = if can_be_generator && body.is_generator { let gen_sig = ty::GenSig { - impl_arg_ty: fcx.impl_arg_ty.unwrap(), yield_ty: fcx.yield_ty.unwrap(), return_ty: ret_ty, }; @@ -1747,7 +1726,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { err_count_on_creation: inh.tcx.sess.err_count(), ret_coercion: None, yield_ty: None, - impl_arg_ty: None, ps: RefCell::new(UnsafetyState::function(hir::Unsafety::Normal, ast::CRATE_NODE_ID)), diverges: Cell::new(Diverges::Maybe), @@ -2573,7 +2551,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let is_closure = match arg.node { // FIXME: Should this be applied for generators? - hir::ExprClosure(.., None) => true, + hir::ExprClosure(.., hir::IsGenerator::No) => true, _ => false }; @@ -3992,25 +3970,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } } - hir::ExprImplArg(_) => { - match self.impl_arg_ty { - Some(ty) => { - ty - } - None => { - struct_span_err!(self.tcx.sess, expr.span, E0626, - "gen arg expression outside of generator literal").emit(); - tcx.types.err - } - } - } hir::ExprYield(ref value) => { match self.yield_ty { Some(ty) => { self.check_expr_coercable_to_type(&value, ty); } None => { - struct_span_err!(self.tcx.sess, expr.span, E0625, + struct_span_err!(self.tcx.sess, expr.span, E0623, "yield statement outside of generator literal").emit(); } } diff --git a/src/librustc_typeck/check/upvar.rs b/src/librustc_typeck/check/upvar.rs index bf7bbfa16b2d1..ffaf6afb6e8d7 100644 --- a/src/librustc_typeck/check/upvar.rs +++ b/src/librustc_typeck/check/upvar.rs @@ -78,7 +78,8 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for InferBorrowKindVisitor<'a, 'gcx, 'tcx> { hir::ExprClosure(cc, _, body_id, _, gen) => { let body = self.fcx.tcx.hir.body(body_id); self.visit_body(body); - self.fcx.analyze_closure(expr.id, expr.span, body, cc, gen.is_some()); + self.fcx.analyze_closure(expr.id, expr.span, body, cc, + gen == hir::IsGenerator::Yes); } _ => { } diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index 5c397a9843716..2f4a9ce4013d9 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -36,9 +36,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { for arg in &body.arguments { wbcx.visit_node_id(arg.pat.span, arg.id); } - if let Some(ref impl_arg) = body.impl_arg { - wbcx.visit_node_id(impl_arg.span, impl_arg.id); - } wbcx.visit_body(body); wbcx.visit_upvar_borrow_map(); wbcx.visit_closures(); @@ -328,7 +325,6 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { fn visit_generator_sigs(&mut self) { for (&node_id, gen_sig) in self.fcx.tables.borrow().generator_sigs.iter() { let gen_sig = gen_sig.map(|s| ty::GenSig { - impl_arg_ty: self.resolve(&s.impl_arg_ty, &node_id), yield_ty: self.resolve(&s.yield_ty, &node_id), return_ty: self.resolve(&s.return_ty, &node_id), }); diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index fb1c9ea5a9246..05f5c4070d348 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1156,7 +1156,7 @@ fn type_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, NodeField(field) => icx.to_ty(&field.ty), NodeExpr(&hir::Expr { node: hir::ExprClosure(.., gen), .. }) => { - if gen.is_some() { + if gen == hir::IsGenerator::Yes { return tcx.typeck_tables_of(def_id).node_id_to_type(node_id); } diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index 45ae8df387b0f..b646678d7d2ec 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -4667,6 +4667,5 @@ register_diagnostics! { E0588, // packed struct cannot transitively contain a `[repr(align)]` struct E0592, // duplicate definitions with name `{}` // E0613, // Removed (merged with E0609) - E0625, // yield statement outside of generator literal - E0626, // gen arg expression outside of generator literal + E0623, // yield statement outside of generator literal } diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 1a2299bcf1f57..0128bf73a359a 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -984,9 +984,6 @@ pub enum ExprKind { /// A `yield`, with an optional value to be yielded Yield(Option>), - - /// A reference to the implicit argument of a generator - ImplArg, } /// The explicit Self type in a "qualified path". The actual diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 0f99761968ad7..bf19a7e038395 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -1335,11 +1335,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { e.span, "yield syntax is experimental"); } - ast::ExprKind::ImplArg => { - gate_feature_post!(&self, generators, - e.span, - "gen arg syntax is experimental"); - } ast::ExprKind::Lit(ref lit) => { if let ast::LitKind::Int(_, ref ty) = lit.node { match *ty { diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 4a86008bb336c..580c2aa58a5c3 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -1304,7 +1304,6 @@ pub fn noop_fold_expr(Expr {id, node, span, attrs}: Expr, folder: &mu }; } ExprKind::Yield(ex) => ExprKind::Yield(ex.map(|x| folder.fold_expr(x))), - ExprKind::ImplArg => ExprKind::ImplArg, ExprKind::Try(ex) => ExprKind::Try(folder.fold_expr(ex)), ExprKind::Catch(body) => ExprKind::Catch(folder.fold_block(body)), }, diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 6b825a9d4012e..b7ae025db5f7c 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -2146,12 +2146,6 @@ impl<'a> Parser<'a> { assert!(self.eat_keyword(keywords::Catch)); return self.parse_catch_expr(lo, attrs); } - if self.is_gen_arg() { - assert!(self.eat_keyword(keywords::Gen)); - assert!(self.eat_keyword(keywords::Arg)); - let hi = self.prev_span; - return Ok(self.mk_expr(lo.to(hi), ExprKind::ImplArg, attrs)); - } if self.eat_keyword(keywords::Return) { if self.token.can_begin_expr() { let e = self.parse_expr()?; @@ -3710,11 +3704,6 @@ impl<'a> Parser<'a> { self.look_ahead(1, |t| t.is_ident() && !t.is_reserved_ident()) } - fn is_gen_arg(&self) -> bool { - self.token.is_keyword(keywords::Gen) && - self.look_ahead(1, |t| t.is_keyword(keywords::Arg)) - } - fn is_defaultness(&self) -> bool { // `pub` is included for better error messages self.token.is_keyword(keywords::Default) && @@ -3818,8 +3807,7 @@ impl<'a> Parser<'a> { // Starts like a simple path, but not a union item. } else if self.token.is_path_start() && !self.token.is_qpath_start() && - !self.is_union_item() && - !self.is_gen_arg() { + !self.is_union_item() { let pth = self.parse_path(PathStyle::Expr)?; if !self.eat(&token::Not) { diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 1412f78b00d73..9e36fb83696a6 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -2290,9 +2290,6 @@ impl<'a> State<'a> { _ => () } } - ast::ExprKind::ImplArg => { - self.s.word("impl arg")?; - } ast::ExprKind::Try(ref e) => { self.print_expr(e)?; self.s.word("?")? diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index cd8a2f1534b93..05077d42a0bed 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -787,7 +787,6 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) { ExprKind::Yield(ref optional_expression) => { walk_list!(visitor, visit_expr, optional_expression); } - ExprKind::ImplArg => (), ExprKind::Try(ref subexpression) => { visitor.visit_expr(subexpression) } diff --git a/src/libsyntax_pos/symbol.rs b/src/libsyntax_pos/symbol.rs index 1123c33c0c28b..debac70545a99 100644 --- a/src/libsyntax_pos/symbol.rs +++ b/src/libsyntax_pos/symbol.rs @@ -307,8 +307,6 @@ declare_keywords! { (56, StaticLifetime, "'static") (57, Union, "union") (58, Catch, "catch") - (59, Arg, "arg") - (60, Gen, "gen") } // If an interner exists in TLS, return it. Otherwise, prepare a fresh one. diff --git a/src/test/compile-fail/feature-gate-generators.rs b/src/test/compile-fail/feature-gate-generators.rs index 8371ff4f57918..3754f92d8cde2 100644 --- a/src/test/compile-fail/feature-gate-generators.rs +++ b/src/test/compile-fail/feature-gate-generators.rs @@ -10,5 +10,4 @@ fn main() { yield true; //~ ERROR yield syntax is experimental - gen arg; //~ ERROR gen arg syntax is experimental } diff --git a/src/test/compile-fail/generator/borrowing.rs b/src/test/compile-fail/generator/borrowing.rs index ea2189d9f8117..0bbb212b09b6f 100644 --- a/src/test/compile-fail/generator/borrowing.rs +++ b/src/test/compile-fail/generator/borrowing.rs @@ -16,14 +16,13 @@ use std::cell::Cell; fn main() { let _b = { let a = 3; - (|| yield &a).resume(()) + (|| yield &a).resume() //~^ ERROR: `a` does not live long enough }; let _b = { let a = 3; || { - let _: () = gen arg; // FIXME: shouldn't be needed for inference yield &a //~^ ERROR: `a` does not live long enough } diff --git a/src/test/compile-fail/generator/no-arguments-on-generators.rs b/src/test/compile-fail/generator/no-arguments-on-generators.rs index 0f8d29e5cabb7..a7e98fe450927 100644 --- a/src/test/compile-fail/generator/no-arguments-on-generators.rs +++ b/src/test/compile-fail/generator/no-arguments-on-generators.rs @@ -14,4 +14,4 @@ fn main() { let gen = |start| { //~ ERROR generators cannot have explicit arguments yield; }; -} \ No newline at end of file +} diff --git a/src/test/compile-fail/generator/not-send-sync.rs b/src/test/compile-fail/generator/not-send-sync.rs index 6cfc8dd333ef3..31f80029b06b7 100644 --- a/src/test/compile-fail/generator/not-send-sync.rs +++ b/src/test/compile-fail/generator/not-send-sync.rs @@ -21,7 +21,6 @@ fn main() { //~^ ERROR: Sync` is not satisfied let a = Cell::new(2); yield; - let _: () = gen arg; }); let a = Cell::new(2); @@ -29,6 +28,5 @@ fn main() { //~^ ERROR: Sync` is not satisfied drop(&a); yield; - let _: () = gen arg; }); } diff --git a/src/test/compile-fail/generator/yield-in-const.rs b/src/test/compile-fail/generator/yield-in-const.rs index 5176f3c5f5687..e166d26515975 100644 --- a/src/test/compile-fail/generator/yield-in-const.rs +++ b/src/test/compile-fail/generator/yield-in-const.rs @@ -10,6 +10,5 @@ #![feature(generators)] -const A: u8 = { yield 3u8; gen arg; 3u8}; +const A: u8 = { yield 3u8; 3u8}; //~^ ERROR yield statement outside -//~| ERROR gen arg expression outside diff --git a/src/test/compile-fail/generator/yield-in-function.rs b/src/test/compile-fail/generator/yield-in-function.rs index 95ec1224421f2..2f6c5a9ef754c 100644 --- a/src/test/compile-fail/generator/yield-in-function.rs +++ b/src/test/compile-fail/generator/yield-in-function.rs @@ -10,6 +10,5 @@ #![feature(generators)] -fn main() { yield; gen arg; } +fn main() { yield; } //~^ ERROR yield statement outside -//~| ERROR gen arg expression outside diff --git a/src/test/compile-fail/generator/yield-in-static.rs b/src/test/compile-fail/generator/yield-in-static.rs index f4cad13ce8eb5..823a2aa425e2c 100644 --- a/src/test/compile-fail/generator/yield-in-static.rs +++ b/src/test/compile-fail/generator/yield-in-static.rs @@ -10,6 +10,5 @@ #![feature(generators)] -static B: u8 = { yield 3u8; gen arg; 3u8}; +static B: u8 = { yield 3u8; 3u8}; //~^ ERROR yield statement outside -//~| ERROR gen arg expression outside diff --git a/src/test/run-pass/generator/control-flow.rs b/src/test/run-pass/generator/control-flow.rs index 911bb96b5827e..d627e835c6303 100644 --- a/src/test/run-pass/generator/control-flow.rs +++ b/src/test/run-pass/generator/control-flow.rs @@ -13,10 +13,10 @@ use std::ops::{State, Generator}; fn finish(mut amt: usize, mut t: T) -> T::Return - where T: Generator<(), Yield = ()> + where T: Generator { loop { - match t.resume(()) { + match t.resume() { State::Yielded(()) => amt = amt.checked_sub(1).unwrap(), State::Complete(ret) => { assert_eq!(amt, 0); diff --git a/src/test/run-pass/generator/drop-env.rs b/src/test/run-pass/generator/drop-env.rs index be4e48f1f4cf8..ac42a25899dbb 100644 --- a/src/test/run-pass/generator/drop-env.rs +++ b/src/test/run-pass/generator/drop-env.rs @@ -37,7 +37,7 @@ fn t1() { }; let n = A.load(Ordering::SeqCst); - drop(foo.resume(())); + drop(foo.resume()); assert_eq!(A.load(Ordering::SeqCst), n); drop(foo); assert_eq!(A.load(Ordering::SeqCst), n + 1); @@ -50,7 +50,7 @@ fn t2() { }; let n = A.load(Ordering::SeqCst); - drop(foo.resume(())); + drop(foo.resume()); assert_eq!(A.load(Ordering::SeqCst), n + 1); drop(foo); assert_eq!(A.load(Ordering::SeqCst), n + 1); @@ -59,7 +59,6 @@ fn t2() { fn t3() { let b = B; let foo = || { - let _: () = gen arg; // FIXME: this line should not be necessary yield; drop(b); }; diff --git a/src/test/run-pass/generator/implicit-argument-dead-when-suspended.rs b/src/test/run-pass/generator/implicit-argument-dead-when-suspended.rs deleted file mode 100644 index 635d8fb3cdc63..0000000000000 --- a/src/test/run-pass/generator/implicit-argument-dead-when-suspended.rs +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![feature(generators, generator_trait)] - -use std::ops::Generator; -use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering}; - -static A: AtomicUsize = ATOMIC_USIZE_INIT; - -struct B; - -impl Drop for B { - fn drop(&mut self) { - A.fetch_add(1, Ordering::SeqCst); - } -} - -fn main() { - let b = B; - - let mut gen = || { - yield; - }; - - assert_eq!(A.load(Ordering::SeqCst), 0); - gen.resume(b); - assert_eq!(A.load(Ordering::SeqCst), 1); - drop(gen); - assert_eq!(A.load(Ordering::SeqCst), 1); -} diff --git a/src/test/run-pass/generator/iterator-count.rs b/src/test/run-pass/generator/iterator-count.rs index 45ba663873b61..8de0e71b85796 100644 --- a/src/test/run-pass/generator/iterator-count.rs +++ b/src/test/run-pass/generator/iterator-count.rs @@ -18,7 +18,7 @@ impl> Iterator for W { type Item = T::Yield; fn next(&mut self) -> Option { - match self.0.resume(()) { + match self.0.resume() { State::Complete(..) => None, State::Yielded(v) => Some(v), } diff --git a/src/test/run-pass/generator/panic-drops.rs b/src/test/run-pass/generator/panic-drops.rs index 6b9d7da197f10..4837f68be5eb2 100644 --- a/src/test/run-pass/generator/panic-drops.rs +++ b/src/test/run-pass/generator/panic-drops.rs @@ -36,7 +36,7 @@ fn main() { assert_eq!(A.load(Ordering::SeqCst), 0); let res = panic::catch_unwind(panic::AssertUnwindSafe(|| { - foo.resume(()) + foo.resume() })); assert!(res.is_err()); assert_eq!(A.load(Ordering::SeqCst), 1); @@ -51,7 +51,7 @@ fn main() { assert_eq!(A.load(Ordering::SeqCst), 1); let res = panic::catch_unwind(panic::AssertUnwindSafe(|| { - foo.resume(()) + foo.resume() })); assert!(res.is_err()); assert_eq!(A.load(Ordering::SeqCst), 1); diff --git a/src/test/run-pass/generator/panic-safe.rs b/src/test/run-pass/generator/panic-safe.rs index 7d86d7b6d94ae..a583f42b93d8c 100644 --- a/src/test/run-pass/generator/panic-safe.rs +++ b/src/test/run-pass/generator/panic-safe.rs @@ -22,13 +22,13 @@ fn main() { }; let res = panic::catch_unwind(panic::AssertUnwindSafe(|| { - foo.resume(()) + foo.resume() })); assert!(res.is_err()); for _ in 0..10 { let res = panic::catch_unwind(panic::AssertUnwindSafe(|| { - foo.resume(()) + foo.resume() })); assert!(res.is_err()); } diff --git a/src/test/run-pass/generator/resume-after-return.rs b/src/test/run-pass/generator/resume-after-return.rs index ca85d2545c822..d5f81d5eecd2e 100644 --- a/src/test/run-pass/generator/resume-after-return.rs +++ b/src/test/run-pass/generator/resume-after-return.rs @@ -21,12 +21,12 @@ fn main() { yield; }; - match foo.resume(()) { + match foo.resume() { State::Complete(()) => {} s => panic!("bad state: {:?}", s), } - match panic::catch_unwind(move || foo.resume(())) { + match panic::catch_unwind(move || foo.resume()) { Ok(_) => panic!("generator successfully resumed"), Err(_) => {} } diff --git a/src/test/run-pass/generator/smoke.rs b/src/test/run-pass/generator/smoke.rs index daa32aa3213e0..21c7b434d2a8c 100644 --- a/src/test/run-pass/generator/smoke.rs +++ b/src/test/run-pass/generator/smoke.rs @@ -23,7 +23,7 @@ fn simple() { } }; - match foo.resume(()) { + match foo.resume() { State::Complete(()) => {} s => panic!("bad state: {:?}", s), } @@ -39,7 +39,7 @@ fn return_capture() { a }; - match foo.resume(()) { + match foo.resume() { State::Complete(ref s) if *s == "foo" => {} s => panic!("bad state: {:?}", s), } @@ -51,11 +51,11 @@ fn simple_yield() { yield; }; - match foo.resume(()) { + match foo.resume() { State::Yielded(()) => {} s => panic!("bad state: {:?}", s), } - match foo.resume(()) { + match foo.resume() { State::Complete(()) => {} s => panic!("bad state: {:?}", s), } @@ -68,11 +68,11 @@ fn yield_capture() { yield b; }; - match foo.resume(()) { + match foo.resume() { State::Yielded(ref s) if *s == "foo" => {} s => panic!("bad state: {:?}", s), } - match foo.resume(()) { + match foo.resume() { State::Complete(()) => {} s => panic!("bad state: {:?}", s), } @@ -85,11 +85,11 @@ fn simple_yield_value() { return String::from("foo") }; - match foo.resume(()) { + match foo.resume() { State::Yielded(ref s) if *s == "bar" => {} s => panic!("bad state: {:?}", s), } - match foo.resume(()) { + match foo.resume() { State::Complete(ref s) if *s == "foo" => {} s => panic!("bad state: {:?}", s), } @@ -103,11 +103,11 @@ fn return_after_yield() { return a }; - match foo.resume(()) { + match foo.resume() { State::Yielded(()) => {} s => panic!("bad state: {:?}", s), } - match foo.resume(()) { + match foo.resume() { State::Complete(ref s) if *s == "foo" => {} s => panic!("bad state: {:?}", s), } @@ -116,40 +116,33 @@ fn return_after_yield() { #[test] fn send_and_sync() { assert_send_sync(|| { - let _: () = gen arg; yield }); assert_send_sync(|| { - let _: () = gen arg; yield String::from("foo"); }); assert_send_sync(|| { - let _: () = gen arg; yield; return String::from("foo"); }); let a = 3; assert_send_sync(|| { - let _: () = gen arg; yield a; return }); let a = 3; assert_send_sync(move || { - let _: () = gen arg; yield a; return }); let a = String::from("a"); assert_send_sync(|| { - let _: () = gen arg; yield ; drop(a); return }); let a = String::from("a"); assert_send_sync(move || { - let _: () = gen arg; yield ; drop(a); return @@ -162,11 +155,11 @@ fn send_and_sync() { fn send_over_threads() { let mut foo = || { yield }; thread::spawn(move || { - match foo.resume(()) { + match foo.resume() { State::Yielded(()) => {} s => panic!("bad state: {:?}", s), } - match foo.resume(()) { + match foo.resume() { State::Complete(()) => {} s => panic!("bad state: {:?}", s), } @@ -175,11 +168,11 @@ fn send_over_threads() { let a = String::from("a"); let mut foo = || { yield a }; thread::spawn(move || { - match foo.resume(()) { + match foo.resume() { State::Yielded(ref s) if *s == "a" => {} s => panic!("bad state: {:?}", s), } - match foo.resume(()) { + match foo.resume() { State::Complete(()) => {} s => panic!("bad state: {:?}", s), } From eea290d7fdbbf549ac3b245c295465c44d4cc118 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Sat, 15 Jul 2017 04:11:13 +0200 Subject: [PATCH 041/113] Convert to spaces --- src/test/compile-fail/generator/yield-in-args-rev.rs | 8 ++++---- src/test/compile-fail/generator/yield-in-args.rs | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/test/compile-fail/generator/yield-in-args-rev.rs b/src/test/compile-fail/generator/yield-in-args-rev.rs index 2fadbfeb9d88d..6d220abe2b516 100644 --- a/src/test/compile-fail/generator/yield-in-args-rev.rs +++ b/src/test/compile-fail/generator/yield-in-args-rev.rs @@ -15,10 +15,10 @@ fn foo(_a: (), _b: &bool) {} // Some examples that probably *could* be accepted, but which we reject for now. fn bar() { - || { - let b = true; - foo(yield, &b); - }; //~ ERROR `b` does not live long enough + || { + let b = true; + foo(yield, &b); + }; //~ ERROR `b` does not live long enough } fn main() { } diff --git a/src/test/compile-fail/generator/yield-in-args.rs b/src/test/compile-fail/generator/yield-in-args.rs index c719baa5e2a39..5c8d65067d69d 100644 --- a/src/test/compile-fail/generator/yield-in-args.rs +++ b/src/test/compile-fail/generator/yield-in-args.rs @@ -13,8 +13,8 @@ fn foo(_b: &bool, _a: ()) {} fn main() { - || { - let b = true; - foo(&b, yield); - }; //~ ERROR `b` does not live long enough + || { + let b = true; + foo(&b, yield); + }; //~ ERROR `b` does not live long enough } From cbdb18650e383fd49beb442ce02d006d0daf865c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Sat, 15 Jul 2017 04:30:16 +0200 Subject: [PATCH 042/113] Add some comments --- src/librustc_mir/util/liveness.rs | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/src/librustc_mir/util/liveness.rs b/src/librustc_mir/util/liveness.rs index c96e3ec057b48..27997b3abc3ac 100644 --- a/src/librustc_mir/util/liveness.rs +++ b/src/librustc_mir/util/liveness.rs @@ -8,10 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Liveness analysis. - -// FIXME: Make sure this analysis uses proper MIR semantics. Also find out what -// the MIR semantics are. +//! Liveness analysis which computes liveness of MIR local variables at the boundary of basic blocks use rustc::mir::*; use rustc::mir::visit::{LvalueContext, Visitor}; @@ -47,15 +44,31 @@ impl<'tcx> Visitor<'tcx> for BlockInfoVisitor { if let Lvalue::Local(local) = *lvalue { match context { LvalueContext::Store | + + // We let Call defined the result in both the success and unwind cases. + // This may not be right. LvalueContext::Call | + + // Storage live and storage dead aren't proper defines, but we can ignore + // values that come before them. LvalueContext::StorageLive | LvalueContext::StorageDead => { self.defs.add(&local); } LvalueContext::Projection(..) | + + // Borrows only consider their local used at the point of the borrow. + // This won't affect the results since we use this analysis for generators + // and we only care about the result at suspension points. Borrows cannot + // cross suspension points so this behavoir is unproblematic. LvalueContext::Borrow { .. } | + LvalueContext::Inspect | LvalueContext::Consume | + + // We consider drops to always be uses of locals. + // Drop eloboration should be run before this analysis otherwise + // the results might be too pessimistic. LvalueContext::Drop => { // Ignore uses which are already defined in this block if !self.pre_defs.contains(&local) { @@ -90,6 +103,7 @@ fn block<'tcx>(b: &BasicBlockData<'tcx>, locals: usize) -> BlockInfo { } } +// This gives the result of the liveness analysis at the boundary of basic blocks pub struct LivenessResult { pub ins: IndexVec, pub outs: IndexVec, From b744b1cfe35b6a5ea81d4a145616e7337378ab2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Sat, 15 Jul 2017 04:31:15 +0200 Subject: [PATCH 043/113] Convert to spaces --- src/test/run-pass/generator/yield-subtype.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/test/run-pass/generator/yield-subtype.rs b/src/test/run-pass/generator/yield-subtype.rs index 268add4974b0b..5ff070f311e01 100644 --- a/src/test/run-pass/generator/yield-subtype.rs +++ b/src/test/run-pass/generator/yield-subtype.rs @@ -14,10 +14,10 @@ fn bar<'a>() { let a: &'static str = "hi"; let b: &'a str = a; - || { - yield a; - yield b; - }; + || { + yield a; + yield b; + }; } fn main() {} \ No newline at end of file From e4fdbcbc9fdc7c3e1670e5c981acbf013ffa51bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Sat, 15 Jul 2017 04:33:45 +0200 Subject: [PATCH 044/113] Update FIXME --- src/librustc_typeck/check/closure.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index 0f68b15977848..7e7e1018f9776 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -32,7 +32,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { debug!("check_expr_closure(expr={:?},expected={:?})", expr, expected); - // FIXME: See if expected_kind here can impact generators + // FIXME: Should we adapt deduce_expectations_from_expected_type to work with + // generator traits? It looks like it's conservative to add support for this later. // It's always helpful for inference if we know the kind of // closure sooner rather than later, so first examine the expected From 14c747678e4514e5179173484d8fdfb12937f9f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Sat, 15 Jul 2017 06:15:40 +0200 Subject: [PATCH 045/113] Fix a string literal --- src/librustc_mir/transform/type_check.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_mir/transform/type_check.rs b/src/librustc_mir/transform/type_check.rs index 69f3d68df5718..fc923f1831c86 100644 --- a/src/librustc_mir/transform/type_check.rs +++ b/src/librustc_mir/transform/type_check.rs @@ -520,7 +520,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { if let Err(terr) = self.sub_types(value_ty, ty) { span_mirbug!(self, term, - "22 - type of yield value is {:?}, but the yield type is {:?}: {:?}", + "type of yield value is {:?}, but the yield type is {:?}: {:?}", value_ty, ty, terr); From 5a6e0694da97dad246f8112c757988163697a3a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Sat, 15 Jul 2017 08:15:33 +0200 Subject: [PATCH 046/113] Remove a FIXME and apply the same hack as closures --- src/librustc_typeck/check/mod.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 6125300fd2e6c..7d3cfb448ca63 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -2550,8 +2550,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } let is_closure = match arg.node { - // FIXME: Should this be applied for generators? - hir::ExprClosure(.., hir::IsGenerator::No) => true, + hir::ExprClosure(..) => true, _ => false }; From 188cdf499f5fd6fdce0382367944e0f2a56026f8 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sat, 15 Jul 2017 05:18:19 -0400 Subject: [PATCH 047/113] combine `bckerr_to_diag` and `note_and_explain_bckerr` --- src/librustc_borrowck/borrowck/mod.rs | 281 +++++++++++++------------- 1 file changed, 137 insertions(+), 144 deletions(-) diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index a0c9a311e05e5..0d321b095521c 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -506,9 +506,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { _ => { } } - let mut db = self.bckerr_to_diag(&err); - self.note_and_explain_bckerr(&mut db, err); - db.emit(); + self.report_bckerr(&err); } pub fn report_use_of_moved_value(&self, @@ -693,8 +691,8 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { self.tcx.sess.span_err_with_code(s, msg, code); } - fn bckerr_to_diag(&self, err: &BckError<'tcx>) -> DiagnosticBuilder<'a> { - let span = err.span.clone(); + fn report_bckerr(&self, err: &BckError<'tcx>) { + let error_span = err.span.clone(); match err.code { err_mutbl => { @@ -718,12 +716,12 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { } }; - match err.cause { + let mut db = match err.cause { MutabilityViolation => { - struct_span_err!(self.tcx.sess, span, E0594, "cannot assign to {}", descr) + struct_span_err!(self.tcx.sess, error_span, E0594, "cannot assign to {}", descr) } BorrowViolation(euv::ClosureCapture(_)) => { - struct_span_err!(self.tcx.sess, span, E0595, + struct_span_err!(self.tcx.sess, error_span, E0595, "closure cannot assign to {}", descr) } BorrowViolation(euv::OverloadedOperator) | @@ -733,30 +731,152 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { BorrowViolation(euv::AutoUnsafe) | BorrowViolation(euv::ForLoop) | BorrowViolation(euv::MatchDiscriminant) => { - struct_span_err!(self.tcx.sess, span, E0596, + struct_span_err!(self.tcx.sess, error_span, E0596, "cannot borrow {} as mutable", descr) } BorrowViolation(euv::ClosureInvocation) => { span_bug!(err.span, "err_mutbl with a closure invocation"); } - } + }; + + self.note_and_explain_mutbl_error(&mut db, &err, &error_span); + self.note_immutability_blame(&mut db, err.cmt.immutability_blame()); + db.emit(); } - err_out_of_scope(..) => { + err_out_of_scope(super_scope, sub_scope, cause) => { let msg = match opt_loan_path(&err.cmt) { None => "borrowed value".to_string(), Some(lp) => { format!("`{}`", self.loan_path_to_string(&lp)) } }; - struct_span_err!(self.tcx.sess, span, E0597, "{} does not live long enough", msg) + let mut db = struct_span_err!(self.tcx.sess, error_span, E0597, "{} does not live long enough", msg); + + let (value_kind, value_msg) = match err.cmt.cat { + mc::Categorization::Rvalue(..) => + ("temporary value", "temporary value created here"), + _ => + ("borrowed value", "borrow occurs here") + }; + + let is_closure = match cause { + euv::ClosureCapture(s) => { + // The primary span starts out as the closure creation point. + // Change the primary span here to highlight the use of the variable + // in the closure, because it seems more natural. Highlight + // closure creation point as a secondary span. + match db.span.primary_span() { + Some(primary) => { + db.span = MultiSpan::from_span(s); + db.span_label(primary, "capture occurs here"); + db.span_label(s, "does not live long enough"); + true + } + None => false + } + } + _ => { + db.span_label(error_span, "does not live long enough"); + false + } + }; + + let sub_span = self.region_end_span(sub_scope); + let super_span = self.region_end_span(super_scope); + + match (sub_span, super_span) { + (Some(s1), Some(s2)) if s1 == s2 => { + if !is_closure { + db.span = MultiSpan::from_span(s1); + db.span_label(error_span, value_msg); + let msg = match opt_loan_path(&err.cmt) { + None => value_kind.to_string(), + Some(lp) => { + format!("`{}`", self.loan_path_to_string(&lp)) + } + }; + db.span_label(s1, + format!("{} dropped here while still borrowed", msg)); + } else { + db.span_label(s1, format!("{} dropped before borrower", value_kind)); + } + db.note("values in a scope are dropped in the opposite order \ + they are created"); + } + (Some(s1), Some(s2)) if !is_closure => { + db.span = MultiSpan::from_span(s2); + db.span_label(error_span, value_msg); + let msg = match opt_loan_path(&err.cmt) { + None => value_kind.to_string(), + Some(lp) => { + format!("`{}`", self.loan_path_to_string(&lp)) + } + }; + db.span_label(s2, format!("{} dropped here while still borrowed", msg)); + db.span_label(s1, format!("{} needs to live until here", value_kind)); + } + _ => { + match sub_span { + Some(s) => { + db.span_label(s, format!("{} needs to live until here", + value_kind)); + } + None => { + self.tcx.note_and_explain_region( + &mut db, + "borrowed value must be valid for ", + sub_scope, + "..."); + } + } + match super_span { + Some(s) => { + db.span_label(s, format!("{} only lives until here", value_kind)); + } + None => { + self.tcx.note_and_explain_region( + &mut db, + "...but borrowed value is only valid for ", + super_scope, + ""); + } + } + } + } + + if let Some(_) = statement_scope_span(self.tcx, super_scope) { + db.note("consider using a `let` binding to increase its lifetime"); + } + + db.emit(); } - err_borrowed_pointer_too_short(..) => { + err_borrowed_pointer_too_short(loan_scope, ptr_scope) => { let descr = self.cmt_to_path_or_string(&err.cmt); - struct_span_err!(self.tcx.sess, span, E0598, - "lifetime of {} is too short to guarantee \ - its contents can be safely reborrowed", - descr) + let mut db = struct_span_err!(self.tcx.sess, error_span, E0598, + "lifetime of {} is too short to guarantee \ + its contents can be safely reborrowed", + descr); + + let descr = match opt_loan_path(&err.cmt) { + Some(lp) => { + format!("`{}`", self.loan_path_to_string(&lp)) + } + None => self.cmt_to_string(&err.cmt), + }; + self.tcx.note_and_explain_region( + &mut db, + &format!("{} would have to be valid for ", + descr), + loan_scope, + "..."); + self.tcx.note_and_explain_region( + &mut db, + &format!("...but {} is only valid for ", descr), + ptr_scope, + ""); + + db.emit(); } } } @@ -1013,133 +1133,6 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { } } - fn note_and_explain_bckerr(&self, db: &mut DiagnosticBuilder, err: BckError<'tcx>) { - let error_span = err.span.clone(); - match err.code { - err_mutbl => { - self.note_and_explain_mutbl_error(db, &err, &error_span); - self.note_immutability_blame(db, err.cmt.immutability_blame()); - } - err_out_of_scope(super_scope, sub_scope, cause) => { - let (value_kind, value_msg) = match err.cmt.cat { - mc::Categorization::Rvalue(..) => - ("temporary value", "temporary value created here"), - _ => - ("borrowed value", "borrow occurs here") - }; - - let is_closure = match cause { - euv::ClosureCapture(s) => { - // The primary span starts out as the closure creation point. - // Change the primary span here to highlight the use of the variable - // in the closure, because it seems more natural. Highlight - // closure creation point as a secondary span. - match db.span.primary_span() { - Some(primary) => { - db.span = MultiSpan::from_span(s); - db.span_label(primary, "capture occurs here"); - db.span_label(s, "does not live long enough"); - true - } - None => false - } - } - _ => { - db.span_label(error_span, "does not live long enough"); - false - } - }; - - let sub_span = self.region_end_span(sub_scope); - let super_span = self.region_end_span(super_scope); - - match (sub_span, super_span) { - (Some(s1), Some(s2)) if s1 == s2 => { - if !is_closure { - db.span = MultiSpan::from_span(s1); - db.span_label(error_span, value_msg); - let msg = match opt_loan_path(&err.cmt) { - None => value_kind.to_string(), - Some(lp) => { - format!("`{}`", self.loan_path_to_string(&lp)) - } - }; - db.span_label(s1, - format!("{} dropped here while still borrowed", msg)); - } else { - db.span_label(s1, format!("{} dropped before borrower", value_kind)); - } - db.note("values in a scope are dropped in the opposite order \ - they are created"); - } - (Some(s1), Some(s2)) if !is_closure => { - db.span = MultiSpan::from_span(s2); - db.span_label(error_span, value_msg); - let msg = match opt_loan_path(&err.cmt) { - None => value_kind.to_string(), - Some(lp) => { - format!("`{}`", self.loan_path_to_string(&lp)) - } - }; - db.span_label(s2, format!("{} dropped here while still borrowed", msg)); - db.span_label(s1, format!("{} needs to live until here", value_kind)); - } - _ => { - match sub_span { - Some(s) => { - db.span_label(s, format!("{} needs to live until here", - value_kind)); - } - None => { - self.tcx.note_and_explain_region( - db, - "borrowed value must be valid for ", - sub_scope, - "..."); - } - } - match super_span { - Some(s) => { - db.span_label(s, format!("{} only lives until here", value_kind)); - } - None => { - self.tcx.note_and_explain_region( - db, - "...but borrowed value is only valid for ", - super_scope, - ""); - } - } - } - } - - if let Some(_) = statement_scope_span(self.tcx, super_scope) { - db.note("consider using a `let` binding to increase its lifetime"); - } - } - - err_borrowed_pointer_too_short(loan_scope, ptr_scope) => { - let descr = match opt_loan_path(&err.cmt) { - Some(lp) => { - format!("`{}`", self.loan_path_to_string(&lp)) - } - None => self.cmt_to_string(&err.cmt), - }; - self.tcx.note_and_explain_region( - db, - &format!("{} would have to be valid for ", - descr), - loan_scope, - "..."); - self.tcx.note_and_explain_region( - db, - &format!("...but {} is only valid for ", descr), - ptr_scope, - ""); - } - } - } - fn note_and_explain_mutbl_error(&self, db: &mut DiagnosticBuilder, err: &BckError<'tcx>, error_span: &Span) { match err.cmt.note { From 3fdc3fa1ec091d4bec006e0201d29ce54dcbf430 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sat, 15 Jul 2017 06:52:49 -0400 Subject: [PATCH 048/113] change how we report `err_out_of_scope` borrowck errors Also, remove the explicit code detecting borrows over a yield. It turns out not to be necessary -- any such borrow winds up with a lifetime that is part of the generator type, and therefore which will outlive the generator expression itself, which yields an `err_out_of_scope`. So instead we intercept those errors and display them in a nicer way. --- src/librustc/middle/region.rs | 71 ++++++------- .../borrowck/gather_loans/mod.rs | 3 +- src/librustc_borrowck/borrowck/mod.rs | 99 ++++++++++++++++--- src/librustc_borrowck/diagnostics.rs | 76 ++++++++++++++ .../check/generator_interior.rs | 4 +- .../ref-escapes-but-not-over-yield.rs | 28 ++++++ .../ref-escapes-but-not-over-yield.stderr | 12 +++ .../generator/yield-in-args-rev.rs | 8 +- .../ui/generator/yield-in-args-rev.stderr | 10 ++ .../generator/yield-in-args.rs | 8 +- src/test/ui/generator/yield-in-args.stderr | 8 ++ .../generator/yield-while-iterating.rs} | 92 +++-------------- .../ui/generator/yield-while-iterating.stderr | 24 +++++ .../generator/yield-while-local-borrowed.rs | 56 +++++++++++ .../yield-while-local-borrowed.stderr | 18 ++++ .../generator/yield-while-ref-reborrowed.rs | 49 +++++++++ .../yield-while-ref-reborrowed.stderr | 16 +++ 17 files changed, 450 insertions(+), 132 deletions(-) create mode 100644 src/test/ui/generator/ref-escapes-but-not-over-yield.rs create mode 100644 src/test/ui/generator/ref-escapes-but-not-over-yield.stderr rename src/test/{compile-fail => ui}/generator/yield-in-args-rev.rs (86%) create mode 100644 src/test/ui/generator/yield-in-args-rev.stderr rename src/test/{compile-fail => ui}/generator/yield-in-args.rs (84%) create mode 100644 src/test/ui/generator/yield-in-args.stderr rename src/test/{compile-fail/generator/yield-during-borrow.rs => ui/generator/yield-while-iterating.rs} (50%) create mode 100644 src/test/ui/generator/yield-while-iterating.stderr create mode 100644 src/test/ui/generator/yield-while-local-borrowed.rs create mode 100644 src/test/ui/generator/yield-while-local-borrowed.stderr create mode 100644 src/test/ui/generator/yield-while-ref-reborrowed.rs create mode 100644 src/test/ui/generator/yield-while-ref-reborrowed.stderr diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index 269522e826920..ce9f9f1444f24 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -1143,7 +1143,7 @@ fn region_maps<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) Rc::new(maps) } -struct YieldFinder(bool); +struct YieldFinder(Option); impl<'tcx> Visitor<'tcx> for YieldFinder { fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> { @@ -1156,52 +1156,57 @@ impl<'tcx> Visitor<'tcx> for YieldFinder { fn visit_expr(&mut self, expr: &'tcx hir::Expr) { if let hir::ExprYield(..) = expr.node { - self.0 = true; + if self.0.is_none() { + self.0 = Some(expr.span); + } } intravisit::walk_expr(self, expr); } } -pub fn extent_has_yield<'a, 'gcx: 'a+'tcx, 'tcx: 'a>(tcx: TyCtxt<'a, 'gcx, 'tcx>, - extent: CodeExtent) -> bool { - let mut finder = YieldFinder(false); - - match extent { - CodeExtent::DestructionScope(node_id) | - CodeExtent::Misc(node_id) => { - match tcx.hir.get(node_id) { - Node::NodeItem(_) | - Node::NodeTraitItem(_) | - Node::NodeImplItem(_) => { - let body = tcx.hir.body(tcx.hir.body_owned_by(node_id)); - intravisit::walk_body(&mut finder, body); +impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { + /// Checks whether the given code extent contains a `yield`. If so, + /// returns `Some(span)` with the span of the "first" yield we find. + pub fn yield_in_extent(self, extent: CodeExtent) -> Option { + let mut finder = YieldFinder(None); + + match extent { + CodeExtent::DestructionScope(node_id) | + CodeExtent::Misc(node_id) => { + match self.hir.get(node_id) { + Node::NodeItem(_) | + Node::NodeTraitItem(_) | + Node::NodeImplItem(_) => { + let body = self.hir.body(self.hir.body_owned_by(node_id)); + intravisit::walk_body(&mut finder, body); + } + Node::NodeExpr(expr) => intravisit::walk_expr(&mut finder, expr), + Node::NodeStmt(stmt) => intravisit::walk_stmt(&mut finder, stmt), + Node::NodeBlock(block) => intravisit::walk_block(&mut finder, block), + _ => bug!(), } - Node::NodeExpr(expr) => intravisit::walk_expr(&mut finder, expr), - Node::NodeStmt(stmt) => intravisit::walk_stmt(&mut finder, stmt), - Node::NodeBlock(block) => intravisit::walk_block(&mut finder, block), - _ => bug!(), } - } - CodeExtent::CallSiteScope(body_id) | - CodeExtent::ParameterScope(body_id) => { - intravisit::walk_body(&mut finder, tcx.hir.body(body_id)) - } + CodeExtent::CallSiteScope(body_id) | + CodeExtent::ParameterScope(body_id) => { + intravisit::walk_body(&mut finder, self.hir.body(body_id)) + } - CodeExtent::Remainder(r) => { - if let Node::NodeBlock(block) = tcx.hir.get(r.block) { - for stmt in &block.stmts[(r.first_statement_index as usize + 1)..] { - intravisit::walk_stmt(&mut finder, stmt); + CodeExtent::Remainder(r) => { + if let Node::NodeBlock(block) = self.hir.get(r.block) { + for stmt in &block.stmts[(r.first_statement_index as usize + 1)..] { + intravisit::walk_stmt(&mut finder, stmt); + } + block.expr.as_ref().map(|e| intravisit::walk_expr(&mut finder, e)); + } else { + bug!() } - block.expr.as_ref().map(|e| intravisit::walk_expr(&mut finder, e)); - } else { - bug!() } } - } - finder.0 + finder.0 + } } pub fn provide(providers: &mut Providers) { diff --git a/src/librustc_borrowck/borrowck/gather_loans/mod.rs b/src/librustc_borrowck/borrowck/gather_loans/mod.rs index 21d6ebe568702..212ddb9a15cd4 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/mod.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/mod.rs @@ -48,9 +48,8 @@ pub fn gather_loans_in_fn<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, move_error_collector: move_error::MoveErrorCollector::new(), }; - let body = glcx.bccx.tcx.hir.body(body); euv::ExprUseVisitor::new(&mut glcx, bccx.tcx, param_env, &bccx.region_maps, bccx.tables) - .consume_body(body); + .consume_body(bccx.body); glcx.report_potential_errors(); let GatherLoanCtxt { all_loans, move_data, .. } = glcx; diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index 0d321b095521c..79dff50022802 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -98,9 +98,8 @@ fn borrowck<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, owner_def_id: DefId) { let body_id = tcx.hir.body_owned_by(owner_id); let tables = tcx.typeck_tables_of(owner_def_id); let region_maps = tcx.region_maps(owner_def_id); - let mut bccx = &mut BorrowckCtxt { tcx, tables, region_maps, owner_def_id }; - - let body = bccx.tcx.hir.body(body_id); + let body = tcx.hir.body(body_id); + let mut bccx = &mut BorrowckCtxt { tcx, tables, region_maps, owner_def_id, body }; // Eventually, borrowck will always read the MIR, but at the // moment we do not. So, for now, we always force MIR to be @@ -128,10 +127,9 @@ fn build_borrowck_dataflow_data<'a, 'tcx>(this: &mut BorrowckCtxt<'a, 'tcx>, { // Check the body of fn items. let tcx = this.tcx; - let body = tcx.hir.body(body_id); let id_range = { let mut visitor = intravisit::IdRangeComputingVisitor::new(&tcx.hir); - visitor.visit_body(body); + visitor.visit_body(this.body); visitor.result() }; let (all_loans, move_data) = @@ -140,7 +138,7 @@ fn build_borrowck_dataflow_data<'a, 'tcx>(this: &mut BorrowckCtxt<'a, 'tcx>, let mut loan_dfcx = DataFlowContext::new(this.tcx, "borrowck", - Some(body), + Some(this.body), cfg, LoanDataFlowOperator, id_range, @@ -151,13 +149,13 @@ fn build_borrowck_dataflow_data<'a, 'tcx>(this: &mut BorrowckCtxt<'a, 'tcx>, loan.kill_scope.node_id(), loan_idx); } loan_dfcx.add_kills_from_flow_exits(cfg); - loan_dfcx.propagate(cfg, body); + loan_dfcx.propagate(cfg, this.body); let flowed_moves = move_data::FlowedMoveData::new(move_data, this, cfg, id_range, - body); + this.body); AnalysisData { all_loans: all_loans, loans: loan_dfcx, @@ -176,7 +174,8 @@ pub fn build_borrowck_dataflow_data_for_fn<'a, 'tcx>( let owner_def_id = tcx.hir.local_def_id(owner_id); let tables = tcx.typeck_tables_of(owner_def_id); let region_maps = tcx.region_maps(owner_def_id); - let mut bccx = BorrowckCtxt { tcx, tables, region_maps, owner_def_id }; + let body = tcx.hir.body(body_id); + let mut bccx = BorrowckCtxt { tcx, tables, region_maps, owner_def_id, body }; let dataflow_data = build_borrowck_dataflow_data(&mut bccx, cfg, body_id); (bccx, dataflow_data) @@ -195,6 +194,8 @@ pub struct BorrowckCtxt<'a, 'tcx: 'a> { region_maps: Rc, owner_def_id: DefId, + + body: &'tcx hir::Body, } /////////////////////////////////////////////////////////////////////////// @@ -751,9 +752,85 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { format!("`{}`", self.loan_path_to_string(&lp)) } }; - let mut db = struct_span_err!(self.tcx.sess, error_span, E0597, "{} does not live long enough", msg); - let (value_kind, value_msg) = match err.cmt.cat { + // When you have a borrow that lives across a yield, + // that reference winds up captured in the generator + // type. Regionck then constraints it to live as long + // as the generator itself. If that borrow is borrowing + // data owned by the generator, this winds up resulting in + // an `err_out_of_scope` error: + // + // ``` + // { + // let g = || { + // let a = &3; // this borrow is forced to ... -+ + // yield (); // | + // println!("{}", a); // | + // }; // | + // } <----------------------... live until here --------+ + // ``` + // + // To detect this case, we look for cases where the + // `super_scope` (lifetime of the value) is within the + // body, but the `sub_scope` is not. + debug!("err_out_of_scope: self.body.is_generator = {:?}", + self.body.is_generator); + let maybe_borrow_across_yield = if self.body.is_generator { + let body_extent = region::CodeExtent::Misc(self.body.id().node_id); + debug!("err_out_of_scope: body_extent = {:?}", body_extent); + debug!("err_out_of_scope: super_scope = {:?}", super_scope); + debug!("err_out_of_scope: sub_scope = {:?}", sub_scope); + match (super_scope, sub_scope) { + (&ty::RegionKind::ReScope(value_extent), + &ty::RegionKind::ReScope(loan_extent)) => { + if { + // value_extent <= body_extent && + self.region_maps.is_subscope_of(value_extent, body_extent) && + // body_extent <= loan_extent + self.region_maps.is_subscope_of(body_extent, loan_extent) + } { + // We now know that this is a case + // that fits the bill described above: + // a borrow of something whose scope + // is within the generator, but the + // borrow is for a scope outside the + // generator. + // + // Now look within the scope of the of + // the value being borrowed (in the + // example above, that would be the + // block remainder that starts with + // `let a`) for a yield. We can cite + // that for the user. + self.tcx.yield_in_extent(value_extent) + } else { + None + } + } + _ => None, + } + } else { + None + }; + + if let Some(yield_span) = maybe_borrow_across_yield { + debug!("err_out_of_scope: opt_yield_span = {:?}", yield_span); + struct_span_err!(self.tcx.sess, + error_span, + E0624, + "borrow may still be in use when generator yields") + .span_label(yield_span, "possible yield occurs here") + .emit(); + return; + } + + let mut db = struct_span_err!(self.tcx.sess, + error_span, + E0597, + "{} does not live long enough", + msg); + + let (value_kind, value_msg) = match err.cmt.cat { mc::Categorization::Rvalue(..) => ("temporary value", "temporary value created here"), _ => diff --git a/src/librustc_borrowck/diagnostics.rs b/src/librustc_borrowck/diagnostics.rs index 38dcc73123691..14454267c99cc 100644 --- a/src/librustc_borrowck/diagnostics.rs +++ b/src/librustc_borrowck/diagnostics.rs @@ -1183,6 +1183,82 @@ x.x = Some(&y); ``` "##, +E0624: r##" +This error occurs because a borrow in a generator persists across a +yield point. + +```compile_fail,E0624 +let mut b = || { + let a = &3; // <-- This borrow... + yield (); // ...is still in scope here, when the yield occurs. + println!("{}", a); +}; +b.resume(); +``` + +At present, it is not permitted to have a yield that occurs while a +borrow is still in scope. To resolve this error, the borrow must +either be "contained" to a smaller scope that does not overlap the +yield or else eliminated in another way. So, for example, we might +resolve the previous example by removing the borrow and just storing +the integer by value: + +``` +let mut b = || { + let a = 3; + yield (); + println!("{}", a); +}; +b.resume(); +``` + +This is a very simple case, of course. In more complex cases, we may +wish to have more than one reference to the value that was borrowed -- +in those cases, something like the `Rc` or `Arc` types may be useful. + +This error also frequently arises with iteration: + +```compile_fail,E0624 +let mut b = || { + let v = vec![1,2,3]; + for &x in &v { // <-- borrow of `v` is still in scope... + yield x; // ...when this yield occurs. + } +}; +b.resume(); +``` + +Such cases can sometimes be resolved by iterating "by value" (or using +`into_iter()`) to avoid borrowing: + +``` +let mut b = || { + let v = vec![1,2,3]; + for x in v { // <-- Take ownership of the values instead! + yield x; // <-- Now yield is OK. + } +}; +b.resume(); +``` + +If taking ownership is not an option, using indices can work too: + +``` +let mut b = || { + let v = vec![1,2,3]; + let len = v.len(); // (*) + for i in 0..len { + let x = v[i]; // (*) + yield x; // <-- Now yield is OK. + } +}; +b.resume(); + +// (*) -- Unfortunately, these temporaries are currently required. +// See . +``` +"##, + } register_diagnostics! { diff --git a/src/librustc_typeck/check/generator_interior.rs b/src/librustc_typeck/check/generator_interior.rs index 44bd2c26b3723..148cf0ddbffcd 100644 --- a/src/librustc_typeck/check/generator_interior.rs +++ b/src/librustc_typeck/check/generator_interior.rs @@ -12,7 +12,7 @@ use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap}; use rustc::hir::{self, Body, Pat, PatKind, Expr}; use rustc::hir::def_id::DefId; use rustc::ty::Ty; -use rustc::middle::region::{RegionMaps, CodeExtent, extent_has_yield}; +use rustc::middle::region::{RegionMaps, CodeExtent}; use util::nodemap::FxHashSet; use std::rc::Rc; use super::FnCtxt; @@ -27,7 +27,7 @@ impl<'a, 'gcx, 'tcx> InteriorVisitor<'a, 'gcx, 'tcx> { fn record(&mut self, ty: Ty<'tcx>, scope: Option, expr: Option<&'tcx Expr>) { use syntax_pos::DUMMY_SP; - if scope.map(|s| extent_has_yield(self.fcx.tcx, s)).unwrap_or(true) { + if scope.map(|s| self.fcx.tcx.yield_in_extent(s).is_some()).unwrap_or(true) { if self.fcx.tcx.sess.verbose() { if let Some(s) = scope { self.fcx.tcx.sess.span_warn(s.span(&self.fcx.tcx.hir).unwrap_or(DUMMY_SP), diff --git a/src/test/ui/generator/ref-escapes-but-not-over-yield.rs b/src/test/ui/generator/ref-escapes-but-not-over-yield.rs new file mode 100644 index 0000000000000..8d77eb92a63f1 --- /dev/null +++ b/src/test/ui/generator/ref-escapes-but-not-over-yield.rs @@ -0,0 +1,28 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(generators, generator_trait)] + +use std::ops::{State, Generator}; +use std::cell::Cell; + +fn foo(x: &i32) { + // In this case, a reference to `b` escapes the generator, but not + // because of a yield. We see that there is no yield in the scope of + // `b` and give the more generic error message. + let mut a = &3; + let mut b = move || { + yield(); + let b = 5; + a = &b; //~ ERROR + }; +} + +fn main() { } diff --git a/src/test/ui/generator/ref-escapes-but-not-over-yield.stderr b/src/test/ui/generator/ref-escapes-but-not-over-yield.stderr new file mode 100644 index 0000000000000..e30d28c2db83b --- /dev/null +++ b/src/test/ui/generator/ref-escapes-but-not-over-yield.stderr @@ -0,0 +1,12 @@ +error[E0597]: `b` does not live long enough + --> $DIR/ref-escapes-but-not-over-yield.rs:25:5 + | +24 | a = &b; //~ ERROR + | - borrow occurs here +25 | }; + | ^ `b` dropped here while still borrowed +26 | } + | - borrowed value needs to live until here + +error: aborting due to previous error + diff --git a/src/test/compile-fail/generator/yield-in-args-rev.rs b/src/test/ui/generator/yield-in-args-rev.rs similarity index 86% rename from src/test/compile-fail/generator/yield-in-args-rev.rs rename to src/test/ui/generator/yield-in-args-rev.rs index 6d220abe2b516..0d2e9a85de1e6 100644 --- a/src/test/compile-fail/generator/yield-in-args-rev.rs +++ b/src/test/ui/generator/yield-in-args-rev.rs @@ -15,10 +15,10 @@ fn foo(_a: (), _b: &bool) {} // Some examples that probably *could* be accepted, but which we reject for now. fn bar() { - || { - let b = true; - foo(yield, &b); - }; //~ ERROR `b` does not live long enough + || { + let b = true; + foo(yield, &b); //~ ERROR + }; } fn main() { } diff --git a/src/test/ui/generator/yield-in-args-rev.stderr b/src/test/ui/generator/yield-in-args-rev.stderr new file mode 100644 index 0000000000000..8f30089fc71bf --- /dev/null +++ b/src/test/ui/generator/yield-in-args-rev.stderr @@ -0,0 +1,10 @@ +error[E0624]: borrow may still be in use when generator yields + --> $DIR/yield-in-args-rev.rs:20:15 + | +20 | \t\tfoo(yield, &b); //~ ERROR + | \t\t ----- ^ + | \t\t | + | \t\t possible yield occurs here + +error: aborting due to previous error + diff --git a/src/test/compile-fail/generator/yield-in-args.rs b/src/test/ui/generator/yield-in-args.rs similarity index 84% rename from src/test/compile-fail/generator/yield-in-args.rs rename to src/test/ui/generator/yield-in-args.rs index 5c8d65067d69d..c2fcfa5cdc207 100644 --- a/src/test/compile-fail/generator/yield-in-args.rs +++ b/src/test/ui/generator/yield-in-args.rs @@ -13,8 +13,8 @@ fn foo(_b: &bool, _a: ()) {} fn main() { - || { - let b = true; - foo(&b, yield); - }; //~ ERROR `b` does not live long enough + || { + let b = true; + foo(&b, yield); //~ ERROR + }; } diff --git a/src/test/ui/generator/yield-in-args.stderr b/src/test/ui/generator/yield-in-args.stderr new file mode 100644 index 0000000000000..e4c31ef36c969 --- /dev/null +++ b/src/test/ui/generator/yield-in-args.stderr @@ -0,0 +1,8 @@ +error[E0624]: borrow may still be in use when generator yields + --> $DIR/yield-in-args.rs:18:8 + | +18 | \t\tfoo(&b, yield); //~ ERROR + | \t\t ^ ----- possible yield occurs here + +error: aborting due to previous error + diff --git a/src/test/compile-fail/generator/yield-during-borrow.rs b/src/test/ui/generator/yield-while-iterating.rs similarity index 50% rename from src/test/compile-fail/generator/yield-during-borrow.rs rename to src/test/ui/generator/yield-while-iterating.rs index 46732ce6599a7..fd260339efb1b 100644 --- a/src/test/compile-fail/generator/yield-during-borrow.rs +++ b/src/test/ui/generator/yield-while-iterating.rs @@ -13,89 +13,16 @@ use std::ops::{State, Generator}; use std::cell::Cell; -fn borrow_local_inline() { - // Not OK to yield with a borrow of a temporary. - // - // (This error occurs because the region shows up in the type of - // `b` and gets extended by region inference.) - let mut b = move || { - let a = &3; - yield(); - println!("{}", a); - }; //~ ERROR E0597 - b.resume(); -} - -fn borrow_local_inline_done() { - // No error here -- `a` is not in scope at the point of `yield`. - let mut b = move || { - { - let a = &3; - } - yield(); - }; - b.resume(); -} - -fn borrow_local() { - // Not OK to yield with a borrow of a temporary. - // - // (This error occurs because the region shows up in the type of - // `b` and gets extended by region inference.) - let mut b = move || { - let a = 3; - { - let b = &a; - yield(); - println!("{}", b); - } - }; //~ ERROR E0597 - b.resume(); -} - -fn reborrow_shared_ref(x: &i32) { - // This is OK -- we have a borrow live over the yield, but it's of - // data that outlives the generator. - let mut b = move || { - let a = &*x; - yield(); - println!("{}", a); - }; - b.resume(); -} - -fn reborrow_mutable_ref(x: &mut i32) { - // This is OK -- we have a borrow live over the yield, but it's of - // data that outlives the generator. - let mut b = move || { - let a = &mut *x; - yield(); - println!("{}", a); - }; - b.resume(); -} - -fn reborrow_mutable_ref_2(x: &mut i32) { - // ...but not OK to go on using `x`. - let mut b = || { - let a = &mut *x; - yield(); - println!("{}", a); - }; - println!("{}", x); //~ ERROR E0501 - b.resume(); -} - fn yield_during_iter_owned_data(x: Vec) { // The generator owns `x`, so we error out when yielding with a // reference to it. This winds up becoming a rather confusing // regionck error -- in particular, we would freeze with the // reference in scope, and it doesn't live long enough. let _b = move || { - for p in &x { + for p in &x { //~ ERROR yield(); } - }; //~ ERROR E0597 + }; } fn yield_during_iter_borrowed_slice(x: &[i32]) { @@ -137,7 +64,20 @@ fn yield_during_iter_borrowed_slice_4() { yield p; } }; - println!("{}", x[0]); //~ ERROR cannot borrow `x` as immutable + println!("{}", x[0]); //~ ERROR + b.resume(); +} + +fn yield_during_range_iter() { + // Should be OK. + let mut b = || { + let v = vec![1,2,3]; + let len = v.len(); + for i in 0..len { + let x = v[i]; + yield x; + } + }; b.resume(); } diff --git a/src/test/ui/generator/yield-while-iterating.stderr b/src/test/ui/generator/yield-while-iterating.stderr new file mode 100644 index 0000000000000..775c36a3df406 --- /dev/null +++ b/src/test/ui/generator/yield-while-iterating.stderr @@ -0,0 +1,24 @@ +error[E0624]: borrow may still be in use when generator yields + --> $DIR/yield-while-iterating.rs:22:19 + | +22 | for p in &x { //~ ERROR + | ^ +23 | yield(); + | ------- possible yield occurs here + +error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable + --> $DIR/yield-while-iterating.rs:67:20 + | +62 | let mut b = || { + | -- mutable borrow occurs here +63 | for p in &mut x { + | - previous borrow occurs due to use of `x` in closure +... +67 | println!("{}", x[0]); //~ ERROR + | ^ immutable borrow occurs here +68 | b.resume(); +69 | } + | - mutable borrow ends here + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/generator/yield-while-local-borrowed.rs b/src/test/ui/generator/yield-while-local-borrowed.rs new file mode 100644 index 0000000000000..b3e6dedf29199 --- /dev/null +++ b/src/test/ui/generator/yield-while-local-borrowed.rs @@ -0,0 +1,56 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(generators, generator_trait)] + +use std::ops::{State, Generator}; +use std::cell::Cell; + +fn borrow_local_inline() { + // Not OK to yield with a borrow of a temporary. + // + // (This error occurs because the region shows up in the type of + // `b` and gets extended by region inference.) + let mut b = move || { + let a = &3; //~ ERROR + yield(); + println!("{}", a); + }; + b.resume(); +} + +fn borrow_local_inline_done() { + // No error here -- `a` is not in scope at the point of `yield`. + let mut b = move || { + { + let a = &3; + } + yield(); + }; + b.resume(); +} + +fn borrow_local() { + // Not OK to yield with a borrow of a temporary. + // + // (This error occurs because the region shows up in the type of + // `b` and gets extended by region inference.) + let mut b = move || { + let a = 3; + { + let b = &a; //~ ERROR + yield(); + println!("{}", b); + } + }; + b.resume(); +} + +fn main() { } diff --git a/src/test/ui/generator/yield-while-local-borrowed.stderr b/src/test/ui/generator/yield-while-local-borrowed.stderr new file mode 100644 index 0000000000000..1e333a33db62a --- /dev/null +++ b/src/test/ui/generator/yield-while-local-borrowed.stderr @@ -0,0 +1,18 @@ +error[E0624]: borrow may still be in use when generator yields + --> $DIR/yield-while-local-borrowed.rs:22:18 + | +22 | let a = &3; //~ ERROR + | ^ +23 | yield(); + | ------- possible yield occurs here + +error[E0624]: borrow may still be in use when generator yields + --> $DIR/yield-while-local-borrowed.rs:48:22 + | +48 | let b = &a; //~ ERROR + | ^ +49 | yield(); + | ------- possible yield occurs here + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/generator/yield-while-ref-reborrowed.rs b/src/test/ui/generator/yield-while-ref-reborrowed.rs new file mode 100644 index 0000000000000..7b6246b1578ed --- /dev/null +++ b/src/test/ui/generator/yield-while-ref-reborrowed.rs @@ -0,0 +1,49 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(generators, generator_trait)] + +use std::ops::{State, Generator}; +use std::cell::Cell; + +fn reborrow_shared_ref(x: &i32) { + // This is OK -- we have a borrow live over the yield, but it's of + // data that outlives the generator. + let mut b = move || { + let a = &*x; + yield(); + println!("{}", a); + }; + b.resume(); +} + +fn reborrow_mutable_ref(x: &mut i32) { + // This is OK -- we have a borrow live over the yield, but it's of + // data that outlives the generator. + let mut b = move || { + let a = &mut *x; + yield(); + println!("{}", a); + }; + b.resume(); +} + +fn reborrow_mutable_ref_2(x: &mut i32) { + // ...but not OK to go on using `x`. + let mut b = || { + let a = &mut *x; + yield(); + println!("{}", a); + }; + println!("{}", x); //~ ERROR + b.resume(); +} + +fn main() { } diff --git a/src/test/ui/generator/yield-while-ref-reborrowed.stderr b/src/test/ui/generator/yield-while-ref-reborrowed.stderr new file mode 100644 index 0000000000000..7269f72973701 --- /dev/null +++ b/src/test/ui/generator/yield-while-ref-reborrowed.stderr @@ -0,0 +1,16 @@ +error[E0501]: cannot borrow `x` as immutable because previous closure requires unique access + --> $DIR/yield-while-ref-reborrowed.rs:45:20 + | +40 | let mut b = || { + | -- closure construction occurs here +41 | let a = &mut *x; + | - previous borrow occurs due to use of `x` in closure +... +45 | println!("{}", x); //~ ERROR + | ^ borrow occurs here +46 | b.resume(); +47 | } + | - borrow from closure ends here + +error: aborting due to previous error + From f5ec50358a7d7a4313434e0726e63e1f08ee7cc3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Sat, 15 Jul 2017 21:28:42 +0200 Subject: [PATCH 049/113] Fix tidy errors --- src/librustc_borrowck/borrowck/mod.rs | 6 +++++- src/test/ui/generator/yield-in-args-rev.rs | 8 ++++---- src/test/ui/generator/yield-in-args.rs | 8 ++++---- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index 79dff50022802..820761603cd6a 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -719,7 +719,11 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { let mut db = match err.cause { MutabilityViolation => { - struct_span_err!(self.tcx.sess, error_span, E0594, "cannot assign to {}", descr) + struct_span_err!(self.tcx.sess, + error_span, + E0594, + "cannot assign to {}", + descr) } BorrowViolation(euv::ClosureCapture(_)) => { struct_span_err!(self.tcx.sess, error_span, E0595, diff --git a/src/test/ui/generator/yield-in-args-rev.rs b/src/test/ui/generator/yield-in-args-rev.rs index 0d2e9a85de1e6..fb0e68136f544 100644 --- a/src/test/ui/generator/yield-in-args-rev.rs +++ b/src/test/ui/generator/yield-in-args-rev.rs @@ -15,10 +15,10 @@ fn foo(_a: (), _b: &bool) {} // Some examples that probably *could* be accepted, but which we reject for now. fn bar() { - || { - let b = true; - foo(yield, &b); //~ ERROR - }; + || { + let b = true; + foo(yield, &b); //~ ERROR + }; } fn main() { } diff --git a/src/test/ui/generator/yield-in-args.rs b/src/test/ui/generator/yield-in-args.rs index c2fcfa5cdc207..faeb4b1feb28d 100644 --- a/src/test/ui/generator/yield-in-args.rs +++ b/src/test/ui/generator/yield-in-args.rs @@ -13,8 +13,8 @@ fn foo(_b: &bool, _a: ()) {} fn main() { - || { - let b = true; - foo(&b, yield); //~ ERROR - }; + || { + let b = true; + foo(&b, yield); //~ ERROR + }; } From 4628f8534f0bff482e22bc394e35934ff1573a26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Sat, 15 Jul 2017 22:40:46 +0200 Subject: [PATCH 050/113] Fix error message tests --- src/librustc_borrowck/diagnostics.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/librustc_borrowck/diagnostics.rs b/src/librustc_borrowck/diagnostics.rs index 14454267c99cc..69b07912e5711 100644 --- a/src/librustc_borrowck/diagnostics.rs +++ b/src/librustc_borrowck/diagnostics.rs @@ -1188,6 +1188,7 @@ This error occurs because a borrow in a generator persists across a yield point. ```compile_fail,E0624 +# #![feature(generators)] let mut b = || { let a = &3; // <-- This borrow... yield (); // ...is still in scope here, when the yield occurs. @@ -1204,6 +1205,7 @@ resolve the previous example by removing the borrow and just storing the integer by value: ``` +# #![feature(generators)] let mut b = || { let a = 3; yield (); @@ -1219,6 +1221,7 @@ in those cases, something like the `Rc` or `Arc` types may be useful. This error also frequently arises with iteration: ```compile_fail,E0624 +# #![feature(generators)] let mut b = || { let v = vec![1,2,3]; for &x in &v { // <-- borrow of `v` is still in scope... @@ -1232,6 +1235,7 @@ Such cases can sometimes be resolved by iterating "by value" (or using `into_iter()`) to avoid borrowing: ``` +# #![feature(generators)] let mut b = || { let v = vec![1,2,3]; for x in v { // <-- Take ownership of the values instead! @@ -1244,6 +1248,7 @@ b.resume(); If taking ownership is not an option, using indices can work too: ``` +# #![feature(generators)] let mut b = || { let v = vec![1,2,3]; let len = v.len(); // (*) From 0a8b81a568864c16a887cc3b82a39b4f15495d39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Sat, 15 Jul 2017 22:41:33 +0200 Subject: [PATCH 051/113] Ignore drop check bools when testing for legal generator types --- src/librustc/ich/impls_mir.rs | 1 + src/librustc/mir/mod.rs | 22 +++++++++++++++++++ src/librustc/mir/visit.rs | 1 + src/librustc_mir/build/matches/mod.rs | 1 + src/librustc_mir/build/mod.rs | 1 + src/librustc_mir/shim.rs | 1 + src/librustc_mir/transform/elaborate_drops.rs | 2 +- src/librustc_mir/transform/generator.rs | 6 ++++- src/librustc_mir/util/patch.rs | 7 ++++++ .../check/generator_interior.rs | 3 --- 10 files changed, 40 insertions(+), 5 deletions(-) diff --git a/src/librustc/ich/impls_mir.rs b/src/librustc/ich/impls_mir.rs index 63100f4c11a2c..9b9a6a0273e57 100644 --- a/src/librustc/ich/impls_mir.rs +++ b/src/librustc/ich/impls_mir.rs @@ -27,6 +27,7 @@ impl_stable_hash_for!(struct mir::LocalDecl<'tcx> { ty, name, source_info, + internal, is_user_variable }); impl_stable_hash_for!(struct mir::UpvarDecl { debug_name, by_ref }); diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index a255221c87156..7b71bc0e678a5 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -411,6 +411,10 @@ pub struct LocalDecl<'tcx> { /// True if this corresponds to a user-declared local variable. pub is_user_variable: bool, + /// True if this an internal local. + /// Such locals are not checked against the legal types in a generator. + pub internal: bool, + /// Type of this local. pub ty: Ty<'tcx>, @@ -436,6 +440,23 @@ impl<'tcx> LocalDecl<'tcx> { span, scope: ARGUMENT_VISIBILITY_SCOPE }, + internal: false, + is_user_variable: false + } + } + + /// Create a new `LocalDecl` for a internal temporary. + #[inline] + pub fn new_internal(ty: Ty<'tcx>, span: Span) -> Self { + LocalDecl { + mutability: Mutability::Mut, + ty, + name: None, + source_info: SourceInfo { + span, + scope: ARGUMENT_VISIBILITY_SCOPE + }, + internal: true, is_user_variable: false } } @@ -452,6 +473,7 @@ impl<'tcx> LocalDecl<'tcx> { span, scope: ARGUMENT_VISIBILITY_SCOPE }, + internal: false, name: None, // FIXME maybe we do want some name here? is_user_variable: false } diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs index 325c87fded61a..234583f7d791f 100644 --- a/src/librustc/mir/visit.rs +++ b/src/librustc/mir/visit.rs @@ -654,6 +654,7 @@ macro_rules! make_mir_visitor { ref $($mutability)* ty, name: _, ref $($mutability)* source_info, + internal: _, is_user_variable: _, } = *local_decl; diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs index 54f285480ab53..702fc89fa129a 100644 --- a/src/librustc_mir/build/matches/mod.rs +++ b/src/librustc_mir/build/matches/mod.rs @@ -712,6 +712,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { ty: var_ty.clone(), name: Some(name), source_info: source_info, + internal: false, is_user_variable: true, }); self.var_indices.insert(var_id, var); diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index d8d6c398b5195..7c65d50269f33 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -521,6 +521,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { span: pattern.map_or(self.fn_span, |pat| pat.span) }, name: name, + internal: false, is_user_variable: false, }); } diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs index bc04be18ac656..fee9ff854cd31 100644 --- a/src/librustc_mir/shim.rs +++ b/src/librustc_mir/shim.rs @@ -128,6 +128,7 @@ fn temp_decl(mutability: Mutability, ty: Ty, span: Span) -> LocalDecl { LocalDecl { mutability, ty, name: None, source_info: SourceInfo { scope: ARGUMENT_VISIBILITY_SCOPE, span }, + internal: false, is_user_variable: false } } diff --git a/src/librustc_mir/transform/elaborate_drops.rs b/src/librustc_mir/transform/elaborate_drops.rs index f5a2b1b974c3d..308a48677e58f 100644 --- a/src/librustc_mir/transform/elaborate_drops.rs +++ b/src/librustc_mir/transform/elaborate_drops.rs @@ -314,7 +314,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { let patch = &mut self.patch; debug!("create_drop_flag({:?})", self.mir.span); self.drop_flags.entry(index).or_insert_with(|| { - patch.new_temp(tcx.types.bool, span) + patch.new_internal(tcx.types.bool, span) }); } diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs index 603e9d1849f8a..524b76b2e6be9 100644 --- a/src/librustc_mir/transform/generator.rs +++ b/src/librustc_mir/transform/generator.rs @@ -263,6 +263,7 @@ fn replace_result_variable<'tcx>(ret_ty: Ty<'tcx>, ty: ret_ty, name: None, source_info, + internal: false, is_user_variable: false, }; let new_ret_local = Local::new(mir.local_decls.len()); @@ -314,7 +315,7 @@ fn compute_layout<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let allowed = tcx.erase_regions(&interior.as_slice()); for (local, decl) in mir.local_decls.iter_enumerated() { - if !live_locals.contains(&local) { + if !live_locals.contains(&local) || decl.internal { continue; } if !allowed.contains(&decl.ty) { @@ -340,6 +341,7 @@ fn compute_layout<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty: unit, name: None, source_info, + internal: false, is_user_variable: false, }; remap.insert(local, (var.ty, upvar_len + 1 + idx)); @@ -482,6 +484,7 @@ fn generate_drop<'a, 'tcx>( ty: tcx.mk_nil(), name: None, source_info, + internal: false, is_user_variable: false, }; @@ -496,6 +499,7 @@ fn generate_drop<'a, 'tcx>( }), name: None, source_info, + internal: false, is_user_variable: false, }; diff --git a/src/librustc_mir/util/patch.rs b/src/librustc_mir/util/patch.rs index ac121131eb999..3cf7858406787 100644 --- a/src/librustc_mir/util/patch.rs +++ b/src/librustc_mir/util/patch.rs @@ -101,6 +101,13 @@ impl<'tcx> MirPatch<'tcx> { Local::new(index as usize) } + pub fn new_internal(&mut self, ty: Ty<'tcx>, span: Span) -> Local { + let index = self.next_local; + self.next_local += 1; + self.new_locals.push(LocalDecl::new_internal(ty, span)); + Local::new(index as usize) + } + pub fn new_block(&mut self, data: BasicBlockData<'tcx>) -> BasicBlock { let block = BasicBlock::new(self.patch_map.len()); debug!("MirPatch: new_block: {:?}: {:?}", block, data); diff --git a/src/librustc_typeck/check/generator_interior.rs b/src/librustc_typeck/check/generator_interior.rs index 148cf0ddbffcd..f116620388f16 100644 --- a/src/librustc_typeck/check/generator_interior.rs +++ b/src/librustc_typeck/check/generator_interior.rs @@ -66,9 +66,6 @@ pub fn find_interior<'a, 'gcx, 'tcx>(fcx: &'a FnCtxt<'a, 'gcx, 'tcx>, }; intravisit::walk_body(&mut visitor, body); - // FIXME: Drop elaboration can insert bool types in the generator - visitor.types.insert(fcx.tcx.types.bool); - // Deduplicate types let set: FxHashSet<_> = visitor.types.into_iter() .map(|t| fcx.resolve_type_vars_if_possible(&t)) From 6106f6c5c15e11a8a4eb8e021bab48d1fd3d42c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Sat, 15 Jul 2017 23:32:52 +0200 Subject: [PATCH 052/113] Fix error message tests --- src/librustc_borrowck/diagnostics.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/librustc_borrowck/diagnostics.rs b/src/librustc_borrowck/diagnostics.rs index 69b07912e5711..f8511bc9c7dc1 100644 --- a/src/librustc_borrowck/diagnostics.rs +++ b/src/librustc_borrowck/diagnostics.rs @@ -1189,6 +1189,7 @@ yield point. ```compile_fail,E0624 # #![feature(generators)] +# use std::ops::Generator; let mut b = || { let a = &3; // <-- This borrow... yield (); // ...is still in scope here, when the yield occurs. @@ -1206,6 +1207,7 @@ the integer by value: ``` # #![feature(generators)] +# use std::ops::Generator; let mut b = || { let a = 3; yield (); @@ -1222,6 +1224,7 @@ This error also frequently arises with iteration: ```compile_fail,E0624 # #![feature(generators)] +# use std::ops::Generator; let mut b = || { let v = vec![1,2,3]; for &x in &v { // <-- borrow of `v` is still in scope... @@ -1236,6 +1239,7 @@ Such cases can sometimes be resolved by iterating "by value" (or using ``` # #![feature(generators)] +# use std::ops::Generator; let mut b = || { let v = vec![1,2,3]; for x in v { // <-- Take ownership of the values instead! @@ -1249,6 +1253,7 @@ If taking ownership is not an option, using indices can work too: ``` # #![feature(generators)] +# use std::ops::Generator; let mut b = || { let v = vec![1,2,3]; let len = v.len(); // (*) From b2d931abbb8a61751862e72d93ec8711aa0a5e75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Sun, 16 Jul 2017 00:28:57 +0200 Subject: [PATCH 053/113] Fix error message tests again --- src/librustc_borrowck/diagnostics.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/librustc_borrowck/diagnostics.rs b/src/librustc_borrowck/diagnostics.rs index f8511bc9c7dc1..3987799ceb618 100644 --- a/src/librustc_borrowck/diagnostics.rs +++ b/src/librustc_borrowck/diagnostics.rs @@ -1188,7 +1188,7 @@ This error occurs because a borrow in a generator persists across a yield point. ```compile_fail,E0624 -# #![feature(generators)] +# #![feature(generators, generator_trait)] # use std::ops::Generator; let mut b = || { let a = &3; // <-- This borrow... @@ -1206,7 +1206,7 @@ resolve the previous example by removing the borrow and just storing the integer by value: ``` -# #![feature(generators)] +# #![feature(generators, generator_trait)] # use std::ops::Generator; let mut b = || { let a = 3; @@ -1223,7 +1223,7 @@ in those cases, something like the `Rc` or `Arc` types may be useful. This error also frequently arises with iteration: ```compile_fail,E0624 -# #![feature(generators)] +# #![feature(generators, generator_trait)] # use std::ops::Generator; let mut b = || { let v = vec![1,2,3]; @@ -1238,7 +1238,7 @@ Such cases can sometimes be resolved by iterating "by value" (or using `into_iter()`) to avoid borrowing: ``` -# #![feature(generators)] +# #![feature(generators, generator_trait)] # use std::ops::Generator; let mut b = || { let v = vec![1,2,3]; @@ -1252,7 +1252,7 @@ b.resume(); If taking ownership is not an option, using indices can work too: ``` -# #![feature(generators)] +# #![feature(generators, generator_trait)] # use std::ops::Generator; let mut b = || { let v = vec![1,2,3]; From d32428bc5fd7fd344e31a2c878f5c516f729e497 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Sun, 16 Jul 2017 04:05:35 +0200 Subject: [PATCH 054/113] Remove tabs --- src/test/ui/generator/yield-in-args-rev.stderr | 8 ++++---- src/test/ui/generator/yield-in-args.stderr | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/test/ui/generator/yield-in-args-rev.stderr b/src/test/ui/generator/yield-in-args-rev.stderr index 8f30089fc71bf..ed0e2e1c97820 100644 --- a/src/test/ui/generator/yield-in-args-rev.stderr +++ b/src/test/ui/generator/yield-in-args-rev.stderr @@ -1,10 +1,10 @@ error[E0624]: borrow may still be in use when generator yields --> $DIR/yield-in-args-rev.rs:20:15 | -20 | \t\tfoo(yield, &b); //~ ERROR - | \t\t ----- ^ - | \t\t | - | \t\t possible yield occurs here +20 | foo(yield, &b); //~ ERROR + | ----- ^ + | | + | possible yield occurs here error: aborting due to previous error diff --git a/src/test/ui/generator/yield-in-args.stderr b/src/test/ui/generator/yield-in-args.stderr index e4c31ef36c969..18e91995a8def 100644 --- a/src/test/ui/generator/yield-in-args.stderr +++ b/src/test/ui/generator/yield-in-args.stderr @@ -1,8 +1,8 @@ error[E0624]: borrow may still be in use when generator yields --> $DIR/yield-in-args.rs:18:8 | -18 | \t\tfoo(&b, yield); //~ ERROR - | \t\t ^ ----- possible yield occurs here +18 | foo(&b, yield); //~ ERROR + | ^ ----- possible yield occurs here error: aborting due to previous error From 39478e8ab132be0b87ef5fc3bd3b32364d5ceb32 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sun, 16 Jul 2017 05:03:21 -0400 Subject: [PATCH 055/113] update references due to removing tabs --- src/test/ui/generator/yield-in-args-rev.stderr | 2 +- src/test/ui/generator/yield-in-args.stderr | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/ui/generator/yield-in-args-rev.stderr b/src/test/ui/generator/yield-in-args-rev.stderr index ed0e2e1c97820..eb7cc04b71ac3 100644 --- a/src/test/ui/generator/yield-in-args-rev.stderr +++ b/src/test/ui/generator/yield-in-args-rev.stderr @@ -1,5 +1,5 @@ error[E0624]: borrow may still be in use when generator yields - --> $DIR/yield-in-args-rev.rs:20:15 + --> $DIR/yield-in-args-rev.rs:20:21 | 20 | foo(yield, &b); //~ ERROR | ----- ^ diff --git a/src/test/ui/generator/yield-in-args.stderr b/src/test/ui/generator/yield-in-args.stderr index 18e91995a8def..7a7e92ac5fadf 100644 --- a/src/test/ui/generator/yield-in-args.stderr +++ b/src/test/ui/generator/yield-in-args.stderr @@ -1,5 +1,5 @@ error[E0624]: borrow may still be in use when generator yields - --> $DIR/yield-in-args.rs:18:8 + --> $DIR/yield-in-args.rs:18:14 | 18 | foo(&b, yield); //~ ERROR | ^ ----- possible yield occurs here From 62e210fb3c26ffcfd767e17698e0ba9ce76d3e4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Thu, 20 Jul 2017 01:15:58 +0200 Subject: [PATCH 056/113] Derive traits for State. --- src/libcore/ops/generator.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcore/ops/generator.rs b/src/libcore/ops/generator.rs index 44b9835daf5f2..5734e8008b7b9 100644 --- a/src/libcore/ops/generator.rs +++ b/src/libcore/ops/generator.rs @@ -13,7 +13,7 @@ /// This enum is returned from the `Generator::resume` method and indicates the /// possible return values of a generator. Currently this corresponds to either /// a suspension point (`Yielded`) or a termination point (`Complete`). -#[derive(Debug)] +#[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Debug, Hash)] #[cfg_attr(not(stage0), lang = "generator_state")] #[unstable(feature = "generator_trait", issue = "43122")] pub enum State { From df0496a620f1a6e322df9748c9843ee8d87a8bd6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Thu, 20 Jul 2017 01:16:12 +0200 Subject: [PATCH 057/113] Rename State to GeneratorState --- src/liballoc/boxed.rs | 4 ++-- src/libcore/ops/generator.rs | 6 +++--- src/libcore/ops/mod.rs | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index f9eeb74ea0035..17dc3d03aae0e 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -66,7 +66,7 @@ use core::hash::{self, Hash}; use core::iter::FusedIterator; use core::marker::{self, Unsize}; use core::mem; -use core::ops::{CoerceUnsized, Deref, DerefMut, Generator, State}; +use core::ops::{CoerceUnsized, Deref, DerefMut, Generator, GeneratorState}; use core::ops::{BoxPlace, Boxed, InPlace, Place, Placer}; use core::ptr::{self, Unique}; use core::convert::From; @@ -791,7 +791,7 @@ impl Generator for Box { type Yield = T::Yield; type Return = T::Return; - fn resume(&mut self) -> State { + fn resume(&mut self) -> GeneratorState { (**self).resume() } } diff --git a/src/libcore/ops/generator.rs b/src/libcore/ops/generator.rs index 5734e8008b7b9..a8217676653b2 100644 --- a/src/libcore/ops/generator.rs +++ b/src/libcore/ops/generator.rs @@ -16,7 +16,7 @@ #[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Debug, Hash)] #[cfg_attr(not(stage0), lang = "generator_state")] #[unstable(feature = "generator_trait", issue = "43122")] -pub enum State { +pub enum GeneratorState { /// The generator suspended with a value. /// /// This state indicates that a generator has been suspended, and typically @@ -116,7 +116,7 @@ pub trait Generator { /// been returned previously. While generator literals in the language are /// guaranteed to panic on resuming after `Complete`, this is not guaranteed /// for all implementations of the `Generator` trait. - fn resume(&mut self) -> State; + fn resume(&mut self) -> GeneratorState; } #[unstable(feature = "generator_trait", issue = "43122")] @@ -125,7 +125,7 @@ impl<'a, T> Generator for &'a mut T { type Yield = T::Yield; type Return = T::Return; - fn resume(&mut self) -> State { + fn resume(&mut self) -> GeneratorState { (**self).resume() } } diff --git a/src/libcore/ops/mod.rs b/src/libcore/ops/mod.rs index 0f415a60c807a..767b22e851eec 100644 --- a/src/libcore/ops/mod.rs +++ b/src/libcore/ops/mod.rs @@ -191,7 +191,7 @@ pub use self::range::{RangeInclusive, RangeToInclusive}; pub use self::try::Try; #[unstable(feature = "generator_trait", issue = "43122")] -pub use self::generator::{Generator, State}; +pub use self::generator::{Generator, GeneratorState}; #[unstable(feature = "placement_new_protocol", issue = "27779")] pub use self::place::{Place, Placer, InPlace, Boxed, BoxPlace}; From 5da9a8aa19c536c60a79145792926e23fcfb35a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Thu, 20 Jul 2017 05:17:07 +0200 Subject: [PATCH 058/113] Rename some variables in lowering.rs and add an error number for the error --- src/librustc/diagnostics.rs | 1 + src/librustc/hir/lowering.rs | 30 +++++++++++++++--------------- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index 3ce39b23b0f67..056c331cf64f4 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -2025,4 +2025,5 @@ register_diagnostics! { E0490, // a value of type `..` is borrowed for too long E0495, // cannot infer an appropriate lifetime due to conflicting requirements E0566, // conflicting representation hints + E0624, // generators cannot have explicit arguments } diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 32fa343e911ff..38f8e291f5488 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -623,12 +623,12 @@ impl<'a> LoweringContext<'a> { }))) } TyKind::Array(ref ty, ref length) => { - let body = self.lower_body(None, |this| this.lower_expr(length)); - hir::TyArray(self.lower_ty(ty), body) + let length = self.lower_body(None, |this| this.lower_expr(length)); + hir::TyArray(self.lower_ty(ty), length) } TyKind::Typeof(ref expr) => { - let body = self.lower_body(None, |this| this.lower_expr(expr)); - hir::TyTypeof(body) + let expr = self.lower_body(None, |this| this.lower_expr(expr)); + hir::TyTypeof(expr) } TyKind::TraitObject(ref bounds) => { let mut lifetime_bound = None; @@ -1299,14 +1299,14 @@ impl<'a> LoweringContext<'a> { hir::ItemUse(path, kind) } ItemKind::Static(ref t, m, ref e) => { - let body = self.lower_body(None, |this| this.lower_expr(e)); + let value = self.lower_body(None, |this| this.lower_expr(e)); hir::ItemStatic(self.lower_ty(t), self.lower_mutability(m), - body) + value) } ItemKind::Const(ref t, ref e) => { - let body = self.lower_body(None, |this| this.lower_expr(e)); - hir::ItemConst(self.lower_ty(t), body) + let value = self.lower_body(None, |this| this.lower_expr(e)); + hir::ItemConst(self.lower_ty(t), value) } ItemKind::Fn(ref decl, unsafety, constness, abi, ref generics, ref body) => { self.with_new_scopes(|this| { @@ -1416,7 +1416,7 @@ impl<'a> LoweringContext<'a> { } TraitItemKind::Method(ref sig, Some(ref body)) => { let body_id = this.lower_body(Some(&sig.decl), |this| { - let body = this.lower_block(body, false); + let body = this.lower_block(body, false); this.expr_block(body, ThinVec::new()) }); hir::TraitItemKind::Method(this.lower_method_sig(sig), @@ -1472,7 +1472,7 @@ impl<'a> LoweringContext<'a> { } ImplItemKind::Method(ref sig, ref body) => { let body_id = this.lower_body(Some(&sig.decl), |this| { - let body = this.lower_block(body, false); + let body = this.lower_block(body, false); this.expr_block(body, ThinVec::new()) }); hir::ImplItemKind::Method(this.lower_method_sig(sig), body_id) @@ -1846,8 +1846,8 @@ impl<'a> LoweringContext<'a> { } ExprKind::Repeat(ref expr, ref count) => { let expr = P(self.lower_expr(expr)); - let body = self.lower_body(None, |this| this.lower_expr(count)); - hir::ExprRepeat(expr, body) + let count = self.lower_body(None, |this| this.lower_expr(count)); + hir::ExprRepeat(expr, count) } ExprKind::Tup(ref elts) => { hir::ExprTup(elts.iter().map(|x| self.lower_expr(x)).collect()) @@ -1947,9 +1947,9 @@ impl<'a> LoweringContext<'a> { e }); if gen == hir::IsGenerator::Yes && !decl.inputs.is_empty() { - this.sess.span_fatal( - fn_decl_span, - &format!("generators cannot have explicit arguments")); + span_err!(this.sess, fn_decl_span, E0624, + "yield statement outside of generator literal"); + this.sess.abort_if_errors(); } hir::ExprClosure(this.lower_capture_clause(capture_clause), this.lower_fn_decl(decl), From 9a6a8668ae80351d9f3547771c0e8ffc325fc577 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Thu, 20 Jul 2017 05:44:41 +0200 Subject: [PATCH 059/113] Remove visit_body from YieldFinder --- src/librustc/middle/region.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index ce9f9f1444f24..63a9731e546ac 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -1150,10 +1150,6 @@ impl<'tcx> Visitor<'tcx> for YieldFinder { NestedVisitorMap::None } - fn visit_body(&mut self, _body: &'tcx hir::Body) { - // Closures don't execute - } - fn visit_expr(&mut self, expr: &'tcx hir::Expr) { if let hir::ExprYield(..) = expr.node { if self.0.is_none() { From 0f8897cc359030f3558930a967e11ea6fb005f8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Thu, 20 Jul 2017 05:52:41 +0200 Subject: [PATCH 060/113] Fix error code --- src/librustc/diagnostics.rs | 2 +- src/librustc/hir/lowering.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index 056c331cf64f4..1bc6422c596c3 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -2025,5 +2025,5 @@ register_diagnostics! { E0490, // a value of type `..` is borrowed for too long E0495, // cannot infer an appropriate lifetime due to conflicting requirements E0566, // conflicting representation hints - E0624, // generators cannot have explicit arguments + E0625, // generators cannot have explicit arguments } diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 38f8e291f5488..8a8b1317b39f4 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -1947,7 +1947,7 @@ impl<'a> LoweringContext<'a> { e }); if gen == hir::IsGenerator::Yes && !decl.inputs.is_empty() { - span_err!(this.sess, fn_decl_span, E0624, + span_err!(this.sess, fn_decl_span, E0625, "yield statement outside of generator literal"); this.sess.abort_if_errors(); } From 9556faca681493a9f1f77150e5c91b868f26d862 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Thu, 20 Jul 2017 08:06:21 +0200 Subject: [PATCH 061/113] Fix error message string --- src/librustc/hir/lowering.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 8a8b1317b39f4..c4a3fe8fa626e 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -1948,7 +1948,7 @@ impl<'a> LoweringContext<'a> { }); if gen == hir::IsGenerator::Yes && !decl.inputs.is_empty() { span_err!(this.sess, fn_decl_span, E0625, - "yield statement outside of generator literal"); + "generators cannot have explicit arguments"); this.sess.abort_if_errors(); } hir::ExprClosure(this.lower_capture_clause(capture_clause), From 93b9b1a2b1efa6ae0ab907ab3d1199400d8a077f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Thu, 20 Jul 2017 08:07:58 +0200 Subject: [PATCH 062/113] Fix tests --- src/test/compile-fail/generator/borrowing.rs | 3 +-- src/test/compile-fail/generator/not-send-sync.rs | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/test/compile-fail/generator/borrowing.rs b/src/test/compile-fail/generator/borrowing.rs index 0bbb212b09b6f..de10bdef4aee0 100644 --- a/src/test/compile-fail/generator/borrowing.rs +++ b/src/test/compile-fail/generator/borrowing.rs @@ -10,8 +10,7 @@ #![feature(generators, generator_trait)] -use std::ops::{State, Generator}; -use std::cell::Cell; +use std::ops::Generator; fn main() { let _b = { diff --git a/src/test/compile-fail/generator/not-send-sync.rs b/src/test/compile-fail/generator/not-send-sync.rs index 31f80029b06b7..0419758d8ea17 100644 --- a/src/test/compile-fail/generator/not-send-sync.rs +++ b/src/test/compile-fail/generator/not-send-sync.rs @@ -8,9 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(generators, generator_trait)] +#![feature(generators)] -use std::ops::{State, Generator}; use std::cell::Cell; fn main() { From ae1856cb9ea58cdbd9b910de3b0b0ac164092812 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Fri, 21 Jul 2017 05:54:01 +0200 Subject: [PATCH 063/113] Update rename State in docs --- .../src/language-features/generators.md | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/doc/unstable-book/src/language-features/generators.md b/src/doc/unstable-book/src/language-features/generators.md index a8d449382eec4..3b7b77e2c3ed8 100644 --- a/src/doc/unstable-book/src/language-features/generators.md +++ b/src/doc/unstable-book/src/language-features/generators.md @@ -28,7 +28,7 @@ A syntactical example of a generator is: ```rust #![feature(generators, generator_trait)] -use std::ops::{Generator, State}; +use std::ops::{Generator, GeneratorState}; fn main() { let mut generator = || { @@ -37,11 +37,11 @@ fn main() { }; match generator.resume() { - State::Yielded(1) => {} + GeneratorState::Yielded(1) => {} _ => panic!("unexpected value from resume"), } match generator.resume() { - State::Complete("foo") => {} + GeneratorState::Complete("foo") => {} _ => panic!("unexpected value from resume"), } } @@ -87,12 +87,12 @@ The `Generator` trait in `std::ops` currently looks like: ``` # #![feature(generator_trait)] -# use std::ops::State; +# use std::ops::GeneratorState; pub trait Generator { type Yield; type Return; - fn resume(&mut self) -> State; + fn resume(&mut self) -> GeneratorState; } ``` @@ -102,10 +102,10 @@ generator. This is typically the last expression in a generator's definition or any value passed to `return` in a generator. The `resume` function is the entry point for executing the `Generator` itself. -The return value of `resume`, `State`, looks like: +The return value of `resume`, `GeneratorState`, looks like: ``` -pub enum State { +pub enum GeneratorState { Yielded(Y), Complete(R), } @@ -185,7 +185,7 @@ This generator literal will compile down to something similar to: ```rust #![feature(generators, generator_trait)] -use std::ops::{Generator, State}; +use std::ops::{Generator, GeneratorState}; fn main() { let ret = "foo"; @@ -200,17 +200,17 @@ fn main() { type Yield = i32; type Return = &'static str; - fn resume(&mut self) -> State { + fn resume(&mut self) -> GeneratorState { use std::mem; match mem::replace(self, __Generator::Done) { __Generator::Start(s) => { *self = __Generator::Yield1(s); - State::Yielded(1) + GeneratorState::Yielded(1) } __Generator::Yield1(s) => { *self = __Generator::Done; - State::Complete(s) + GeneratorState::Complete(s) } __Generator::Done => { From be0a9b89583d712557268e9d813e5fac87846561 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Sat, 22 Jul 2017 04:20:46 +0200 Subject: [PATCH 064/113] Fix tests --- src/test/run-pass/generator/control-flow.rs | 6 ++-- src/test/run-pass/generator/iterator-count.rs | 6 ++-- .../run-pass/generator/resume-after-return.rs | 4 +-- src/test/run-pass/generator/smoke.rs | 30 +++++++++---------- 4 files changed, 23 insertions(+), 23 deletions(-) diff --git a/src/test/run-pass/generator/control-flow.rs b/src/test/run-pass/generator/control-flow.rs index d627e835c6303..60a00b4e46756 100644 --- a/src/test/run-pass/generator/control-flow.rs +++ b/src/test/run-pass/generator/control-flow.rs @@ -10,15 +10,15 @@ #![feature(generators, generator_trait)] -use std::ops::{State, Generator}; +use std::ops::{GeneratorState, Generator}; fn finish(mut amt: usize, mut t: T) -> T::Return where T: Generator { loop { match t.resume() { - State::Yielded(()) => amt = amt.checked_sub(1).unwrap(), - State::Complete(ret) => { + GeneratorState::Yielded(()) => amt = amt.checked_sub(1).unwrap(), + GeneratorState::Complete(ret) => { assert_eq!(amt, 0); return ret } diff --git a/src/test/run-pass/generator/iterator-count.rs b/src/test/run-pass/generator/iterator-count.rs index 8de0e71b85796..9afe95f9e865c 100644 --- a/src/test/run-pass/generator/iterator-count.rs +++ b/src/test/run-pass/generator/iterator-count.rs @@ -10,7 +10,7 @@ #![feature(generators, generator_trait, conservative_impl_trait)] -use std::ops::{State, Generator}; +use std::ops::{GeneratorState, Generator}; struct W(T); @@ -19,8 +19,8 @@ impl> Iterator for W { fn next(&mut self) -> Option { match self.0.resume() { - State::Complete(..) => None, - State::Yielded(v) => Some(v), + GeneratorState::Complete(..) => None, + GeneratorState::Yielded(v) => Some(v), } } } diff --git a/src/test/run-pass/generator/resume-after-return.rs b/src/test/run-pass/generator/resume-after-return.rs index d5f81d5eecd2e..b2e2a3e7e9d5b 100644 --- a/src/test/run-pass/generator/resume-after-return.rs +++ b/src/test/run-pass/generator/resume-after-return.rs @@ -10,7 +10,7 @@ #![feature(generators, generator_trait)] -use std::ops::{State, Generator}; +use std::ops::{GeneratorState, Generator}; use std::panic; fn main() { @@ -22,7 +22,7 @@ fn main() { }; match foo.resume() { - State::Complete(()) => {} + GeneratorState::Complete(()) => {} s => panic!("bad state: {:?}", s), } diff --git a/src/test/run-pass/generator/smoke.rs b/src/test/run-pass/generator/smoke.rs index 21c7b434d2a8c..48f1b688f2466 100644 --- a/src/test/run-pass/generator/smoke.rs +++ b/src/test/run-pass/generator/smoke.rs @@ -12,7 +12,7 @@ #![feature(generators, generator_trait)] -use std::ops::{State, Generator}; +use std::ops::{GeneratorState, Generator}; use std::thread; #[test] @@ -24,7 +24,7 @@ fn simple() { }; match foo.resume() { - State::Complete(()) => {} + GeneratorState::Complete(()) => {} s => panic!("bad state: {:?}", s), } } @@ -40,7 +40,7 @@ fn return_capture() { }; match foo.resume() { - State::Complete(ref s) if *s == "foo" => {} + GeneratorState::Complete(ref s) if *s == "foo" => {} s => panic!("bad state: {:?}", s), } } @@ -52,11 +52,11 @@ fn simple_yield() { }; match foo.resume() { - State::Yielded(()) => {} + GeneratorState::Yielded(()) => {} s => panic!("bad state: {:?}", s), } match foo.resume() { - State::Complete(()) => {} + GeneratorState::Complete(()) => {} s => panic!("bad state: {:?}", s), } } @@ -69,11 +69,11 @@ fn yield_capture() { }; match foo.resume() { - State::Yielded(ref s) if *s == "foo" => {} + GeneratorState::Yielded(ref s) if *s == "foo" => {} s => panic!("bad state: {:?}", s), } match foo.resume() { - State::Complete(()) => {} + GeneratorState::Complete(()) => {} s => panic!("bad state: {:?}", s), } } @@ -86,11 +86,11 @@ fn simple_yield_value() { }; match foo.resume() { - State::Yielded(ref s) if *s == "bar" => {} + GeneratorState::Yielded(ref s) if *s == "bar" => {} s => panic!("bad state: {:?}", s), } match foo.resume() { - State::Complete(ref s) if *s == "foo" => {} + GeneratorState::Complete(ref s) if *s == "foo" => {} s => panic!("bad state: {:?}", s), } } @@ -104,11 +104,11 @@ fn return_after_yield() { }; match foo.resume() { - State::Yielded(()) => {} + GeneratorState::Yielded(()) => {} s => panic!("bad state: {:?}", s), } match foo.resume() { - State::Complete(ref s) if *s == "foo" => {} + GeneratorState::Complete(ref s) if *s == "foo" => {} s => panic!("bad state: {:?}", s), } } @@ -156,11 +156,11 @@ fn send_over_threads() { let mut foo = || { yield }; thread::spawn(move || { match foo.resume() { - State::Yielded(()) => {} + GeneratorState::Yielded(()) => {} s => panic!("bad state: {:?}", s), } match foo.resume() { - State::Complete(()) => {} + GeneratorState::Complete(()) => {} s => panic!("bad state: {:?}", s), } }).join().unwrap(); @@ -169,11 +169,11 @@ fn send_over_threads() { let mut foo = || { yield a }; thread::spawn(move || { match foo.resume() { - State::Yielded(ref s) if *s == "a" => {} + GeneratorState::Yielded(ref s) if *s == "a" => {} s => panic!("bad state: {:?}", s), } match foo.resume() { - State::Complete(()) => {} + GeneratorState::Complete(()) => {} s => panic!("bad state: {:?}", s), } }).join().unwrap(); From ff996853feeb2f87608c49988553ff4e85f1c319 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 21 Jul 2017 20:48:46 -0700 Subject: [PATCH 065/113] Fix more tests with `GeneratorState` rename --- src/libcore/ops/generator.rs | 16 ++++++++-------- .../generator/ref-escapes-but-not-over-yield.rs | 2 +- src/test/ui/generator/yield-while-iterating.rs | 2 +- .../ui/generator/yield-while-local-borrowed.rs | 2 +- .../ui/generator/yield-while-ref-reborrowed.rs | 2 +- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/libcore/ops/generator.rs b/src/libcore/ops/generator.rs index a8217676653b2..798c182bc6e38 100644 --- a/src/libcore/ops/generator.rs +++ b/src/libcore/ops/generator.rs @@ -48,7 +48,7 @@ pub enum GeneratorState { /// ```rust /// #![feature(generators, generator_trait)] /// -/// use std::ops::{Generator, State}; +/// use std::ops::{Generator, GeneratorState}; /// /// fn main() { /// let mut generator = || { @@ -57,11 +57,11 @@ pub enum GeneratorState { /// }; /// /// match generator.resume() { -/// State::Yielded(1) => {} +/// GeneratorState::Yielded(1) => {} /// _ => panic!("unexpected return from resume"), /// } /// match generator.resume() { -/// State::Complete("foo") => {} +/// GeneratorState::Complete("foo") => {} /// _ => panic!("unexpected return from resume"), /// } /// } @@ -100,11 +100,11 @@ pub trait Generator { /// /// # Return value /// - /// The `State` enum returned from this function indicates what state the - /// generator is in upon returning. If the `Yielded` variant is returned - /// then the generator has reached a suspension point and a value has been - /// yielded out. Generators in this state are available for resumption at a - /// later point. + /// The `GeneratorState` enum returned from this function indicates what + /// state the generator is in upon returning. If the `Yielded` variant is + /// returned then the generator has reached a suspension point and a value + /// has been yielded out. Generators in this state are available for + /// resumption at a later point. /// /// If `Complete` is returned then the generator has completely finished /// with the value provided. It is invalid for the generator to be resumed diff --git a/src/test/ui/generator/ref-escapes-but-not-over-yield.rs b/src/test/ui/generator/ref-escapes-but-not-over-yield.rs index 8d77eb92a63f1..87edbb22baae1 100644 --- a/src/test/ui/generator/ref-escapes-but-not-over-yield.rs +++ b/src/test/ui/generator/ref-escapes-but-not-over-yield.rs @@ -10,7 +10,7 @@ #![feature(generators, generator_trait)] -use std::ops::{State, Generator}; +use std::ops::{GeneratorState, Generator}; use std::cell::Cell; fn foo(x: &i32) { diff --git a/src/test/ui/generator/yield-while-iterating.rs b/src/test/ui/generator/yield-while-iterating.rs index fd260339efb1b..bc53448cb08e6 100644 --- a/src/test/ui/generator/yield-while-iterating.rs +++ b/src/test/ui/generator/yield-while-iterating.rs @@ -10,7 +10,7 @@ #![feature(generators, generator_trait)] -use std::ops::{State, Generator}; +use std::ops::{GeneratorState, Generator}; use std::cell::Cell; fn yield_during_iter_owned_data(x: Vec) { diff --git a/src/test/ui/generator/yield-while-local-borrowed.rs b/src/test/ui/generator/yield-while-local-borrowed.rs index b3e6dedf29199..d21c86e88681e 100644 --- a/src/test/ui/generator/yield-while-local-borrowed.rs +++ b/src/test/ui/generator/yield-while-local-borrowed.rs @@ -10,7 +10,7 @@ #![feature(generators, generator_trait)] -use std::ops::{State, Generator}; +use std::ops::{GeneratorState, Generator}; use std::cell::Cell; fn borrow_local_inline() { diff --git a/src/test/ui/generator/yield-while-ref-reborrowed.rs b/src/test/ui/generator/yield-while-ref-reborrowed.rs index 7b6246b1578ed..b9c963ae74077 100644 --- a/src/test/ui/generator/yield-while-ref-reborrowed.rs +++ b/src/test/ui/generator/yield-while-ref-reborrowed.rs @@ -10,7 +10,7 @@ #![feature(generators, generator_trait)] -use std::ops::{State, Generator}; +use std::ops::{GeneratorState, Generator}; use std::cell::Cell; fn reborrow_shared_ref(x: &i32) { From 416096d0fdb642058e9a21b7b70ce1380a787c4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Tue, 25 Jul 2017 08:31:02 +0200 Subject: [PATCH 066/113] Update comment --- src/librustc_mir/transform/generator.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs index 524b76b2e6be9..dc86bc6818def 100644 --- a/src/librustc_mir/transform/generator.rs +++ b/src/librustc_mir/transform/generator.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Transforming generator bodies into a state machines +//! Transforms generators into state machines #![allow(warnings)] From 9285a61413c8872e912ad7fbb147db0d098afc0b Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 28 Jul 2017 13:09:33 -0700 Subject: [PATCH 067/113] Remove `IsGenerator` in favor of a boolean No need to be mixed! --- src/librustc/hir/lowering.rs | 18 +++++++++--------- src/librustc/hir/mod.rs | 11 +++-------- src/librustc/ich/impls_hir.rs | 5 ----- src/librustc/mir/visit.rs | 2 +- src/librustc_mir/hair/cx/expr.rs | 4 ++-- src/librustc_typeck/check/upvar.rs | 4 ++-- src/librustc_typeck/collect.rs | 4 ++-- 7 files changed, 19 insertions(+), 29 deletions(-) diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index c4a3fe8fa626e..cd2bb32bbf866 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -92,7 +92,7 @@ pub struct LoweringContext<'a> { trait_impls: BTreeMap>, trait_default_impl: BTreeMap, - is_generator: hir::IsGenerator, + is_generator: bool, catch_scopes: Vec, loop_scopes: Vec, @@ -146,7 +146,7 @@ pub fn lower_crate(sess: &Session, current_hir_id_owner: vec![(CRATE_DEF_INDEX, 0)], item_local_id_counters: NodeMap(), node_id_to_hir_id: IndexVec::new(), - is_generator: hir::IsGenerator::No, + is_generator: false, }.lower_crate(krate) } @@ -371,7 +371,7 @@ impl<'a> LoweringContext<'a> { arguments: decl.map_or(hir_vec![], |decl| { decl.inputs.iter().map(|x| self.lower_arg(x)).collect() }), - is_generator: self.is_generator == hir::IsGenerator::Yes, + is_generator: self.is_generator, value, }; let id = body.id(); @@ -432,7 +432,7 @@ impl<'a> LoweringContext<'a> { fn lower_body(&mut self, decl: Option<&FnDecl>, f: F) -> hir::BodyId where F: FnOnce(&mut LoweringContext) -> hir::Expr { - let prev = mem::replace(&mut self.is_generator, hir::IsGenerator::No); + let prev = mem::replace(&mut self.is_generator, false); let result = f(self); let r = self.record_body(result, decl); self.is_generator = prev; @@ -1940,13 +1940,13 @@ impl<'a> LoweringContext<'a> { ExprKind::Closure(capture_clause, ref decl, ref body, fn_decl_span) => { self.with_new_scopes(|this| { this.with_parent_def(e.id, |this| { - let mut gen = hir::IsGenerator::No; + let mut is_generator = false; let body_id = this.lower_body(Some(decl), |this| { let e = this.lower_expr(body); - gen = this.is_generator; + is_generator = this.is_generator; e }); - if gen == hir::IsGenerator::Yes && !decl.inputs.is_empty() { + if is_generator && !decl.inputs.is_empty() { span_err!(this.sess, fn_decl_span, E0625, "generators cannot have explicit arguments"); this.sess.abort_if_errors(); @@ -1955,7 +1955,7 @@ impl<'a> LoweringContext<'a> { this.lower_fn_decl(decl), body_id, fn_decl_span, - gen) + is_generator) }) }) } @@ -2092,7 +2092,7 @@ impl<'a> LoweringContext<'a> { } ExprKind::Yield(ref opt_expr) => { - self.is_generator = hir::IsGenerator::Yes; + self.is_generator = true; let expr = opt_expr.as_ref().map(|x| self.lower_expr(x)).unwrap_or_else(|| { self.expr(e.span, hir::ExprTup(hir_vec![]), ThinVec::new()) }); diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 8fb7ca643a7c9..d1cc6b5d3e4a6 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -1013,8 +1013,9 @@ pub enum Expr_ { /// /// The final span is the span of the argument block `|...|` /// - /// This may also be a generator literal, in that case there is an GeneratorClause. - ExprClosure(CaptureClause, P, BodyId, Span, IsGenerator), + /// This may also be a generator literal, indicated by the final boolean, + /// in that case there is an GeneratorClause. + ExprClosure(CaptureClause, P, BodyId, Span, bool), /// A block (`{ ... }`) ExprBlock(P), @@ -1190,12 +1191,6 @@ pub struct Destination { pub target_id: ScopeTarget, } -#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)] -pub enum IsGenerator { - Yes, - No, -} - #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)] pub enum CaptureClause { CaptureByValue, diff --git a/src/librustc/ich/impls_hir.rs b/src/librustc/ich/impls_hir.rs index 04e8cbeb7ff9f..140c9c6ae9a1b 100644 --- a/src/librustc/ich/impls_hir.rs +++ b/src/librustc/ich/impls_hir.rs @@ -688,11 +688,6 @@ impl<'a, 'gcx, 'tcx> HashStable> for hir::M } } -impl_stable_hash_for!(enum hir::IsGenerator { - Yes, - No -}); - impl_stable_hash_for!(enum hir::CaptureClause { CaptureByValue, CaptureByRef diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs index 9c018026092f9..903d70add6ffd 100644 --- a/src/librustc/mir/visit.rs +++ b/src/librustc/mir/visit.rs @@ -560,7 +560,7 @@ macro_rules! make_mir_visitor { AggregateKind::Generator(ref $($mutability)* def_id, ref $($mutability)* closure_substs) => { self.visit_def_id(def_id, location); - self.visit_closure_substs(closure_substs); + self.visit_closure_substs(closure_substs, location); } } diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index 338c46a4c93b7..9b3585fff58b3 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -428,7 +428,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, } } - hir::ExprClosure(.., gen) => { + hir::ExprClosure(.., is_generator) => { let closure_ty = cx.tables().expr_ty(expr); let (def_id, substs) = match closure_ty.sty { ty::TyClosure(def_id, substs) | @@ -447,7 +447,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, closure_id: def_id, substs: substs, upvars: upvars, - generator: gen == hir::IsGenerator::Yes, + generator: is_generator, } } diff --git a/src/librustc_typeck/check/upvar.rs b/src/librustc_typeck/check/upvar.rs index ffaf6afb6e8d7..70325ee3a9333 100644 --- a/src/librustc_typeck/check/upvar.rs +++ b/src/librustc_typeck/check/upvar.rs @@ -75,11 +75,11 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for InferBorrowKindVisitor<'a, 'gcx, 'tcx> { fn visit_expr(&mut self, expr: &'gcx hir::Expr) { match expr.node { - hir::ExprClosure(cc, _, body_id, _, gen) => { + hir::ExprClosure(cc, _, body_id, _, is_generator) => { let body = self.fcx.tcx.hir.body(body_id); self.visit_body(body); self.fcx.analyze_closure(expr.id, expr.span, body, cc, - gen == hir::IsGenerator::Yes); + is_generator); } _ => { } diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 05f5c4070d348..d1ba9fd091827 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1155,8 +1155,8 @@ fn type_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, NodeField(field) => icx.to_ty(&field.ty), - NodeExpr(&hir::Expr { node: hir::ExprClosure(.., gen), .. }) => { - if gen == hir::IsGenerator::Yes { + NodeExpr(&hir::Expr { node: hir::ExprClosure(.., is_generator), .. }) => { + if is_generator { return tcx.typeck_tables_of(def_id).node_id_to_type(node_id); } From cc4ff8f4d169562ff4ae22b94197a191215e6d56 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Sat, 29 Jul 2017 09:05:50 -0700 Subject: [PATCH 068/113] Use a free error code --- src/librustc_borrowck/borrowck/mod.rs | 2 +- src/librustc_borrowck/diagnostics.rs | 6 +++--- src/librustc_typeck/check/mod.rs | 2 +- src/librustc_typeck/diagnostics.rs | 2 +- src/test/ui/generator/yield-in-args-rev.stderr | 2 +- src/test/ui/generator/yield-in-args.stderr | 2 +- src/test/ui/generator/yield-while-iterating.stderr | 2 +- src/test/ui/generator/yield-while-local-borrowed.stderr | 4 ++-- 8 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index 820761603cd6a..0016c406b375f 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -821,7 +821,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { debug!("err_out_of_scope: opt_yield_span = {:?}", yield_span); struct_span_err!(self.tcx.sess, error_span, - E0624, + E0626, "borrow may still be in use when generator yields") .span_label(yield_span, "possible yield occurs here") .emit(); diff --git a/src/librustc_borrowck/diagnostics.rs b/src/librustc_borrowck/diagnostics.rs index 3987799ceb618..5d8998b332dc6 100644 --- a/src/librustc_borrowck/diagnostics.rs +++ b/src/librustc_borrowck/diagnostics.rs @@ -1183,11 +1183,11 @@ x.x = Some(&y); ``` "##, -E0624: r##" +E0626: r##" This error occurs because a borrow in a generator persists across a yield point. -```compile_fail,E0624 +```compile_fail,E0626 # #![feature(generators, generator_trait)] # use std::ops::Generator; let mut b = || { @@ -1222,7 +1222,7 @@ in those cases, something like the `Rc` or `Arc` types may be useful. This error also frequently arises with iteration: -```compile_fail,E0624 +```compile_fail,E0626 # #![feature(generators, generator_trait)] # use std::ops::Generator; let mut b = || { diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 7d3cfb448ca63..67ffca69efaff 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -3975,7 +3975,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.check_expr_coercable_to_type(&value, ty); } None => { - struct_span_err!(self.tcx.sess, expr.span, E0623, + struct_span_err!(self.tcx.sess, expr.span, E0624, "yield statement outside of generator literal").emit(); } } diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index b646678d7d2ec..7c410b111c2f0 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -4667,5 +4667,5 @@ register_diagnostics! { E0588, // packed struct cannot transitively contain a `[repr(align)]` struct E0592, // duplicate definitions with name `{}` // E0613, // Removed (merged with E0609) - E0623, // yield statement outside of generator literal + E0624, // yield statement outside of generator literal } diff --git a/src/test/ui/generator/yield-in-args-rev.stderr b/src/test/ui/generator/yield-in-args-rev.stderr index eb7cc04b71ac3..157f896820906 100644 --- a/src/test/ui/generator/yield-in-args-rev.stderr +++ b/src/test/ui/generator/yield-in-args-rev.stderr @@ -1,4 +1,4 @@ -error[E0624]: borrow may still be in use when generator yields +error[E0626]: borrow may still be in use when generator yields --> $DIR/yield-in-args-rev.rs:20:21 | 20 | foo(yield, &b); //~ ERROR diff --git a/src/test/ui/generator/yield-in-args.stderr b/src/test/ui/generator/yield-in-args.stderr index 7a7e92ac5fadf..06561853dee8c 100644 --- a/src/test/ui/generator/yield-in-args.stderr +++ b/src/test/ui/generator/yield-in-args.stderr @@ -1,4 +1,4 @@ -error[E0624]: borrow may still be in use when generator yields +error[E0626]: borrow may still be in use when generator yields --> $DIR/yield-in-args.rs:18:14 | 18 | foo(&b, yield); //~ ERROR diff --git a/src/test/ui/generator/yield-while-iterating.stderr b/src/test/ui/generator/yield-while-iterating.stderr index 775c36a3df406..ea55e032e4761 100644 --- a/src/test/ui/generator/yield-while-iterating.stderr +++ b/src/test/ui/generator/yield-while-iterating.stderr @@ -1,4 +1,4 @@ -error[E0624]: borrow may still be in use when generator yields +error[E0626]: borrow may still be in use when generator yields --> $DIR/yield-while-iterating.rs:22:19 | 22 | for p in &x { //~ ERROR diff --git a/src/test/ui/generator/yield-while-local-borrowed.stderr b/src/test/ui/generator/yield-while-local-borrowed.stderr index 1e333a33db62a..46363e5919d37 100644 --- a/src/test/ui/generator/yield-while-local-borrowed.stderr +++ b/src/test/ui/generator/yield-while-local-borrowed.stderr @@ -1,4 +1,4 @@ -error[E0624]: borrow may still be in use when generator yields +error[E0626]: borrow may still be in use when generator yields --> $DIR/yield-while-local-borrowed.rs:22:18 | 22 | let a = &3; //~ ERROR @@ -6,7 +6,7 @@ error[E0624]: borrow may still be in use when generator yields 23 | yield(); | ------- possible yield occurs here -error[E0624]: borrow may still be in use when generator yields +error[E0626]: borrow may still be in use when generator yields --> $DIR/yield-while-local-borrowed.rs:48:22 | 48 | let b = &a; //~ ERROR From 352577f4bb7c0214570db062d84dc69004348769 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 9 Aug 2017 13:56:19 -0700 Subject: [PATCH 069/113] Initial pass review comments --- src/librustc/ich/impls_ty.rs | 2 +- src/librustc/mir/mod.rs | 7 +- src/librustc/traits/select.rs | 2 +- src/librustc/ty/flags.rs | 2 +- src/librustc/ty/outlives.rs | 2 +- src/librustc/ty/relate.rs | 2 +- src/librustc/ty/structural_impls.rs | 8 +- src/librustc/ty/sty.rs | 14 +-- src/librustc/ty/util.rs | 2 +- src/librustc/ty/walk.rs | 2 +- src/librustc/util/ppaux.rs | 2 +- src/librustc_data_structures/indexed_set.rs | 39 +++++++ src/librustc_mir/hair/cx/expr.rs | 94 +++++++-------- src/librustc_mir/transform/generator.rs | 109 ++++-------------- src/librustc_mir/util/liveness.rs | 25 +++- src/librustc_mir/util/pretty.rs | 4 +- src/librustc_trans/back/symbol_names.rs | 4 +- .../check/generator_interior.rs | 44 ++++--- src/librustc_typeck/check/mod.rs | 33 +++--- .../run-pass/generator/auxiliary/xcrate.rs | 25 ++++ src/test/run-pass/generator/panic-drops.rs | 8 +- src/test/run-pass/generator/xcrate.rs | 26 +++++ .../generator/borrowing.rs | 0 .../generator/no-arguments-on-generators.rs | 0 .../generator/not-send-sync.rs | 0 .../generator/yield-in-const.rs | 0 .../generator/yield-in-function.rs | 0 .../generator/yield-in-static.rs | 0 28 files changed, 251 insertions(+), 205 deletions(-) create mode 100644 src/test/run-pass/generator/auxiliary/xcrate.rs create mode 100644 src/test/run-pass/generator/xcrate.rs rename src/test/{compile-fail => ui}/generator/borrowing.rs (100%) rename src/test/{compile-fail => ui}/generator/no-arguments-on-generators.rs (100%) rename src/test/{compile-fail => ui}/generator/not-send-sync.rs (100%) rename src/test/{compile-fail => ui}/generator/yield-in-const.rs (100%) rename src/test/{compile-fail => ui}/generator/yield-in-function.rs (100%) rename src/test/{compile-fail => ui}/generator/yield-in-static.rs (100%) diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index 9286d3c73ed67..e316fd5f3e6db 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -320,7 +320,7 @@ for ::middle::const_val::ConstVal<'tcx> { impl_stable_hash_for!(struct ty::ClosureSubsts<'tcx> { substs }); -impl_stable_hash_for!(tuple_struct ty::GeneratorInterior<'tcx> { ty }); +impl_stable_hash_for!(struct ty::GeneratorInterior<'tcx> { witness }); impl_stable_hash_for!(struct ty::GenericPredicates<'tcx> { parent, diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index 4063609474bc9..e688af4316032 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -411,8 +411,13 @@ pub struct LocalDecl<'tcx> { /// True if this corresponds to a user-declared local variable. pub is_user_variable: bool, - /// True if this an internal local. + /// True if this is an internal local. /// Such locals are not checked against the legal types in a generator. + /// + /// Scalar state variables created by optimizations (e.g. nonzeroing drop + /// flags) should not be included in generator OIBIT computations. + /// Therefore, we mark them as `internal` so we can ignore them when + /// sanity-checking the OIBIT list. pub internal: bool, /// Type of this local. diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 9d5494d1fbab6..52c8b67278e20 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -2126,7 +2126,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { } ty::TyGenerator(def_id, ref substs, interior) => { - let witness = iter::once(interior.witness()); + let witness = iter::once(interior.witness); substs.upvar_tys(def_id, self.tcx()).chain(witness).collect() } diff --git a/src/librustc/ty/flags.rs b/src/librustc/ty/flags.rs index 02d50ce29e4f1..f40e1d370a995 100644 --- a/src/librustc/ty/flags.rs +++ b/src/librustc/ty/flags.rs @@ -89,7 +89,7 @@ impl FlagComputation { self.add_flags(TypeFlags::HAS_TY_CLOSURE); self.add_flags(TypeFlags::HAS_LOCAL_NAMES); self.add_substs(&substs.substs); - self.add_ty(interior.witness()); + self.add_ty(interior.witness); } &ty::TyClosure(_, ref substs) => { diff --git a/src/librustc/ty/outlives.rs b/src/librustc/ty/outlives.rs index 3549a7706439e..657ed4077911c 100644 --- a/src/librustc/ty/outlives.rs +++ b/src/librustc/ty/outlives.rs @@ -122,7 +122,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } // But generators can have additional interior types - self.compute_components(interior.witness(), out); + self.compute_components(interior.witness, out); } // OutlivesTypeParameterEnv -- the actual checking that `X:'a` diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs index 437f511cb3d0e..da94eddf295ea 100644 --- a/src/librustc/ty/relate.rs +++ b/src/librustc/ty/relate.rs @@ -531,7 +531,7 @@ impl<'tcx> Relate<'tcx> for ty::GeneratorInterior<'tcx> { -> RelateResult<'tcx, ty::GeneratorInterior<'tcx>> where R: TypeRelation<'a, 'gcx, 'tcx>, 'gcx: 'a+'tcx, 'tcx: 'a { - let interior = relation.relate(&a.witness(), &b.witness())?; + let interior = relation.relate(&a.witness, &b.witness)?; Ok(ty::GeneratorInterior::new(interior)) } } diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 087c41a7883ce..cbb0a45cf1e14 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -232,8 +232,8 @@ impl<'a, 'tcx> Lift<'tcx> for ty::ClosureSubsts<'a> { impl<'a, 'tcx> Lift<'tcx> for ty::GeneratorInterior<'a> { type Lifted = ty::GeneratorInterior<'tcx>; fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option { - tcx.lift(&self.witness()).map(|witness| { - ty::GeneratorInterior(witness) + tcx.lift(&self.witness).map(|witness| { + ty::GeneratorInterior { witness } }) } } @@ -737,11 +737,11 @@ impl<'tcx> TypeFoldable<'tcx> for ty::ClosureSubsts<'tcx> { impl<'tcx> TypeFoldable<'tcx> for ty::GeneratorInterior<'tcx> { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { - ty::GeneratorInterior(self.0.fold_with(folder)) + ty::GeneratorInterior::new(self.witness.fold_with(folder)) } fn super_visit_with>(&self, visitor: &mut V) -> bool { - self.0.visit_with(visitor) + self.witness.visit_with(visitor) } } diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index 2f3fd5244aeae..9898ce5d73daa 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -295,19 +295,17 @@ impl<'a, 'gcx, 'tcx> ClosureSubsts<'tcx> { /// The state transformation MIR pass may only produce layouts which mention types in this tuple. /// Upvars are not counted here. #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] -pub struct GeneratorInterior<'tcx>(pub Ty<'tcx>); +pub struct GeneratorInterior<'tcx> { + pub witness: Ty<'tcx>, +} impl<'tcx> GeneratorInterior<'tcx> { pub fn new(witness: Ty<'tcx>) -> GeneratorInterior<'tcx> { - GeneratorInterior(witness) - } - - pub fn witness(&self) -> Ty<'tcx> { - self.0 + GeneratorInterior { witness } } pub fn as_slice(&self) -> &'tcx Slice> { - match self.0.sty { + match self.witness.sty { ty::TyTuple(s, _) => s, _ => bug!(), } @@ -638,10 +636,8 @@ pub struct GenSig<'tcx> { pub return_ty: Ty<'tcx>, } -#[allow(warnings)] pub type PolyGenSig<'tcx> = Binder>; -#[allow(warnings)] impl<'tcx> PolyGenSig<'tcx> { pub fn yield_ty(&self) -> ty::Binder> { self.map_bound_ref(|sig| sig.yield_ty) diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index 6bbcc674ef408..67ec8d2ae63ad 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -570,7 +570,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } ty::TyGenerator(def_id, substs, interior) => { - substs.upvar_tys(def_id, self).chain(iter::once(interior.witness())).map(|ty| { + substs.upvar_tys(def_id, self).chain(iter::once(interior.witness)).map(|ty| { self.dtorck_constraint_for_ty(span, for_ty, depth+1, ty) }).collect() } diff --git a/src/librustc/ty/walk.rs b/src/librustc/ty/walk.rs index a2087b0b2f1bf..bfabacdb17214 100644 --- a/src/librustc/ty/walk.rs +++ b/src/librustc/ty/walk.rs @@ -114,7 +114,7 @@ fn push_subtypes<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent_ty: Ty<'tcx>) { } ty::TyGenerator(_, ref substs, ref interior) => { stack.extend(substs.substs.types().rev()); - stack.push(interior.witness()); + stack.push(interior.witness); } ty::TyTuple(ts, _) => { stack.extend(ts.iter().cloned().rev()); diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 33ab83d236f7c..ed72f2429487f 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -717,7 +717,7 @@ impl<'tcx> fmt::Display for ty::TraitRef<'tcx> { impl<'tcx> fmt::Display for ty::GeneratorInterior<'tcx> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", self.0) + self.witness.fmt(f) } } diff --git a/src/librustc_data_structures/indexed_set.rs b/src/librustc_data_structures/indexed_set.rs index 821e2b01431c5..9fa47cee65958 100644 --- a/src/librustc_data_structures/indexed_set.rs +++ b/src/librustc_data_structures/indexed_set.rs @@ -9,9 +9,11 @@ // except according to those terms. use std::fmt; +use std::iter; use std::marker::PhantomData; use std::mem; use std::ops::{Deref, DerefMut, Range}; +use std::slice; use bitslice::{BitSlice, Word}; use bitslice::{bitwise, Union, Subtract}; use indexed_vec::Idx; @@ -161,4 +163,41 @@ impl IdxSet { pub fn subtract(&mut self, other: &IdxSet) -> bool { bitwise(self.words_mut(), other.words(), &Subtract) } + + pub fn iter(&self) -> Iter { + Iter { + cur: None, + iter: self.words().iter().enumerate(), + _pd: PhantomData, + } + } +} + +pub struct Iter<'a, T: Idx> { + cur: Option<(Word, usize)>, + iter: iter::Enumerate>, + _pd: PhantomData, +} + +impl<'a, T: Idx> Iterator for Iter<'a, T> { + type Item = T; + + fn next(&mut self) -> Option { + let word_bits = mem::size_of::() * 8; + loop { + if let Some((ref mut word, offset)) = self.cur { + let bit_pos = word.trailing_zeros(); + if bit_pos != word_bits as u32 { + let bit = 1 << bit_pos; + *word ^= bit; + return Some(T::new(bit + offset)) + } + } + + match self.iter.next() { + Some((i, word)) => self.cur = Some((*word, word_bits * i)), + None => return None, + } + } + } } diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index 9b3585fff58b3..a81103213b841 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -703,57 +703,57 @@ fn convert_var<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, let region = cx.tcx.mk_region(region); let self_expr = if let ty::TyClosure(..) = closure_ty.sty { - match cx.tcx.closure_kind(closure_def_id) { - ty::ClosureKind::Fn => { - let ref_closure_ty = cx.tcx.mk_ref(region, - ty::TypeAndMut { - ty: closure_ty, - mutbl: hir::MutImmutable, - }); - Expr { - ty: closure_ty, - temp_lifetime: temp_lifetime, - span: expr.span, - kind: ExprKind::Deref { - arg: Expr { - ty: ref_closure_ty, - temp_lifetime: temp_lifetime, - span: expr.span, - kind: ExprKind::SelfRef, - } - .to_ref(), - }, + match cx.tcx.closure_kind(closure_def_id) { + ty::ClosureKind::Fn => { + let ref_closure_ty = cx.tcx.mk_ref(region, + ty::TypeAndMut { + ty: closure_ty, + mutbl: hir::MutImmutable, + }); + Expr { + ty: closure_ty, + temp_lifetime: temp_lifetime, + span: expr.span, + kind: ExprKind::Deref { + arg: Expr { + ty: ref_closure_ty, + temp_lifetime: temp_lifetime, + span: expr.span, + kind: ExprKind::SelfRef, + } + .to_ref(), + }, + } } - } - ty::ClosureKind::FnMut => { - let ref_closure_ty = cx.tcx.mk_ref(region, - ty::TypeAndMut { - ty: closure_ty, - mutbl: hir::MutMutable, - }); - Expr { - ty: closure_ty, - temp_lifetime: temp_lifetime, - span: expr.span, - kind: ExprKind::Deref { - arg: Expr { - ty: ref_closure_ty, - temp_lifetime: temp_lifetime, - span: expr.span, - kind: ExprKind::SelfRef, - }.to_ref(), - }, + ty::ClosureKind::FnMut => { + let ref_closure_ty = cx.tcx.mk_ref(region, + ty::TypeAndMut { + ty: closure_ty, + mutbl: hir::MutMutable, + }); + Expr { + ty: closure_ty, + temp_lifetime: temp_lifetime, + span: expr.span, + kind: ExprKind::Deref { + arg: Expr { + ty: ref_closure_ty, + temp_lifetime: temp_lifetime, + span: expr.span, + kind: ExprKind::SelfRef, + }.to_ref(), + }, + } } - } - ty::ClosureKind::FnOnce => { - Expr { - ty: closure_ty, - temp_lifetime: temp_lifetime, - span: expr.span, - kind: ExprKind::SelfRef, + ty::ClosureKind::FnOnce => { + Expr { + ty: closure_ty, + temp_lifetime: temp_lifetime, + span: expr.span, + kind: ExprKind::SelfRef, + } } } - } } else { Expr { ty: closure_ty, diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs index dc86bc6818def..f57ba0cf42a12 100644 --- a/src/librustc_mir/transform/generator.rs +++ b/src/librustc_mir/transform/generator.rs @@ -10,8 +10,6 @@ //! Transforms generators into state machines -#![allow(warnings)] - use rustc::hir; use rustc::hir::def_id::DefId; use rustc::middle::const_val::ConstVal; @@ -23,11 +21,11 @@ use rustc::ty::subst::{Kind, Substs}; use util::dump_mir; use util::liveness; use rustc_const_math::ConstInt; -use rustc_data_structures::bitvec::BitVector; use rustc_data_structures::indexed_vec::Idx; use std::collections::HashMap; use std::borrow::Cow; use std::iter::once; +use std::mem; use syntax::ast::NodeId; use transform::simplify; @@ -150,7 +148,7 @@ impl<'a, 'tcx> MutVisitor<'tcx> for TransformVisitor<'a, 'tcx> { } }); - ret_val.map(|(state_idx, resume, v, drop)| { + if let Some((state_idx, resume, v, drop)) = ret_val { let bb_idx = { let bb_targets = &mut self.bb_targets; let bb_target = &mut self.bb_target_count; @@ -168,54 +166,12 @@ impl<'a, 'tcx> MutVisitor<'tcx> for TransformVisitor<'a, 'tcx> { self.make_state(state_idx, v)), }); data.terminator.as_mut().unwrap().kind = TerminatorKind::Return; - }); + } self.super_basic_block_data(block, data); } } -fn get_body_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, node_id: NodeId) -> (bool, hir::BodyId) { - // Figure out what primary body this item has. - match tcx.hir.get(node_id) { - hir::map::NodeItem(item) => { - match item.node { - hir::ItemConst(_, body) | - hir::ItemStatic(_, _, body) | - hir::ItemFn(.., body) => (false, body), - _ => bug!(), - } - } - hir::map::NodeTraitItem(item) => { - match item.node { - hir::TraitItemKind::Const(_, Some(body)) | - hir::TraitItemKind::Method(_, - hir::TraitMethod::Provided(body)) => (false, body), - _ => bug!(), - } - } - hir::map::NodeImplItem(item) => { - match item.node { - hir::ImplItemKind::Const(_, body) | - hir::ImplItemKind::Method(_, body) => (false, body), - _ => bug!(), - } - } - hir::map::NodeExpr(expr) => { - // FIXME(eddyb) Closures should have separate - // function definition IDs and expression IDs. - // Type-checking should not let closures get - // this far in a constant position. - // Assume that everything other than closures - // is a constant "initializer" expression. - match expr.node { - hir::ExprClosure(_, _, body, _, _) => (true, body), - _ => (false, hir::BodyId { node_id: expr.id }) - } - } - _ => bug!(), - } -} - fn ensure_generator_state_argument<'a, 'tcx>( tcx: TyCtxt<'a, 'tcx, 'tcx>, node_id: NodeId, @@ -281,7 +237,6 @@ fn replace_result_variable<'tcx>(ret_ty: Ty<'tcx>, fn locals_live_across_suspend_points<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, mir: &Mir<'tcx>, source: MirSource) -> liveness::LocalSet { - use rustc_data_structures::indexed_set::IdxSetBuf; let mut set = liveness::LocalSet::new_empty(mir.local_decls.len()); let result = liveness::liveness_of_locals(mir); liveness::dump_mir(tcx, "generator_liveness", source, mir, &result); @@ -299,18 +254,12 @@ fn locals_live_across_suspend_points<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } fn compute_layout<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - def_id: DefId, source: MirSource, interior: GeneratorInterior<'tcx>, mir: &mut Mir<'tcx>) -> (HashMap, usize)>, GeneratorLayout<'tcx>) { - let source_info = SourceInfo { - span: mir.span, - scope: ARGUMENT_VISIBILITY_SCOPE, - }; - - let mut live_locals = locals_live_across_suspend_points(tcx, mir, source); + let live_locals = locals_live_across_suspend_points(tcx, mir, source); let allowed = tcx.erase_regions(&interior.as_slice()); @@ -319,34 +268,23 @@ fn compute_layout<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, continue; } if !allowed.contains(&decl.ty) { - tcx.sess.span_warn(mir.span, - &format!("generator contains type {} in MIR, but typeck only knows about {}", - decl.ty, - interior)); + span_bug!(mir.span, + "Broken MIR: generator contains type {} in MIR, \ + but typeck only knows about {}", + decl.ty, + interior); } } let upvar_len = mir.upvar_decls.len(); - let live_decls : Vec<_> = mir.local_decls - .iter_enumerated_mut() - .filter(|&(local, _)| live_locals.contains(&local)) - .collect(); - - let mut remap = HashMap::new(); - let unit = tcx.mk_nil(); - let mut vars: Vec<_> = live_decls.into_iter().enumerate().map(|(idx, (local, decl))| { - let var = decl.clone(); - *decl = LocalDecl { - mutability: Mutability::Mut, - ty: unit, - name: None, - source_info, - internal: false, - is_user_variable: false, - }; - remap.insert(local, (var.ty, upvar_len + 1 + idx)); - var - }).collect(); + let dummy_local = LocalDecl::new_internal(tcx.mk_nil(), mir.span); + let live_decls = live_locals.iter().map(|local| { + let var = mem::replace(&mut mir.local_decls[local], dummy_local.clone()); + (local, var) + }); + let (remap, vars) = live_decls.enumerate().map(|(idx, (local, var))| { + ((local, (var.ty, upvar_len + 1 + idx)), var) + }).unzip(); let layout = GeneratorLayout { fields: vars @@ -369,7 +307,7 @@ fn insert_entry_point<'tcx>(mir: &mut Mir<'tcx>, fn elaborate_generator_drops<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId, mir: &mut Mir<'tcx>) { - use util::elaborate_drops::{elaborate_drop, Unwind, DropElaborator, DropStyle, DropFlagMode}; + use util::elaborate_drops::{elaborate_drop, Unwind}; use util::patch::MirPatch; use shim::DropShimElaborator; @@ -418,7 +356,6 @@ fn elaborate_generator_drops<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, fn generate_drop<'a, 'tcx>( tcx: TyCtxt<'a, 'tcx, 'tcx>, transform: &TransformVisitor<'a, 'tcx>, - node_id: NodeId, def_id: DefId, source: MirSource, gen_ty: Ty<'tcx>, @@ -439,7 +376,7 @@ fn generate_drop<'a, 'tcx>( is_cleanup: false, }); - let mut cases: Vec<_> = transform.bb_targets.iter().filter_map(|(&(r, u), &s)| { + let mut cases: Vec<_> = transform.bb_targets.iter().filter_map(|(&(_, u), &s)| { u.map(|d| (s, d)) }).collect(); @@ -581,10 +518,9 @@ fn insert_resume_after_return<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, cleanup } -fn generate_resume<'a, 'tcx>( +fn generate_entry_point<'a, 'tcx>( tcx: TyCtxt<'a, 'tcx, 'tcx>, mut transform: TransformVisitor<'a, 'tcx>, - node_id: NodeId, def_id: DefId, source: MirSource, cleanup: Option, @@ -721,7 +657,7 @@ impl MirPass for StateTransform { let new_ret_local = replace_result_variable(ret_ty, mir); - let (remap, layout) = compute_layout(tcx, def_id, source, interior, mir); + let (remap, layout) = compute_layout(tcx, source, interior, mir); let tail_block = BasicBlock::new(mir.basic_blocks().len()); @@ -763,7 +699,6 @@ impl MirPass for StateTransform { generate_drop(tcx, &transform, - node_id, def_id, source, gen_ty, @@ -772,6 +707,6 @@ impl MirPass for StateTransform { mir.generator_drop = Some(box drop_impl); - generate_resume(tcx, transform, node_id, def_id, source, arg_cleanup, mir); + generate_entry_point(tcx, transform, def_id, source, arg_cleanup, mir); } } diff --git a/src/librustc_mir/util/liveness.rs b/src/librustc_mir/util/liveness.rs index 946e9ff474743..fd15c90dc9013 100644 --- a/src/librustc_mir/util/liveness.rs +++ b/src/librustc_mir/util/liveness.rs @@ -9,6 +9,29 @@ // except according to those terms. //! Liveness analysis which computes liveness of MIR local variables at the boundary of basic blocks +//! +//! This analysis considers references as being used only at the point of the +//! borrow. This means that this does not track uses because of references that +//! already exist: +//! +//! ```Rust +//! fn foo() { +//! x = 0; +//! // `x` is live here +//! GLOBAL = &x: *const u32; +//! // but not here, even while it can be accessed through `GLOBAL`. +//! foo(); +//! x = 1; +//! // `x` is live again here, because it is assigned to `OTHER_GLOBAL` +//! OTHER_GLOBAL = &x: *const u32; +//! // ... +//! } +//! ``` +//! +//! This means that users of this analysis still have to check whether +//! pre-existing references can be used to access the value (e.g. at movable +//! generator yield points, all pre-existing references are invalidated, so this +//! doesn't matter). use rustc::mir::*; use rustc::mir::visit::{LvalueContext, Visitor}; @@ -60,7 +83,7 @@ impl<'tcx> Visitor<'tcx> for BlockInfoVisitor { // Borrows only consider their local used at the point of the borrow. // This won't affect the results since we use this analysis for generators // and we only care about the result at suspension points. Borrows cannot - // cross suspension points so this behavoir is unproblematic. + // cross suspension points so this behavior is unproblematic. LvalueContext::Borrow { .. } | LvalueContext::Inspect | diff --git a/src/librustc_mir/util/pretty.rs b/src/librustc_mir/util/pretty.rs index e3087efbfe626..0811783a9e57f 100644 --- a/src/librustc_mir/util/pretty.rs +++ b/src/librustc_mir/util/pretty.rs @@ -348,7 +348,9 @@ fn write_mir_sig(tcx: TyCtxt, src: MirSource, mir: &Mir, w: &mut Write) write!(w, ") -> {}", mir.return_ty) } - _ => { + MirSource::Const(..) | + MirSource::Static(..) | + MirSource::Promoted(..) => { assert_eq!(mir.arg_count, 0); write!(w, ": {} =", mir.return_ty) } diff --git a/src/librustc_trans/back/symbol_names.rs b/src/librustc_trans/back/symbol_names.rs index d646b515bf41e..10b66fb199108 100644 --- a/src/librustc_trans/back/symbol_names.rs +++ b/src/librustc_trans/back/symbol_names.rs @@ -287,9 +287,7 @@ fn compute_symbol_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, instance: Instance let hash = get_symbol_hash(tcx, Some(def_id), instance_ty, Some(substs)); - let buffer = SymbolPathBuffer::from_interned(tcx.def_symbol_name(def_id)); - - buffer.finish(hash) + SymbolPathBuffer::from_interned(tcx.def_symbol_name(def_id)).finish(hash) } // Follow C++ namespace-mangling style, see diff --git a/src/librustc_typeck/check/generator_interior.rs b/src/librustc_typeck/check/generator_interior.rs index f116620388f16..6753d42b0c549 100644 --- a/src/librustc_typeck/check/generator_interior.rs +++ b/src/librustc_typeck/check/generator_interior.rs @@ -8,14 +8,15 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use log; +use rustc::hir::def_id::DefId; use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap}; use rustc::hir::{self, Body, Pat, PatKind, Expr}; -use rustc::hir::def_id::DefId; -use rustc::ty::Ty; use rustc::middle::region::{RegionMaps, CodeExtent}; -use util::nodemap::FxHashSet; +use rustc::ty::Ty; use std::rc::Rc; use super::FnCtxt; +use util::nodemap::FxHashSet; struct InteriorVisitor<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { fcx: &'a FnCtxt<'a, 'gcx, 'tcx>, @@ -28,36 +29,34 @@ impl<'a, 'gcx, 'tcx> InteriorVisitor<'a, 'gcx, 'tcx> { use syntax_pos::DUMMY_SP; if scope.map(|s| self.fcx.tcx.yield_in_extent(s).is_some()).unwrap_or(true) { - if self.fcx.tcx.sess.verbose() { + if log_enabled!(log::LogLevel::Debug) { if let Some(s) = scope { - self.fcx.tcx.sess.span_warn(s.span(&self.fcx.tcx.hir).unwrap_or(DUMMY_SP), - &format!("type in generator with scope = {:?}, type = {:?}", - scope, - self.fcx.resolve_type_vars_if_possible(&ty))); + let span = s.span(&self.fcx.tcx.hir).unwrap_or(DUMMY_SP); + debug!("type in generator with scope = {:?}, type = {:?}, span = {:?}", + scope, + self.fcx.resolve_type_vars_if_possible(&ty), + span); } else { - self.fcx.tcx.sess.span_warn(DUMMY_SP, - &format!("type in generator WITHOUT scope, type = {:?}", - self.fcx.resolve_type_vars_if_possible(&ty))); + debug!("type in generator WITHOUT scope, type = {:?}", + self.fcx.resolve_type_vars_if_possible(&ty)); } if let Some(e) = expr { - self.fcx.tcx.sess.span_warn(e.span, - &format!("type from expression: {:?}", e)); + debug!("type from expression: {:?}, span={:?}", e, e.span); } } self.types.insert(ty); - } else if self.fcx.tcx.sess.verbose() { + } else { if let Some(e) = expr { - self.fcx.tcx.sess.span_warn(e.span, - &format!("NO type from expression: {:?}", e)); + debug!("NO type from expression: {:?}, span = {:?}", e, e.span); } } } } -pub fn find_interior<'a, 'gcx, 'tcx>(fcx: &'a FnCtxt<'a, 'gcx, 'tcx>, - def_id: DefId, - body_id: hir::BodyId, - witness: Ty<'tcx>) { +pub fn resolve_interior<'a, 'gcx, 'tcx>(fcx: &'a FnCtxt<'a, 'gcx, 'tcx>, + def_id: DefId, + body_id: hir::BodyId, + witness: Ty<'tcx>) { let body = fcx.tcx.hir.body(body_id); let mut visitor = InteriorVisitor { fcx, @@ -74,10 +73,7 @@ pub fn find_interior<'a, 'gcx, 'tcx>(fcx: &'a FnCtxt<'a, 'gcx, 'tcx>, let tuple = fcx.tcx.intern_tup(&types, false); - if fcx.tcx.sess.verbose() { - fcx.tcx.sess.span_warn(body.value.span, - &format!("Types in generator {:?}", tuple)); - } + debug!("Types in generator {:?}, span = {:?}", tuple, body.value.span); // Unify the tuple with the witness match fcx.at(&fcx.misc(body.value.span), fcx.param_env).eq(witness, tuple) { diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index ed6d0c035de8c..fee10f503780a 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -892,7 +892,7 @@ fn typeck_tables_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, fcx.closure_analyze(body); fcx.select_obligations_where_possible(); fcx.check_casts(); - fcx.find_generator_interiors(def_id); + fcx.resolve_generator_interiors(def_id); fcx.select_all_obligations_or_error(); if fn_decl.is_some() { @@ -2107,10 +2107,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } - fn find_generator_interiors(&self, def_id: DefId) { + fn resolve_generator_interiors(&self, def_id: DefId) { let mut deferred_generator_interiors = self.deferred_generator_interiors.borrow_mut(); for (body_id, witness) in deferred_generator_interiors.drain(..) { - generator_interior::find_interior(self, def_id, body_id, witness); + generator_interior::resolve_interior(self, def_id, body_id, witness); } } @@ -2677,8 +2677,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } pub fn check_expr_has_type_or_error(&self, - expr: &'gcx hir::Expr, - expected: Ty<'tcx>) -> Ty<'tcx> { + expr: &'gcx hir::Expr, + expected: Ty<'tcx>) -> Ty<'tcx> { self.check_expr_meets_expectation_or_error(expr, ExpectHasType(expected)) } @@ -3138,13 +3138,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { return field_ty; } - if tuple_like { + if tuple_like { type_error_struct!(self.tcx().sess, expr.span, expr_t, E0612, - "attempted out-of-bounds tuple index `{}` on type `{}`", - idx.node, expr_t).emit(); - } else { + "attempted out-of-bounds tuple index `{}` on type `{}`", + idx.node, expr_t).emit(); + } else { self.no_such_field_err(expr.span, idx.node, expr_t).emit(); - } + } self.tcx().types.err } @@ -3733,14 +3733,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Only check this if not in an `if` condition, as the // mistyped comparison help is more appropriate. if !self.tcx.expr_is_lval(&lhs) { - struct_span_err!( - self.tcx.sess, expr.span, E0070, - "invalid left-hand side expression") - .span_label( - expr.span, - "left-hand of expression not valid") - .emit(); - } + struct_span_err!(self.tcx.sess, expr.span, E0070, + "invalid left-hand side expression") + .span_label(expr.span, "left-hand of expression not valid") + .emit(); + } } } diff --git a/src/test/run-pass/generator/auxiliary/xcrate.rs b/src/test/run-pass/generator/auxiliary/xcrate.rs new file mode 100644 index 0000000000000..519c34cd0edbf --- /dev/null +++ b/src/test/run-pass/generator/auxiliary/xcrate.rs @@ -0,0 +1,25 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(generators, generator_trait, conservative_impl_trait)] + +use std::ops::Generator; + +fn bar() -> bool { + false +} + +pub fn foo() -> impl Generator { + || { + if bar() { + yield; + } + } +} diff --git a/src/test/run-pass/generator/panic-drops.rs b/src/test/run-pass/generator/panic-drops.rs index 4837f68be5eb2..53cd3235d9d0c 100644 --- a/src/test/run-pass/generator/panic-drops.rs +++ b/src/test/run-pass/generator/panic-drops.rs @@ -24,10 +24,14 @@ impl Drop for B { } } +fn bool_true() -> bool { + true +} + fn main() { let b = B; let mut foo = || { - if true { + if bool_true() { panic!(); } drop(b); @@ -42,7 +46,7 @@ fn main() { assert_eq!(A.load(Ordering::SeqCst), 1); let mut foo = || { - if true { + if bool_true() { panic!(); } drop(B); diff --git a/src/test/run-pass/generator/xcrate.rs b/src/test/run-pass/generator/xcrate.rs new file mode 100644 index 0000000000000..5d6cdee1a242f --- /dev/null +++ b/src/test/run-pass/generator/xcrate.rs @@ -0,0 +1,26 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:xcrate.rs + +#![feature(generators, generator_trait)] + +extern crate xcrate; + +use std::ops::{GeneratorState, Generator}; + +fn main() { + let mut foo = xcrate::foo(); + + match foo.resume() { + GeneratorState::Complete(()) => {} + s => panic!("bad state: {:?}", s), + } +} diff --git a/src/test/compile-fail/generator/borrowing.rs b/src/test/ui/generator/borrowing.rs similarity index 100% rename from src/test/compile-fail/generator/borrowing.rs rename to src/test/ui/generator/borrowing.rs diff --git a/src/test/compile-fail/generator/no-arguments-on-generators.rs b/src/test/ui/generator/no-arguments-on-generators.rs similarity index 100% rename from src/test/compile-fail/generator/no-arguments-on-generators.rs rename to src/test/ui/generator/no-arguments-on-generators.rs diff --git a/src/test/compile-fail/generator/not-send-sync.rs b/src/test/ui/generator/not-send-sync.rs similarity index 100% rename from src/test/compile-fail/generator/not-send-sync.rs rename to src/test/ui/generator/not-send-sync.rs diff --git a/src/test/compile-fail/generator/yield-in-const.rs b/src/test/ui/generator/yield-in-const.rs similarity index 100% rename from src/test/compile-fail/generator/yield-in-const.rs rename to src/test/ui/generator/yield-in-const.rs diff --git a/src/test/compile-fail/generator/yield-in-function.rs b/src/test/ui/generator/yield-in-function.rs similarity index 100% rename from src/test/compile-fail/generator/yield-in-function.rs rename to src/test/ui/generator/yield-in-function.rs diff --git a/src/test/compile-fail/generator/yield-in-static.rs b/src/test/ui/generator/yield-in-static.rs similarity index 100% rename from src/test/compile-fail/generator/yield-in-static.rs rename to src/test/ui/generator/yield-in-static.rs From f72724eeb4971e686718c5d2f8a4ae96f9395e15 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 9 Aug 2017 14:02:45 -0700 Subject: [PATCH 070/113] Fix iterator over indexed sets --- src/librustc_data_structures/indexed_set.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/librustc_data_structures/indexed_set.rs b/src/librustc_data_structures/indexed_set.rs index 9fa47cee65958..cc56289a56334 100644 --- a/src/librustc_data_structures/indexed_set.rs +++ b/src/librustc_data_structures/indexed_set.rs @@ -186,11 +186,11 @@ impl<'a, T: Idx> Iterator for Iter<'a, T> { let word_bits = mem::size_of::() * 8; loop { if let Some((ref mut word, offset)) = self.cur { - let bit_pos = word.trailing_zeros(); - if bit_pos != word_bits as u32 { + let bit_pos = word.trailing_zeros() as usize; + if bit_pos != word_bits { let bit = 1 << bit_pos; *word ^= bit; - return Some(T::new(bit + offset)) + return Some(T::new(bit_pos + offset)) } } From e181060a59c5975bd1a011524d9541a3cdacdfbb Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 9 Aug 2017 16:37:56 -0700 Subject: [PATCH 071/113] Add UI test outputs --- src/test/ui/generator/borrowing.stderr | 29 +++++++++++++++++++ .../no-arguments-on-generators.stderr | 8 +++++ src/test/ui/generator/not-send-sync.stderr | 24 +++++++++++++++ src/test/ui/generator/yield-in-const.stderr | 10 +++++++ .../ui/generator/yield-in-function.stderr | 8 +++++ src/test/ui/generator/yield-in-static.stderr | 10 +++++++ 6 files changed, 89 insertions(+) create mode 100644 src/test/ui/generator/borrowing.stderr create mode 100644 src/test/ui/generator/no-arguments-on-generators.stderr create mode 100644 src/test/ui/generator/not-send-sync.stderr create mode 100644 src/test/ui/generator/yield-in-const.stderr create mode 100644 src/test/ui/generator/yield-in-function.stderr create mode 100644 src/test/ui/generator/yield-in-static.stderr diff --git a/src/test/ui/generator/borrowing.stderr b/src/test/ui/generator/borrowing.stderr new file mode 100644 index 0000000000000..0ed7e1f99027d --- /dev/null +++ b/src/test/ui/generator/borrowing.stderr @@ -0,0 +1,29 @@ +error[E0597]: `a` does not live long enough + --> $DIR/borrowing.rs:18:20 + | +18 | (|| yield &a).resume() + | -- ^ does not live long enough + | | + | capture occurs here +19 | //~^ ERROR: `a` does not live long enough +20 | }; + | - borrowed value only lives until here +... +29 | } + | - borrowed value needs to live until here + +error[E0597]: `a` does not live long enough + --> $DIR/borrowing.rs:25:20 + | +24 | || { + | -- capture occurs here +25 | yield &a + | ^ does not live long enough +... +28 | }; + | - borrowed value only lives until here +29 | } + | - borrowed value needs to live until here + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/generator/no-arguments-on-generators.stderr b/src/test/ui/generator/no-arguments-on-generators.stderr new file mode 100644 index 0000000000000..290ad7b7f6c6a --- /dev/null +++ b/src/test/ui/generator/no-arguments-on-generators.stderr @@ -0,0 +1,8 @@ +error[E0625]: generators cannot have explicit arguments + --> $DIR/no-arguments-on-generators.rs:14:15 + | +14 | let gen = |start| { //~ ERROR generators cannot have explicit arguments + | ^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/generator/not-send-sync.stderr b/src/test/ui/generator/not-send-sync.stderr new file mode 100644 index 0000000000000..a1f110accc100 --- /dev/null +++ b/src/test/ui/generator/not-send-sync.stderr @@ -0,0 +1,24 @@ +error[E0277]: the trait bound `std::cell::Cell: std::marker::Sync` is not satisfied + --> $DIR/not-send-sync.rs:26:5 + | +26 | assert_send(|| { + | ^^^^^^^^^^^ `std::cell::Cell` cannot be shared between threads safely + | + = help: the trait `std::marker::Sync` is not implemented for `std::cell::Cell` + = note: required because of the requirements on the impl of `std::marker::Send` for `&std::cell::Cell` + = note: required because it appears within the type `[generator@$DIR/not-send-sync.rs:26:17: 30:6 a:&std::cell::Cell _]` + = note: required by `main::assert_send` + +error[E0277]: the trait bound `std::cell::Cell: std::marker::Sync` is not satisfied in `[generator@$DIR/not-send-sync.rs:19:17: 23:6 (std::cell::Cell, ())]` + --> $DIR/not-send-sync.rs:19:5 + | +19 | assert_sync(|| { + | ^^^^^^^^^^^ `std::cell::Cell` cannot be shared between threads safely + | + = help: within `[generator@$DIR/not-send-sync.rs:19:17: 23:6 (std::cell::Cell, ())]`, the trait `std::marker::Sync` is not implemented for `std::cell::Cell` + = note: required because it appears within the type `(std::cell::Cell, ())` + = note: required because it appears within the type `[generator@$DIR/not-send-sync.rs:19:17: 23:6 (std::cell::Cell, ())]` + = note: required by `main::assert_sync` + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/generator/yield-in-const.stderr b/src/test/ui/generator/yield-in-const.stderr new file mode 100644 index 0000000000000..8a265c065b988 --- /dev/null +++ b/src/test/ui/generator/yield-in-const.stderr @@ -0,0 +1,10 @@ +error[E0601]: main function not found + +error[E0627]: yield statement outside of generator literal + --> $DIR/yield-in-const.rs:13:17 + | +13 | const A: u8 = { yield 3u8; 3u8}; + | ^^^^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/generator/yield-in-function.stderr b/src/test/ui/generator/yield-in-function.stderr new file mode 100644 index 0000000000000..c6ee3b8e9e7e1 --- /dev/null +++ b/src/test/ui/generator/yield-in-function.stderr @@ -0,0 +1,8 @@ +error[E0627]: yield statement outside of generator literal + --> $DIR/yield-in-function.rs:13:13 + | +13 | fn main() { yield; } + | ^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/generator/yield-in-static.stderr b/src/test/ui/generator/yield-in-static.stderr new file mode 100644 index 0000000000000..d0575a0e47b3a --- /dev/null +++ b/src/test/ui/generator/yield-in-static.stderr @@ -0,0 +1,10 @@ +error[E0601]: main function not found + +error[E0627]: yield statement outside of generator literal + --> $DIR/yield-in-static.rs:13:18 + | +13 | static B: u8 = { yield 3u8; 3u8}; + | ^^^^^^^^^ + +error: aborting due to 2 previous errors + From be95ca4b17203a3aed27c17c1e93b76c9477e5bc Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 9 Aug 2017 16:38:05 -0700 Subject: [PATCH 072/113] Add a failing xcrate generator test --- src/test/run-pass/generator/auxiliary/xcrate.rs | 12 +++++++----- src/test/run-pass/generator/xcrate.rs | 11 +++++++++++ 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/src/test/run-pass/generator/auxiliary/xcrate.rs b/src/test/run-pass/generator/auxiliary/xcrate.rs index 519c34cd0edbf..f6878e64fbf93 100644 --- a/src/test/run-pass/generator/auxiliary/xcrate.rs +++ b/src/test/run-pass/generator/auxiliary/xcrate.rs @@ -12,14 +12,16 @@ use std::ops::Generator; -fn bar() -> bool { - false -} - pub fn foo() -> impl Generator { || { - if bar() { + if false { yield; } } } + +pub fn bar(t: T) -> Box> { + Box::new(|| { + yield t; + }) +} diff --git a/src/test/run-pass/generator/xcrate.rs b/src/test/run-pass/generator/xcrate.rs index 5d6cdee1a242f..7db567938290b 100644 --- a/src/test/run-pass/generator/xcrate.rs +++ b/src/test/run-pass/generator/xcrate.rs @@ -23,4 +23,15 @@ fn main() { GeneratorState::Complete(()) => {} s => panic!("bad state: {:?}", s), } + + let mut foo = xcrate::bar(3); + + match foo.resume() { + GeneratorState::Yielded(4) => {} + s => panic!("bad state: {:?}", s), + } + match foo.resume() { + GeneratorState::Complete(()) => {} + s => panic!("bad state: {:?}", s), + } } From 2d30e7e982bb1f2e60bc8ed449489c021416c845 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Fri, 11 Aug 2017 04:24:25 +0200 Subject: [PATCH 073/113] Fix merge of scope.rs --- src/librustc_mir/build/scope.rs | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/librustc_mir/build/scope.rs b/src/librustc_mir/build/scope.rs index 2033131c0650e..cb7b13f1e614c 100644 --- a/src/librustc_mir/build/scope.rs +++ b/src/librustc_mir/build/scope.rs @@ -875,15 +875,13 @@ fn build_scope_drops<'tcx>(cfg: &mut CFG<'tcx>, // for us to diverge into in case the drop panics. let on_diverge = iter.peek().iter().filter_map(|dd| { match dd.kind { - DropKind::Value { - cached_block: CachedBlock { - unwind: None, - generator_drop: None, + DropKind::Value { cached_block } => { + let result = cached_block.get(generator_drop); + if result.is_none() { + span_bug!(drop_data.span, "cached block not present?") } - } => { - span_bug!(drop_data.span, "cached block not present?") - } - DropKind::Value { cached_block } => cached_block.get(generator_drop), + result + }, DropKind::Storage => None } }).next(); @@ -903,6 +901,11 @@ fn build_scope_drops<'tcx>(cfg: &mut CFG<'tcx>, DropKind::Storage => {} } + // We do not need to emit StorageDead for generator drops + if generator_drop { + continue + } + // Drop the storage for both value and storage drops. // Only temps and vars need their storage dead. match drop_data.location { From ffcd32cfe62735a19dd9e81fe30a3b448c39fe2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Fri, 11 Aug 2017 04:36:39 +0200 Subject: [PATCH 074/113] Remove code related to the dropping of generator arguments --- src/librustc_mir/transform/generator.rs | 50 +++---------------------- 1 file changed, 5 insertions(+), 45 deletions(-) diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs index f57ba0cf42a12..d2fd0fdc0540d 100644 --- a/src/librustc_mir/transform/generator.rs +++ b/src/librustc_mir/transform/generator.rs @@ -448,16 +448,7 @@ fn generate_drop<'a, 'tcx>( } fn insert_resume_after_return<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - def_id: DefId, - mir: &mut Mir<'tcx>) -> Option { - let drop_arg = mir.local_decls.raw[2].ty.needs_drop(tcx, tcx.param_env(def_id)); - - let cleanup = if drop_arg { - Some(BasicBlock::new(mir.basic_blocks().len() + 1)) - } else { - None - }; - + mir: &mut Mir<'tcx>) { let assert_block = BasicBlock::new(mir.basic_blocks().len()); let term = TerminatorKind::Assert { cond: Operand::Constant(box Constant { @@ -470,7 +461,7 @@ fn insert_resume_after_return<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, expected: true, msg: AssertMessage::GeneratorResumedAfterReturn, target: assert_block, - cleanup: cleanup, + cleanup: None, }; let source_info = SourceInfo { @@ -486,36 +477,6 @@ fn insert_resume_after_return<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, }), is_cleanup: false, }); - - if drop_arg { - let resume_block = BasicBlock::new(mir.basic_blocks().len() + 1); - - let term = TerminatorKind::Drop { - location: Lvalue::Local(Local::new(2)), - target: resume_block, - unwind: None, - }; - - mir.basic_blocks_mut().push(BasicBlockData { - statements: Vec::new(), - terminator: Some(Terminator { - source_info, - kind: term, - }), - is_cleanup: true, - }); - - mir.basic_blocks_mut().push(BasicBlockData { - statements: Vec::new(), - terminator: Some(Terminator { - source_info, - kind: TerminatorKind::Resume, - }), - is_cleanup: true, - }); - } - - cleanup } fn generate_entry_point<'a, 'tcx>( @@ -523,7 +484,6 @@ fn generate_entry_point<'a, 'tcx>( mut transform: TransformVisitor<'a, 'tcx>, def_id: DefId, source: MirSource, - cleanup: Option, mir: &mut Mir<'tcx>) { // Poison the generator when it unwinds for block in mir.basic_blocks_mut() { @@ -551,7 +511,7 @@ fn generate_entry_point<'a, 'tcx>( expected: true, msg: AssertMessage::GeneratorResumedAfterPanic, target: transform.return_block, - cleanup: cleanup, + cleanup: None, }; mir.basic_blocks_mut().push(BasicBlockData { @@ -685,7 +645,7 @@ impl MirPass for StateTransform { mir.spread_arg = None; mir.generator_layout = Some(layout); - let arg_cleanup = insert_resume_after_return(tcx, def_id, mir); + insert_resume_after_return(tcx, mir); let (_return_block, drop_clean) = insert_clean_drop(mir); @@ -707,6 +667,6 @@ impl MirPass for StateTransform { mir.generator_drop = Some(box drop_impl); - generate_entry_point(tcx, transform, def_id, source, arg_cleanup, mir); + generate_entry_point(tcx, transform, def_id, source, mir); } } From bbe15522d5837abfe45652bf7dac40ffd8caea66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Fri, 11 Aug 2017 06:20:28 +0200 Subject: [PATCH 075/113] Some tweaks and comments --- src/librustc/mir/mod.rs | 13 ++- src/librustc_mir/transform/generator.rs | 140 ++++++++++++++++-------- 2 files changed, 102 insertions(+), 51 deletions(-) diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index e688af4316032..20e74f47c9e29 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -412,12 +412,13 @@ pub struct LocalDecl<'tcx> { pub is_user_variable: bool, /// True if this is an internal local. - /// Such locals are not checked against the legal types in a generator. - /// - /// Scalar state variables created by optimizations (e.g. nonzeroing drop - /// flags) should not be included in generator OIBIT computations. - /// Therefore, we mark them as `internal` so we can ignore them when - /// sanity-checking the OIBIT list. + /// These locals are not based on types in the source code and are only used + /// for drop flags at the moment. + /// The generator transformation will sanity check the locals which are live across + /// a suspension point against the type components of the generator which + /// type checking knows are live across a suspension point. + /// We need to flag drop flags to avoid triggering this check as they are introduced + /// after typeck. pub internal: bool, /// Type of this local. diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs index d2fd0fdc0540d..6a29de1361b0b 100644 --- a/src/librustc_mir/transform/generator.rs +++ b/src/librustc_mir/transform/generator.rs @@ -26,7 +26,6 @@ use std::collections::HashMap; use std::borrow::Cow; use std::iter::once; use std::mem; -use syntax::ast::NodeId; use transform::simplify; pub struct StateTransform; @@ -67,20 +66,35 @@ struct TransformVisitor<'a, 'tcx: 'a> { tcx: TyCtxt<'a, 'tcx, 'tcx>, state_adt_ref: &'tcx AdtDef, state_substs: &'tcx Substs<'tcx>, + + // The index of the generator state in the generator struct + state_field: usize, + + // Mapping from Local to (type of local, generator struct index) remap: HashMap, usize)>, + + // The number of generator states. 0 is unresumed, 1 is poisoned. So this is initialized to 2 bb_target_count: u32, + + // Map from a (which block to resume execution at, which block to use to drop the generator) to a + // genrator state bb_targets: HashMap<(BasicBlock, Option), u32>, + + // The original RETURN_POINTER local new_ret_local: Local, + + // The block to resume execution when for Return return_block: BasicBlock, - state_field: usize, } impl<'a, 'tcx> TransformVisitor<'a, 'tcx> { + // Make a GeneratorState rvalue fn make_state(&self, idx: usize, val: Operand<'tcx>) -> Rvalue<'tcx> { let adt = AggregateKind::Adt(self.state_adt_ref, idx, self.state_substs, None); Rvalue::Aggregate(box adt, vec![val]) } + // Create a Lvalue referencing a generator struct field fn make_field(&self, idx: usize, ty: Ty<'tcx>) -> Lvalue<'tcx> { let base = Lvalue::Local(Local::new(1)); let field = Projection { @@ -90,6 +104,7 @@ impl<'a, 'tcx> TransformVisitor<'a, 'tcx> { Lvalue::Projection(Box::new(field)) } + // Create a statement which changes the generator state fn set_state(&self, state_disc: u32, source_info: SourceInfo) -> Statement<'tcx> { let state = self.make_field(self.state_field, self.tcx.types.u32); let val = Operand::Constant(box Constant { @@ -112,6 +127,7 @@ impl<'a, 'tcx> MutVisitor<'tcx> for TransformVisitor<'a, 'tcx> { context: LvalueContext<'tcx>, location: Location) { if let Lvalue::Local(l) = *lvalue { + // Replace an Local in the remap with a generator struct access if let Some(&(ty, idx)) = self.remap.get(&l) { *lvalue = self.make_field(idx, ty); } @@ -135,6 +151,7 @@ impl<'a, 'tcx> MutVisitor<'tcx> for TransformVisitor<'a, 'tcx> { _ => None }; + // Remove StorageLive and StorageDead statements for remapped locals data.retain_statements(|s| { match s.kind { StatementKind::StorageLive(ref l) | StatementKind::StorageDead(ref l) => { @@ -172,16 +189,6 @@ impl<'a, 'tcx> MutVisitor<'tcx> for TransformVisitor<'a, 'tcx> { } } -fn ensure_generator_state_argument<'a, 'tcx>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, - node_id: NodeId, - def_id: DefId, - mir: &mut Mir<'tcx>) -> (Ty<'tcx>, GeneratorInterior<'tcx>) { - let interior = *tcx.typeck_tables_of(def_id).generator_interiors.get(&node_id).unwrap(); - let gen_ty = mir.local_decls.raw[1].ty; - (gen_ty, interior) -} - fn make_generator_state_argument_indirect<'a, 'tcx>( tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId, @@ -259,14 +266,21 @@ fn compute_layout<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, mir: &mut Mir<'tcx>) -> (HashMap, usize)>, GeneratorLayout<'tcx>) { + // Use a liveness analysis to compute locals which are live across a suspension point let live_locals = locals_live_across_suspend_points(tcx, mir, source); + // Erase regions from the types passed in from typeck so we can compare them with + // MIR types let allowed = tcx.erase_regions(&interior.as_slice()); for (local, decl) in mir.local_decls.iter_enumerated() { + // Ignore locals which are internal or not live if !live_locals.contains(&local) || decl.internal { continue; } + + // Sanity check that typeck knows about the type of locals which are + // live across a suspension point if !allowed.contains(&decl.ty) { span_bug!(mir.span, "Broken MIR: generator contains type {} in MIR, \ @@ -278,10 +292,17 @@ fn compute_layout<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let upvar_len = mir.upvar_decls.len(); let dummy_local = LocalDecl::new_internal(tcx.mk_nil(), mir.span); + + // Gather live locals and their indices replacing values in mir.local_decls with a dummy + // to avoid changing local indices let live_decls = live_locals.iter().map(|local| { let var = mem::replace(&mut mir.local_decls[local], dummy_local.clone()); (local, var) }); + + // Create a map from local indices to generator struct indices. + // These are offset by (upvar_len + 1) because of fields which comes before locals. + // We also create a vector of the LocalDecls of these locals. let (remap, vars) = live_decls.enumerate().map(|(idx, (local, var))| { ((local, (var.ty, upvar_len + 1 + idx)), var) }).unzip(); @@ -353,14 +374,16 @@ fn elaborate_generator_drops<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } } -fn generate_drop<'a, 'tcx>( +fn create_generator_drop_shim<'a, 'tcx>( tcx: TyCtxt<'a, 'tcx, 'tcx>, transform: &TransformVisitor<'a, 'tcx>, def_id: DefId, source: MirSource, gen_ty: Ty<'tcx>, - mir: &mut Mir<'tcx>, - drop_clean: BasicBlock) { + mir: &Mir<'tcx>, + drop_clean: BasicBlock) -> Mir<'tcx> { + let mut mir = mir.clone(); + let source_info = SourceInfo { span: mir.span, scope: ARGUMENT_VISIBILITY_SCOPE, @@ -393,7 +416,7 @@ fn generate_drop<'a, 'tcx>( targets: cases.iter().map(|&(_, d)| d).chain(once(return_block)).collect(), }; - insert_entry_point(mir, BasicBlockData { + insert_entry_point(&mut mir, BasicBlockData { statements: Vec::new(), terminator: Some(Terminator { source_info, @@ -425,7 +448,7 @@ fn generate_drop<'a, 'tcx>( is_user_variable: false, }; - make_generator_state_argument_indirect(tcx, def_id, mir); + make_generator_state_argument_indirect(tcx, def_id, &mut mir); // Change the generator argument from &mut to *mut mir.local_decls[Local::new(1)] = LocalDecl { @@ -442,12 +465,14 @@ fn generate_drop<'a, 'tcx>( // Make sure we remove dead blocks to remove // unrelated code from the resume part of the function - simplify::remove_dead_blocks(mir); + simplify::remove_dead_blocks(&mut mir); + + dump_mir(tcx, None, "generator_drop", &0, source, &mut mir); - dump_mir(tcx, None, "generator_drop", &0, source, mir); + mir } -fn insert_resume_after_return<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, +fn insert_panic_on_resume_after_return<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, mir: &mut Mir<'tcx>) { let assert_block = BasicBlock::new(mir.basic_blocks().len()); let term = TerminatorKind::Assert { @@ -479,12 +504,12 @@ fn insert_resume_after_return<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, }); } -fn generate_entry_point<'a, 'tcx>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, - mut transform: TransformVisitor<'a, 'tcx>, - def_id: DefId, - source: MirSource, - mir: &mut Mir<'tcx>) { +fn creator_generator_resume_function<'a, 'tcx>( + tcx: TyCtxt<'a, 'tcx, 'tcx>, + mut transform: TransformVisitor<'a, 'tcx>, + def_id: DefId, + source: MirSource, + mir: &mut Mir<'tcx>) { // Poison the generator when it unwinds for block in mir.basic_blocks_mut() { let source_info = block.terminator().source_info; @@ -555,7 +580,7 @@ fn generate_entry_point<'a, 'tcx>( dump_mir(tcx, None, "generator_resume", &0, source, mir); } -fn insert_clean_drop<'a, 'tcx>(mir: &mut Mir<'tcx>) -> (BasicBlock, BasicBlock) { +fn insert_clean_drop<'a, 'tcx>(mir: &mut Mir<'tcx>) -> BasicBlock { let source_info = SourceInfo { span: mir.span, scope: ARGUMENT_VISIBILITY_SCOPE, @@ -587,7 +612,7 @@ fn insert_clean_drop<'a, 'tcx>(mir: &mut Mir<'tcx>) -> (BasicBlock, BasicBlock) is_cleanup: false, }); - (return_block, drop_clean) + drop_clean } impl MirPass for StateTransform { @@ -607,25 +632,39 @@ impl MirPass for StateTransform { let node_id = source.item_id(); let def_id = tcx.hir.local_def_id(source.item_id()); - let (gen_ty, interior) = ensure_generator_state_argument(tcx, node_id, def_id, mir); + // Get the interior types which typeck computed + let interior = *tcx.typeck_tables_of(def_id).generator_interiors.get(&node_id).unwrap(); + // The first argument is the generator type passed by value + let gen_ty = mir.local_decls.raw[1].ty; + + // Compute GeneratorState let state_did = tcx.lang_items.gen_state().unwrap(); let state_adt_ref = tcx.adt_def(state_did); let state_substs = tcx.mk_substs([Kind::from(yield_ty), Kind::from(mir.return_ty)].iter()); let ret_ty = tcx.mk_adt(state_adt_ref, state_substs); + // We rename RETURN_POINTER which has type mir.return_ty to new_ret_local + // RETURN_POINTER then is a fresh unused local with type ret_ty. let new_ret_local = replace_result_variable(ret_ty, mir); + // Extract locals which are live across suspension point into `layout` + // `remap` gives a mapping from local indices onto generator struct indices let (remap, layout) = compute_layout(tcx, source, interior, mir); - let tail_block = BasicBlock::new(mir.basic_blocks().len()); - let state_field = mir.upvar_decls.len(); let mut bb_targets = HashMap::new(); + + // If we jump to the entry point, we should go to the initial 0 generator state. + // FIXME: Could this result in the need for destruction for state 0? bb_targets.insert((BasicBlock::new(0), None), 0); + // Run the transformation which converts Lvalues from Local to generator struct + // accesses for locals in `remap`. + // It also rewrites `return x` and `yield y` as writing a new generator state and returning + // GeneratorState::Complete(x) and GeneratorState::Yielded(y) respectively. let mut transform = TransformVisitor { tcx, state_adt_ref, @@ -634,39 +673,50 @@ impl MirPass for StateTransform { bb_target_count: 2, bb_targets, new_ret_local, - return_block: tail_block, state_field, + + // For returns we will resume execution at the next added basic block. + // This happens in `insert_panic_on_resume_after_return` + return_block: BasicBlock::new(mir.basic_blocks().len()), }; transform.visit_mir(mir); + // Update our MIR struct to reflect the changed we've made mir.return_ty = ret_ty; mir.yield_ty = None; mir.arg_count = 1; mir.spread_arg = None; mir.generator_layout = Some(layout); - insert_resume_after_return(tcx, mir); + // Panic if we resumed after returning + insert_panic_on_resume_after_return(tcx, mir); - let (_return_block, drop_clean) = insert_clean_drop(mir); + // Insert `drop(generator_struct)` which is used to drop upvars for generators in + // the unresumed (0) state. + // This is expanded to a drop ladder in `elaborate_generator_drops`. + let drop_clean = insert_clean_drop(mir); dump_mir(tcx, None, "generator_pre-elab", &0, source, mir); + // Expand `drop(generator_struct)` to a drop ladder which destroys upvars. + // If any upvars are moved out of, drop elaboration will handle upvar destruction. + // However we need to also elaborate the code generated by `insert_clean_drop`. elaborate_generator_drops(tcx, def_id, mir); dump_mir(tcx, None, "generator_post-transform", &0, source, mir); - let mut drop_impl = mir.clone(); - - generate_drop(tcx, - &transform, - def_id, - source, - gen_ty, - &mut drop_impl, - drop_clean); + // Create a copy of our MIR and use it to create the drop shim for the generator + let drop_shim = create_generator_drop_shim(tcx, + &transform, + def_id, + source, + gen_ty, + &mir, + drop_clean); - mir.generator_drop = Some(box drop_impl); + mir.generator_drop = Some(box drop_shim); - generate_entry_point(tcx, transform, def_id, source, mir); + // Create the Genreator::resume function + creator_generator_resume_function(tcx, transform, def_id, source, mir); } } From 91dde3eb2d886fa581a39a0968b027328b95658e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Fri, 11 Aug 2017 06:23:22 +0200 Subject: [PATCH 076/113] Typo --- src/librustc_mir/transform/generator.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs index 6a29de1361b0b..90bcc87b0c4a0 100644 --- a/src/librustc_mir/transform/generator.rs +++ b/src/librustc_mir/transform/generator.rs @@ -716,7 +716,7 @@ impl MirPass for StateTransform { mir.generator_drop = Some(box drop_shim); - // Create the Genreator::resume function + // Create the Generator::resume function creator_generator_resume_function(tcx, transform, def_id, source, mir); } } From be9c64b0c78401358a93b66e357d3bb094ba6274 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Fri, 11 Aug 2017 07:15:33 +0200 Subject: [PATCH 077/113] Store generator interior in MIR literals --- src/librustc/ich/impls_mir.rs | 8 ++++++-- src/librustc/mir/mod.rs | 13 +++++++------ src/librustc/mir/tcx.rs | 9 ++------- src/librustc/mir/visit.rs | 16 ++++++++++++++-- src/librustc_mir/build/expr/as_rvalue.rs | 6 +++--- src/librustc_mir/hair/cx/expr.rs | 10 +++++----- src/librustc_mir/hair/mod.rs | 4 ++-- src/librustc_mir/transform/generator.rs | 4 ++-- 8 files changed, 41 insertions(+), 29 deletions(-) diff --git a/src/librustc/ich/impls_mir.rs b/src/librustc/ich/impls_mir.rs index e277f40a26d9c..3d5de5579f0f9 100644 --- a/src/librustc/ich/impls_mir.rs +++ b/src/librustc/ich/impls_mir.rs @@ -442,11 +442,15 @@ for mir::AggregateKind<'tcx> { substs.hash_stable(hcx, hasher); active_field.hash_stable(hcx, hasher); } - mir::AggregateKind::Closure(def_id, ref substs) | - mir::AggregateKind::Generator(def_id, ref substs) => { + mir::AggregateKind::Closure(def_id, ref substs) => { def_id.hash_stable(hcx, hasher); substs.hash_stable(hcx, hasher); } + mir::AggregateKind::Generator(def_id, ref substs, ref interior) => { + def_id.hash_stable(hcx, hasher); + substs.hash_stable(hcx, hasher); + interior.hash_stable(hcx, hasher); + } } } } diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index 20e74f47c9e29..0d3629a8e5fee 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -21,7 +21,7 @@ use rustc_data_structures::control_flow_graph::ControlFlowGraph; use hir::def::CtorKind; use hir::def_id::DefId; use ty::subst::{Subst, Substs}; -use ty::{self, AdtDef, ClosureSubsts, Region, Ty}; +use ty::{self, AdtDef, ClosureSubsts, Region, Ty, GeneratorInterior}; use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; use util::ppaux; use rustc_back::slice; @@ -1260,7 +1260,7 @@ pub enum AggregateKind<'tcx> { /// number and is present only for union expressions. Adt(&'tcx AdtDef, usize, &'tcx Substs<'tcx>, Option), Closure(DefId, ClosureSubsts<'tcx>), - Generator(DefId, ClosureSubsts<'tcx>), + Generator(DefId, ClosureSubsts<'tcx>, GeneratorInterior<'tcx>), } #[derive(Copy, Clone, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable)] @@ -1423,7 +1423,7 @@ impl<'tcx> Debug for Rvalue<'tcx> { } }), - AggregateKind::Generator(def_id, _) => ty::tls::with(|tcx| { + AggregateKind::Generator(def_id, _, _) => ty::tls::with(|tcx| { if let Some(node_id) = tcx.hir.as_local_node_id(def_id) { let name = format!("[generator@{:?}]", tcx.hir.span(node_id)); let mut struct_fmt = fmt.debug_struct(&name); @@ -1892,8 +1892,8 @@ impl<'tcx> TypeFoldable<'tcx> for Rvalue<'tcx> { AggregateKind::Adt(def, v, substs.fold_with(folder), n), AggregateKind::Closure(id, substs) => AggregateKind::Closure(id, substs.fold_with(folder)), - AggregateKind::Generator(id, substs) => - AggregateKind::Generator(id, substs.fold_with(folder)), + AggregateKind::Generator(id, substs, interior) => + AggregateKind::Generator(id, substs.fold_with(folder), interior.fold_with(folder)), }; Aggregate(kind, fields.fold_with(folder)) } @@ -1920,7 +1920,8 @@ impl<'tcx> TypeFoldable<'tcx> for Rvalue<'tcx> { AggregateKind::Tuple => false, AggregateKind::Adt(_, _, substs, _) => substs.visit_with(visitor), AggregateKind::Closure(_, substs) => substs.visit_with(visitor), - AggregateKind::Generator(_, substs) => substs.visit_with(visitor), + AggregateKind::Generator(_, substs, interior) => substs.visit_with(visitor) || + interior.visit_with(visitor), }) || fields.visit_with(visitor) } } diff --git a/src/librustc/mir/tcx.rs b/src/librustc/mir/tcx.rs index 12588edbea9c0..14c53ee2dd782 100644 --- a/src/librustc/mir/tcx.rs +++ b/src/librustc/mir/tcx.rs @@ -202,13 +202,8 @@ impl<'tcx> Rvalue<'tcx> { AggregateKind::Closure(did, substs) => { tcx.mk_closure_from_closure_substs(did, substs) } - AggregateKind::Generator(did, substs) => { - let node_id = tcx.hir.as_local_node_id(did).unwrap(); - let interior = *tcx.typeck_tables_of(did) - .generator_interiors - .get(&node_id) - .unwrap(); - tcx.mk_generator(did, substs, interior.subst(tcx, substs.substs)) + AggregateKind::Generator(did, substs, interior) => { + tcx.mk_generator(did, substs, interior) } } } diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs index 8cc5b6cab116e..30ffa73019c96 100644 --- a/src/librustc/mir/visit.rs +++ b/src/librustc/mir/visit.rs @@ -11,7 +11,7 @@ use middle::const_val::ConstVal; use hir::def_id::DefId; use ty::subst::Substs; -use ty::{ClosureSubsts, Region, Ty}; +use ty::{ClosureSubsts, Region, Ty, GeneratorInterior}; use mir::*; use rustc_const_math::ConstUsize; use syntax_pos::Span; @@ -226,6 +226,12 @@ macro_rules! make_mir_visitor { self.super_closure_substs(substs); } + fn visit_generator_interior(&mut self, + interior: & $($mutability)* GeneratorInterior<'tcx>, + _: Location) { + self.super_generator_interior(interior); + } + fn visit_const_val(&mut self, const_val: & $($mutability)* ConstVal, _: Location) { @@ -570,9 +576,11 @@ macro_rules! make_mir_visitor { self.visit_closure_substs(closure_substs, location); } AggregateKind::Generator(ref $($mutability)* def_id, - ref $($mutability)* closure_substs) => { + ref $($mutability)* closure_substs, + ref $($mutability)* interior) => { self.visit_def_id(def_id, location); self.visit_closure_substs(closure_substs, location); + self.visit_generator_interior(interior, location); } } @@ -742,6 +750,10 @@ macro_rules! make_mir_visitor { fn super_substs(&mut self, _substs: & $($mutability)* &'tcx Substs<'tcx>) { } + fn super_generator_interior(&mut self, + _interior: & $($mutability)* GeneratorInterior<'tcx>) { + } + fn super_closure_substs(&mut self, _substs: & $($mutability)* ClosureSubsts<'tcx>) { } diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs index d585672d6da23..b2a3867924010 100644 --- a/src/librustc_mir/build/expr/as_rvalue.rs +++ b/src/librustc_mir/build/expr/as_rvalue.rs @@ -179,12 +179,12 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { block.and(Rvalue::Aggregate(box AggregateKind::Tuple, fields)) } - ExprKind::Closure { closure_id, substs, upvars, generator } => { // see (*) above + ExprKind::Closure { closure_id, substs, upvars, interior } => { // see (*) above let mut operands: Vec<_> = upvars.into_iter() .map(|upvar| unpack!(block = this.as_operand(block, scope, upvar))) .collect(); - let result = if generator { + let result = if let Some(interior) = interior { // Add the state operand operands.push(Operand::Constant(box Constant { span: expr_span, @@ -193,7 +193,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { value: ConstVal::Integral(ConstInt::U32(0)), }, })); - box AggregateKind::Generator(closure_id, substs) + box AggregateKind::Generator(closure_id, substs, interior) } else { box AggregateKind::Closure(closure_id, substs) }; diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index a81103213b841..b8b69382d7d0d 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -428,11 +428,11 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, } } - hir::ExprClosure(.., is_generator) => { + hir::ExprClosure(..) => { let closure_ty = cx.tables().expr_ty(expr); - let (def_id, substs) = match closure_ty.sty { - ty::TyClosure(def_id, substs) | - ty::TyGenerator(def_id, substs, _) => (def_id, substs), + let (def_id, substs, interior) = match closure_ty.sty { + ty::TyClosure(def_id, substs) => (def_id, substs, None), + ty::TyGenerator(def_id, substs, interior) => (def_id, substs, Some(interior)), _ => { span_bug!(expr.span, "closure expr w/o closure type: {:?}", closure_ty); } @@ -447,7 +447,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, closure_id: def_id, substs: substs, upvars: upvars, - generator: is_generator, + interior, } } diff --git a/src/librustc_mir/hair/mod.rs b/src/librustc_mir/hair/mod.rs index ff239a2adddd3..89d0260fb9f5d 100644 --- a/src/librustc_mir/hair/mod.rs +++ b/src/librustc_mir/hair/mod.rs @@ -19,7 +19,7 @@ use rustc::mir::{BinOp, BorrowKind, Field, Literal, UnOp}; use rustc::hir::def_id::DefId; use rustc::middle::region::CodeExtent; use rustc::ty::subst::Substs; -use rustc::ty::{self, AdtDef, ClosureSubsts, Region, Ty}; +use rustc::ty::{self, AdtDef, ClosureSubsts, Region, Ty, GeneratorInterior}; use rustc::hir; use syntax::ast; use syntax_pos::Span; @@ -239,7 +239,7 @@ pub enum ExprKind<'tcx> { closure_id: DefId, substs: ClosureSubsts<'tcx>, upvars: Vec>, - generator: bool, + interior: Option>, }, Literal { literal: Literal<'tcx>, diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs index 90bcc87b0c4a0..651246ab4a5e3 100644 --- a/src/librustc_mir/transform/generator.rs +++ b/src/librustc_mir/transform/generator.rs @@ -76,8 +76,8 @@ struct TransformVisitor<'a, 'tcx: 'a> { // The number of generator states. 0 is unresumed, 1 is poisoned. So this is initialized to 2 bb_target_count: u32, - // Map from a (which block to resume execution at, which block to use to drop the generator) to a - // genrator state + // Map from a (which block to resume execution at, which block to use to drop the generator) + // to a generator state bb_targets: HashMap<(BasicBlock, Option), u32>, // The original RETURN_POINTER local From 6601ab9b1b569f81df9afa199de77cc205132e0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Fri, 11 Aug 2017 07:35:01 +0200 Subject: [PATCH 078/113] Remove allocations --- src/librustc/ty/sty.rs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index 9898ce5d73daa..2a310e1d5df78 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -270,22 +270,20 @@ impl<'a, 'gcx, 'tcx> ClosureSubsts<'tcx> { /// It is calculated in rustc_mir::transform::generator::StateTransform. /// All the types here must be in the tuple in GeneratorInterior. pub fn state_tys(self, def_id: DefId, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> - impl Iterator> + 'tcx + impl Iterator> + 'a { let state = tcx.generator_layout(def_id).fields.iter(); - let state: Vec<_> = state.map(|d| d.ty.subst(tcx, self.substs)).collect(); - state.into_iter() + state.map(move |d| d.ty.subst(tcx, self.substs)) } /// This is the types of all the fields stored in a generator. /// It includes the upvars, state types and the state discriminant which is u32. pub fn field_tys(self, def_id: DefId, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> - impl Iterator> + 'tcx + impl Iterator> + 'a { let upvars = self.upvar_tys(def_id, tcx); let state = self.state_tys(def_id, tcx); - let tys: Vec<_> = upvars.chain(iter::once(tcx.types.u32)).chain(state).collect(); - tys.into_iter() + upvars.chain(iter::once(tcx.types.u32)).chain(state) } } From 54db165f8e7a8cd37414039e8ed76ae115f5563e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Fri, 11 Aug 2017 08:26:06 +0200 Subject: [PATCH 079/113] Implement a cache for looking up yields --- src/librustc/middle/region.rs | 62 ++++++++++++++----- src/librustc_borrowck/borrowck/mod.rs | 4 +- .../check/generator_interior.rs | 7 ++- 3 files changed, 53 insertions(+), 20 deletions(-) diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index 82e2a2114da5e..1f75d09c31724 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -24,6 +24,7 @@ use std::mem; use std::rc::Rc; use syntax::codemap; use syntax::ast; +use syntax::ast::NodeId; use syntax_pos::Span; use ty::TyCtxt; use ty::maps::Providers; @@ -1167,29 +1168,56 @@ fn region_maps<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) Rc::new(maps) } -struct YieldFinder(Option); +struct YieldFinder<'a> { + cache: &'a mut FxHashMap>, + result: Option, +} + +impl<'a> YieldFinder<'a> { + fn lookup(&mut self, id: NodeId, f: F) { + if let Some(result) = self.cache.get(&id) { + self.result = *result; + return; + } + if self.result.is_some() { + return; + } + f(self); + self.cache.insert(id, self.result); + } +} -impl<'tcx> Visitor<'tcx> for YieldFinder { +impl<'a, 'tcx> Visitor<'tcx> for YieldFinder<'a> { fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> { NestedVisitorMap::None } fn visit_expr(&mut self, expr: &'tcx hir::Expr) { if let hir::ExprYield(..) = expr.node { - if self.0.is_none() { - self.0 = Some(expr.span); - } + self.result = Some(expr.span); + return; } - intravisit::walk_expr(self, expr); + self.lookup(expr.id, |this| { + intravisit::walk_expr(this, expr); + }); + } + + fn visit_block(&mut self, block: &'tcx hir::Block) { + self.lookup(block.id, |this| { + intravisit::walk_block(this, block); + }); } } impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { /// Checks whether the given code extent contains a `yield`. If so, - /// returns `Some(span)` with the span of the "first" yield we find. - pub fn yield_in_extent(self, extent: CodeExtent) -> Option { - let mut finder = YieldFinder(None); + /// returns `Some(span)` with the span of a yield we found. + pub fn yield_in_extent(self, extent: CodeExtent, cache: &mut FxHashMap>) -> Option { + let mut finder = YieldFinder { + cache, + result: None, + }; match extent { CodeExtent::DestructionScope(node_id) | @@ -1199,33 +1227,33 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { Node::NodeTraitItem(_) | Node::NodeImplItem(_) => { let body = self.hir.body(self.hir.body_owned_by(node_id)); - intravisit::walk_body(&mut finder, body); + finder.visit_body(body); } - Node::NodeExpr(expr) => intravisit::walk_expr(&mut finder, expr), - Node::NodeStmt(stmt) => intravisit::walk_stmt(&mut finder, stmt), - Node::NodeBlock(block) => intravisit::walk_block(&mut finder, block), + Node::NodeExpr(expr) => finder.visit_expr(expr), + Node::NodeStmt(stmt) => finder.visit_stmt(stmt), + Node::NodeBlock(block) => finder.visit_block(block), _ => bug!(), } } CodeExtent::CallSiteScope(body_id) | CodeExtent::ParameterScope(body_id) => { - intravisit::walk_body(&mut finder, self.hir.body(body_id)) + finder.visit_body(self.hir.body(body_id)) } CodeExtent::Remainder(r) => { if let Node::NodeBlock(block) = self.hir.get(r.block) { for stmt in &block.stmts[(r.first_statement_index as usize + 1)..] { - intravisit::walk_stmt(&mut finder, stmt); + finder.visit_stmt(stmt); } - block.expr.as_ref().map(|e| intravisit::walk_expr(&mut finder, e)); + block.expr.as_ref().map(|e| finder.visit_expr(e)); } else { bug!() } } } - finder.0 + finder.result } } diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index 41771738ac623..ca047b0d488ab 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -36,7 +36,7 @@ use rustc::middle::region::{self, RegionMaps}; use rustc::middle::free_region::RegionRelations; use rustc::ty::{self, TyCtxt}; use rustc::ty::maps::Providers; - +use rustc::util::nodemap::FxHashMap; use std::fmt; use std::rc::Rc; use std::hash::{Hash, Hasher}; @@ -827,7 +827,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { // block remainder that starts with // `let a`) for a yield. We can cite // that for the user. - self.tcx.yield_in_extent(value_extent) + self.tcx.yield_in_extent(value_extent, &mut FxHashMap()) } else { None } diff --git a/src/librustc_typeck/check/generator_interior.rs b/src/librustc_typeck/check/generator_interior.rs index 6753d42b0c549..a5440e6d99216 100644 --- a/src/librustc_typeck/check/generator_interior.rs +++ b/src/librustc_typeck/check/generator_interior.rs @@ -14,12 +14,16 @@ use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap}; use rustc::hir::{self, Body, Pat, PatKind, Expr}; use rustc::middle::region::{RegionMaps, CodeExtent}; use rustc::ty::Ty; +use syntax::ast::NodeId; +use syntax::codemap::Span; use std::rc::Rc; use super::FnCtxt; use util::nodemap::FxHashSet; +use util::nodemap::FxHashMap; struct InteriorVisitor<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { fcx: &'a FnCtxt<'a, 'gcx, 'tcx>, + cache: FxHashMap>, types: FxHashSet>, region_maps: Rc, } @@ -28,7 +32,7 @@ impl<'a, 'gcx, 'tcx> InteriorVisitor<'a, 'gcx, 'tcx> { fn record(&mut self, ty: Ty<'tcx>, scope: Option, expr: Option<&'tcx Expr>) { use syntax_pos::DUMMY_SP; - if scope.map(|s| self.fcx.tcx.yield_in_extent(s).is_some()).unwrap_or(true) { + if scope.map(|s| self.fcx.tcx.yield_in_extent(s, &mut self.cache).is_some()).unwrap_or(true) { if log_enabled!(log::LogLevel::Debug) { if let Some(s) = scope { let span = s.span(&self.fcx.tcx.hir).unwrap_or(DUMMY_SP); @@ -61,6 +65,7 @@ pub fn resolve_interior<'a, 'gcx, 'tcx>(fcx: &'a FnCtxt<'a, 'gcx, 'tcx>, let mut visitor = InteriorVisitor { fcx, types: FxHashSet(), + cache: FxHashMap(), region_maps: fcx.tcx.region_maps(def_id), }; intravisit::walk_body(&mut visitor, body); From 2e3eaca0fab10bc7495dd04652462071a82dfd31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Fri, 11 Aug 2017 09:25:44 +0200 Subject: [PATCH 080/113] Please tidy --- src/librustc/middle/region.rs | 4 +++- src/librustc/mir/mod.rs | 4 +++- src/librustc_typeck/check/generator_interior.rs | 6 +++++- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index 1f75d09c31724..9d28e2f496dfc 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -1213,7 +1213,9 @@ impl<'a, 'tcx> Visitor<'tcx> for YieldFinder<'a> { impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { /// Checks whether the given code extent contains a `yield`. If so, /// returns `Some(span)` with the span of a yield we found. - pub fn yield_in_extent(self, extent: CodeExtent, cache: &mut FxHashMap>) -> Option { + pub fn yield_in_extent(self, + extent: CodeExtent, + cache: &mut FxHashMap>) -> Option { let mut finder = YieldFinder { cache, result: None, diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index 0d3629a8e5fee..6484572d2243c 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -1893,7 +1893,9 @@ impl<'tcx> TypeFoldable<'tcx> for Rvalue<'tcx> { AggregateKind::Closure(id, substs) => AggregateKind::Closure(id, substs.fold_with(folder)), AggregateKind::Generator(id, substs, interior) => - AggregateKind::Generator(id, substs.fold_with(folder), interior.fold_with(folder)), + AggregateKind::Generator(id, + substs.fold_with(folder), + interior.fold_with(folder)), }; Aggregate(kind, fields.fold_with(folder)) } diff --git a/src/librustc_typeck/check/generator_interior.rs b/src/librustc_typeck/check/generator_interior.rs index a5440e6d99216..5bfcf77cda89f 100644 --- a/src/librustc_typeck/check/generator_interior.rs +++ b/src/librustc_typeck/check/generator_interior.rs @@ -32,7 +32,11 @@ impl<'a, 'gcx, 'tcx> InteriorVisitor<'a, 'gcx, 'tcx> { fn record(&mut self, ty: Ty<'tcx>, scope: Option, expr: Option<&'tcx Expr>) { use syntax_pos::DUMMY_SP; - if scope.map(|s| self.fcx.tcx.yield_in_extent(s, &mut self.cache).is_some()).unwrap_or(true) { + let live_across_yield = scope.map(|s| { + self.fcx.tcx.yield_in_extent(s, &mut self.cache).is_some() + }).unwrap_or(true); + + if live_across_yield { if log_enabled!(log::LogLevel::Debug) { if let Some(s) = scope { let span = s.span(&self.fcx.tcx.hir).unwrap_or(DUMMY_SP); From 2b04afba632711eb205574ad03d086efdd4d11e0 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 11 Aug 2017 09:54:28 -0700 Subject: [PATCH 081/113] Fix xcrate generator test --- src/test/run-pass/generator/xcrate.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/run-pass/generator/xcrate.rs b/src/test/run-pass/generator/xcrate.rs index 7db567938290b..dc7a6fdef9c7e 100644 --- a/src/test/run-pass/generator/xcrate.rs +++ b/src/test/run-pass/generator/xcrate.rs @@ -27,7 +27,7 @@ fn main() { let mut foo = xcrate::bar(3); match foo.resume() { - GeneratorState::Yielded(4) => {} + GeneratorState::Yielded(3) => {} s => panic!("bad state: {:?}", s), } match foo.resume() { From 84af3d8f3ba0baeb962ade6ddf1b0193753d903d Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 11 Aug 2017 13:09:25 -0700 Subject: [PATCH 082/113] Fix an error in diagnostic codes --- src/librustc_typeck/diagnostics.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index f5ecedcebb493..6f7e2c80112fc 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -4649,7 +4649,7 @@ A private item was used outside of its scope. Erroneous code example: -```compile_fail,E0627 +```compile_fail,E0624 mod inner { pub struct Foo; From fa18aa35206b52b3081d5200c21700f3a109ba65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Sat, 12 Aug 2017 07:06:34 +0200 Subject: [PATCH 083/113] Strip landing pads in the state transformation --- src/librustc_mir/transform/generator.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs index 651246ab4a5e3..29c24ef41ecb5 100644 --- a/src/librustc_mir/transform/generator.rs +++ b/src/librustc_mir/transform/generator.rs @@ -27,6 +27,7 @@ use std::borrow::Cow; use std::iter::once; use std::mem; use transform::simplify; +use transform::no_landing_pads::no_landing_pads; pub struct StateTransform; @@ -463,6 +464,8 @@ fn create_generator_drop_shim<'a, 'tcx>( is_user_variable: false, }; + no_landing_pads(tcx, &mut mir); + // Make sure we remove dead blocks to remove // unrelated code from the resume part of the function simplify::remove_dead_blocks(&mut mir); @@ -573,6 +576,8 @@ fn creator_generator_resume_function<'a, 'tcx>( make_generator_state_argument_indirect(tcx, def_id, mir); + no_landing_pads(tcx, &mut mir); + // Make sure we remove dead blocks to remove // unrelated code from the drop part of the function simplify::remove_dead_blocks(mir); From 1787d4ecf52b886d2094ddd901d64ec66c715219 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Sat, 12 Aug 2017 07:37:17 +0200 Subject: [PATCH 084/113] Fix errors --- src/librustc_mir/build/scope.rs | 8 -------- src/librustc_mir/transform/generator.rs | 2 +- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/src/librustc_mir/build/scope.rs b/src/librustc_mir/build/scope.rs index c35f709a528a2..f530cac9397d3 100644 --- a/src/librustc_mir/build/scope.rs +++ b/src/librustc_mir/build/scope.rs @@ -433,7 +433,6 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { self.diverge_cleanup_gen(true); let src_info = self.scopes[0].source_info(self.fn_span); - let tmp = self.get_unit_temp(); let mut block = self.cfg.start_new_block(); let result = block; let mut rest = &mut self.scopes[..]; @@ -463,13 +462,6 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // End all regions for scopes out of which we are breaking. self.cfg.push_end_region(block, src_info, scope.extent); - - if let Some(ref free_data) = scope.free { - let next = self.cfg.start_new_block(); - let free = build_free(self.hir.tcx(), &tmp, free_data, next); - self.cfg.terminate(block, scope.source_info(free_data.span), free); - block = next; - } } self.cfg.terminate(block, src_info, TerminatorKind::GeneratorDrop); diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs index 29c24ef41ecb5..e0b9ed4c1c9cd 100644 --- a/src/librustc_mir/transform/generator.rs +++ b/src/librustc_mir/transform/generator.rs @@ -576,7 +576,7 @@ fn creator_generator_resume_function<'a, 'tcx>( make_generator_state_argument_indirect(tcx, def_id, mir); - no_landing_pads(tcx, &mut mir); + no_landing_pads(tcx, mir); // Make sure we remove dead blocks to remove // unrelated code from the drop part of the function From 6eab1ca9dd332f0c4a66086c15eaaf392169af56 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Sat, 12 Aug 2017 11:36:00 -0700 Subject: [PATCH 085/113] Fix UI test --- src/test/ui/generator/not-send-sync.stderr | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/test/ui/generator/not-send-sync.stderr b/src/test/ui/generator/not-send-sync.stderr index a1f110accc100..e0c32a95e0d9b 100644 --- a/src/test/ui/generator/not-send-sync.stderr +++ b/src/test/ui/generator/not-send-sync.stderr @@ -9,15 +9,15 @@ error[E0277]: the trait bound `std::cell::Cell: std::marker::Sync` is not s = note: required because it appears within the type `[generator@$DIR/not-send-sync.rs:26:17: 30:6 a:&std::cell::Cell _]` = note: required by `main::assert_send` -error[E0277]: the trait bound `std::cell::Cell: std::marker::Sync` is not satisfied in `[generator@$DIR/not-send-sync.rs:19:17: 23:6 (std::cell::Cell, ())]` +error[E0277]: the trait bound `std::cell::Cell: std::marker::Sync` is not satisfied in `[generator@$DIR/not-send-sync.rs:19:17: 23:6 ((), std::cell::Cell)]` --> $DIR/not-send-sync.rs:19:5 | 19 | assert_sync(|| { | ^^^^^^^^^^^ `std::cell::Cell` cannot be shared between threads safely | - = help: within `[generator@$DIR/not-send-sync.rs:19:17: 23:6 (std::cell::Cell, ())]`, the trait `std::marker::Sync` is not implemented for `std::cell::Cell` - = note: required because it appears within the type `(std::cell::Cell, ())` - = note: required because it appears within the type `[generator@$DIR/not-send-sync.rs:19:17: 23:6 (std::cell::Cell, ())]` + = help: within `[generator@$DIR/not-send-sync.rs:19:17: 23:6 ((), std::cell::Cell)]`, the trait `std::marker::Sync` is not implemented for `std::cell::Cell` + = note: required because it appears within the type `((), std::cell::Cell)` + = note: required because it appears within the type `[generator@$DIR/not-send-sync.rs:19:17: 23:6 ((), std::cell::Cell)]` = note: required by `main::assert_sync` error: aborting due to 2 previous errors From eff2884e5ff3eaa5338e3308ac6e6a2bfbd0b664 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Mon, 14 Aug 2017 07:23:35 +0200 Subject: [PATCH 086/113] Make generator interior types deterministic --- .../check/generator_interior.rs | 42 +++++++------------ 1 file changed, 15 insertions(+), 27 deletions(-) diff --git a/src/librustc_typeck/check/generator_interior.rs b/src/librustc_typeck/check/generator_interior.rs index 5bfcf77cda89f..f50fb7e4a1326 100644 --- a/src/librustc_typeck/check/generator_interior.rs +++ b/src/librustc_typeck/check/generator_interior.rs @@ -18,13 +18,14 @@ use syntax::ast::NodeId; use syntax::codemap::Span; use std::rc::Rc; use super::FnCtxt; -use util::nodemap::FxHashSet; use util::nodemap::FxHashMap; struct InteriorVisitor<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { fcx: &'a FnCtxt<'a, 'gcx, 'tcx>, cache: FxHashMap>, - types: FxHashSet>, + + // FIXME: Use an ordered hash map here + types: Vec>, region_maps: Rc, } @@ -37,26 +38,19 @@ impl<'a, 'gcx, 'tcx> InteriorVisitor<'a, 'gcx, 'tcx> { }).unwrap_or(true); if live_across_yield { + let ty = self.fcx.resolve_type_vars_if_possible(&ty); + if log_enabled!(log::LogLevel::Debug) { - if let Some(s) = scope { - let span = s.span(&self.fcx.tcx.hir).unwrap_or(DUMMY_SP); - debug!("type in generator with scope = {:?}, type = {:?}, span = {:?}", - scope, - self.fcx.resolve_type_vars_if_possible(&ty), - span); - } else { - debug!("type in generator WITHOUT scope, type = {:?}", - self.fcx.resolve_type_vars_if_possible(&ty)); - } - if let Some(e) = expr { - debug!("type from expression: {:?}, span={:?}", e, e.span); - } + let span = scope.map(|s| s.span(&self.fcx.tcx.hir).unwrap_or(DUMMY_SP)); + debug!("type in expr = {:?}, scope = {:?}, type = {:?}, span = {:?}", + expr, scope, ty, span); } - self.types.insert(ty); - } else { - if let Some(e) = expr { - debug!("NO type from expression: {:?}, span = {:?}", e, e.span); + + if !self.types.contains(&ty) { + self.types.push(ty); } + } else { + debug!("no type in expr = {:?}, span = {:?}", expr, expr.map(|e| e.span)); } } } @@ -68,19 +62,13 @@ pub fn resolve_interior<'a, 'gcx, 'tcx>(fcx: &'a FnCtxt<'a, 'gcx, 'tcx>, let body = fcx.tcx.hir.body(body_id); let mut visitor = InteriorVisitor { fcx, - types: FxHashSet(), + types: Vec::new(), cache: FxHashMap(), region_maps: fcx.tcx.region_maps(def_id), }; intravisit::walk_body(&mut visitor, body); - // Deduplicate types - let set: FxHashSet<_> = visitor.types.into_iter() - .map(|t| fcx.resolve_type_vars_if_possible(&t)) - .collect(); - let types: Vec<_> = set.into_iter().collect(); - - let tuple = fcx.tcx.intern_tup(&types, false); + let tuple = fcx.tcx.intern_tup(&visitor.types, false); debug!("Types in generator {:?}, span = {:?}", tuple, body.value.span); From b045c201b2086073f43d76290b9cb2a5a8e16f89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Mon, 14 Aug 2017 14:11:35 +0200 Subject: [PATCH 087/113] Use a DepNode for the generator signature --- src/librustc/dep_graph/dep_node.rs | 1 + src/librustc/ty/maps.rs | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index 5b609f192e1c2..f4143e9b22e82 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -432,6 +432,7 @@ define_dep_nodes!( <'tcx> [] ImplPolarity(DefId), [] ClosureKind(DefId), [] FnSignature(DefId), + [] GenSignature(DefId), [] CoerceUnsizedInfo(DefId), [] ItemVarianceConstraints(DefId), diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs index b121c05f244fd..ba3cd5ba3910f 100644 --- a/src/librustc/ty/maps.rs +++ b/src/librustc/ty/maps.rs @@ -919,7 +919,7 @@ define_maps! { <'tcx> /// Records the signature of each generator. The def ID is the ID of the /// expression defining the closure. - [] generator_sig: TypeckTables(DefId) -> Option>, + [] generator_sig: GenSignature(DefId) -> Option>, /// Caches CoerceUnsized kinds for impls on custom types. [] coerce_unsized_info: CoerceUnsizedInfo(DefId) From 22ebcaca168dd929f8d99a66fb9d348f615c6cc1 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 14 Aug 2017 19:38:32 -0700 Subject: [PATCH 088/113] Choose another error code --- src/librustc/diagnostics.rs | 2 +- src/librustc/hir/lowering.rs | 2 +- src/test/ui/generator/no-arguments-on-generators.stderr | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index 23616b4bc3851..480e6ee1bc5e3 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -2026,5 +2026,5 @@ register_diagnostics! { E0495, // cannot infer an appropriate lifetime due to conflicting requirements E0566, // conflicting representation hints E0623, // lifetime mismatch where both parameters are anonymous regions - E0625, // generators cannot have explicit arguments + E0628, // generators cannot have explicit arguments } diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index f7ffda03f2384..fed06128cc9b8 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -1980,7 +1980,7 @@ impl<'a> LoweringContext<'a> { e }); if is_generator && !decl.inputs.is_empty() { - span_err!(this.sess, fn_decl_span, E0625, + span_err!(this.sess, fn_decl_span, E0628, "generators cannot have explicit arguments"); this.sess.abort_if_errors(); } diff --git a/src/test/ui/generator/no-arguments-on-generators.stderr b/src/test/ui/generator/no-arguments-on-generators.stderr index 290ad7b7f6c6a..4d2e228685ae3 100644 --- a/src/test/ui/generator/no-arguments-on-generators.stderr +++ b/src/test/ui/generator/no-arguments-on-generators.stderr @@ -1,4 +1,4 @@ -error[E0625]: generators cannot have explicit arguments +error[E0628]: generators cannot have explicit arguments --> $DIR/no-arguments-on-generators.rs:14:15 | 14 | let gen = |start| { //~ ERROR generators cannot have explicit arguments From b6b9690a76d4dd4796ac5aaef71385b9240452af Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 14 Aug 2017 20:12:13 -0700 Subject: [PATCH 089/113] Fix merge conflicts with `gen` branch --- src/librustc/infer/mod.rs | 3 +- src/librustc/middle/mem_categorization.rs | 2 +- src/librustc/middle/reachable.rs | 2 +- src/librustc/ty/context.rs | 44 +++++++++++++++++++++-- src/librustc_mir/build/mod.rs | 4 +-- src/librustc_mir/transform/generator.rs | 3 +- src/librustc_typeck/check/mod.rs | 12 ++++--- src/librustc_typeck/check/writeback.rs | 24 +++++++++---- src/librustc_typeck/collect.rs | 3 +- 9 files changed, 76 insertions(+), 21 deletions(-) diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 11f3da3c2081e..f09dc8a67c82b 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -1367,7 +1367,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { pub fn generator_sig(&self, def_id: DefId) -> Option> { if let Some(tables) = self.in_progress_tables { if let Some(id) = self.tcx.hir.as_local_node_id(def_id) { - if let Some(&ty) = tables.borrow().generator_sigs.get(&id) { + let hir_id = self.tcx.hir.node_to_hir_id(id); + if let Some(&ty) = tables.borrow().generator_sigs().get(hir_id) { return ty.map(|t| ty::Binder(t)); } } diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 354930be441fa..00ad0678e0d37 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -728,7 +728,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { let kind = match self.tables.closure_kinds().get(fn_hir_id) { Some(&(kind, _)) => kind, None => { - let ty = self.node_ty(fn_node_id)?; + let ty = self.node_ty(fn_hir_id)?; match ty.sty { ty::TyGenerator(..) => ty::ClosureKind::FnOnce, _ => span_bug!(span, "missing closure kind"), diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs index 666f71cca06bb..3efc696f2a50a 100644 --- a/src/librustc/middle/reachable.rs +++ b/src/librustc/middle/reachable.rs @@ -296,7 +296,7 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> { hir::ImplItemKind::Type(_) => {} } } - hir_map::NodeExpr(&hir::Expr { node: hir::ExprClosure(.., body, _), .. }) => { + hir_map::NodeExpr(&hir::Expr { node: hir::ExprClosure(.., body, _, _), .. }) => { self.visit_nested_body(body); } // Nothing to recurse on for these diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 18478f7c61d72..51269534dcfea 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -340,9 +340,9 @@ pub struct TypeckTables<'tcx> { /// that caused the closure to be this kind. closure_kinds: ItemLocalMap<(ty::ClosureKind, Option<(Span, ast::Name)>)>, - pub generator_sigs: ItemLocalMap>>, + generator_sigs: ItemLocalMap>>, - pub generator_interiors: ItemLocalMap>, + generator_interiors: ItemLocalMap>, /// For each fn, records the "liberated" types of its arguments /// and return type. Liberated means that all bound regions @@ -640,6 +640,42 @@ impl<'tcx> TypeckTables<'tcx> { data: &mut self.cast_kinds } } + + pub fn generator_sigs(&self) + -> LocalTableInContext>> + { + LocalTableInContext { + local_id_root: self.local_id_root, + data: &self.generator_sigs, + } + } + + pub fn generator_sigs_mut(&mut self) + -> LocalTableInContextMut>> + { + LocalTableInContextMut { + local_id_root: self.local_id_root, + data: &mut self.generator_sigs, + } + } + + pub fn generator_interiors(&self) + -> LocalTableInContext> + { + LocalTableInContext { + local_id_root: self.local_id_root, + data: &self.generator_interiors, + } + } + + pub fn generator_interiors_mut(&mut self) + -> LocalTableInContextMut> + { + LocalTableInContextMut { + local_id_root: self.local_id_root, + data: &mut self.generator_interiors, + } + } } impl<'a, 'gcx, 'tcx> HashStable> for TypeckTables<'gcx> { @@ -664,6 +700,8 @@ impl<'a, 'gcx, 'tcx> HashStable> for Typeck ref used_trait_imports, tainted_by_errors, ref free_region_map, + ref generator_sigs, + ref generator_interiors, } = *self; hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| { @@ -697,6 +735,8 @@ impl<'a, 'gcx, 'tcx> HashStable> for Typeck ich::hash_stable_itemlocalmap(hcx, hasher, liberated_fn_sigs); ich::hash_stable_itemlocalmap(hcx, hasher, fru_field_types); ich::hash_stable_itemlocalmap(hcx, hasher, cast_kinds); + ich::hash_stable_itemlocalmap(hcx, hasher, generator_sigs); + ich::hash_stable_itemlocalmap(hcx, hasher, generator_interiors); ich::hash_stable_hashset(hcx, hasher, used_trait_imports, |hcx, def_id| { hcx.def_path_hash(*def_id) diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index cb3ad6743a7dc..afede7e89c068 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -103,7 +103,7 @@ pub fn mir_build<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Mir<'t Some((closure_self_ty(tcx, id, body_id), None)) } ty::TyGenerator(..) => { - let gen_ty = tcx.body_tables(body_id).node_id_to_type(id); + let gen_ty = tcx.body_tables(body_id).node_id_to_type(fn_hir_id); Some((gen_ty, None)) } _ => None, @@ -121,7 +121,7 @@ pub fn mir_build<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Mir<'t let arguments = implicit_argument.into_iter().chain(explicit_arguments); let (yield_ty, return_ty) = if body.is_generator { - let gen_sig = cx.tables().generator_sigs[&id].clone().unwrap(); + let gen_sig = cx.tables().generator_sigs()[fn_hir_id].clone().unwrap(); (Some(gen_sig.yield_ty), gen_sig.return_ty) } else { (None, fn_sig.output()) diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs index e0b9ed4c1c9cd..b4d6bb09a157e 100644 --- a/src/librustc_mir/transform/generator.rs +++ b/src/librustc_mir/transform/generator.rs @@ -636,9 +636,10 @@ impl MirPass for StateTransform { let node_id = source.item_id(); let def_id = tcx.hir.local_def_id(source.item_id()); + let hir_id = tcx.hir.node_to_hir_id(node_id); // Get the interior types which typeck computed - let interior = *tcx.typeck_tables_of(def_id).generator_interiors.get(&node_id).unwrap(); + let interior = *tcx.typeck_tables_of(def_id).generator_interiors().get(hir_id).unwrap(); // The first argument is the generator type passed by value let gen_ty = mir.local_decls.raw[1].ty; diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index ff96f3db7ebb4..bdacf4f343547 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -750,7 +750,8 @@ fn generator_sig<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Option> { let node_id = tcx.hir.as_local_node_id(def_id).unwrap(); - tcx.typeck_tables_of(def_id).generator_sigs[&node_id].map(|s| ty::Binder(s)) + let hir_id = tcx.hir.node_to_hir_id(node_id); + tcx.typeck_tables_of(def_id).generator_sigs()[hir_id].map(|s| ty::Binder(s)) } fn closure_kind<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, @@ -1050,25 +1051,26 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>, fcx.write_ty(arg.hir_id, arg_ty); } + let fn_hir_id = fcx.tcx.hir.node_to_hir_id(fn_id); let gen_ty = if can_be_generator && body.is_generator { let gen_sig = ty::GenSig { yield_ty: fcx.yield_ty.unwrap(), return_ty: ret_ty, }; - inherited.tables.borrow_mut().generator_sigs.insert(fn_hir_id, Some(gen_sig)); + inherited.tables.borrow_mut().generator_sigs_mut().insert(fn_hir_id, Some(gen_sig)); let witness = fcx.next_ty_var(TypeVariableOrigin::MiscVariable(span)); fcx.deferred_generator_interiors.borrow_mut().push((body.id(), witness)); let interior = ty::GeneratorInterior::new(witness); - inherited.tables.borrow_mut().generator_interiors.insert(fn_hir_id, interior); + inherited.tables.borrow_mut().generator_interiors_mut().insert(fn_hir_id, interior); Some(interior) } else { - inherited.tables.borrow_mut().generator_sigs.insert(fn_hir_id, None); + inherited.tables.borrow_mut().generator_sigs_mut().insert(fn_hir_id, None); None }; - inherited.tables.borrow_mut().liberated_fn_sigs.insert(fn_hir_id, fn_sig); + inherited.tables.borrow_mut().liberated_fn_sigs_mut().insert(fn_hir_id, fn_sig); fcx.check_return_expr(&body.value); diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index 54be3507774d2..8ebf55258ad68 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -361,19 +361,29 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { } fn visit_generator_interiors(&mut self) { - for (&node_id, interior) in self.fcx.tables.borrow().generator_interiors.iter() { - let interior = self.resolve(interior, &node_id); - self.tables.generator_interiors.insert(node_id, interior); + let common_local_id_root = self.fcx.tables.borrow().local_id_root.unwrap(); + for (&id, interior) in self.fcx.tables.borrow().generator_interiors().iter() { + let hir_id = hir::HirId { + owner: common_local_id_root.index, + local_id: id, + }; + let interior = self.resolve(interior, &hir_id); + self.tables.generator_interiors_mut().insert(hir_id, interior); } } fn visit_generator_sigs(&mut self) { - for (&node_id, gen_sig) in self.fcx.tables.borrow().generator_sigs.iter() { + let common_local_id_root = self.fcx.tables.borrow().local_id_root.unwrap(); + for (&id, gen_sig) in self.fcx.tables.borrow().generator_sigs().iter() { + let hir_id = hir::HirId { + owner: common_local_id_root.index, + local_id: id, + }; let gen_sig = gen_sig.map(|s| ty::GenSig { - yield_ty: self.resolve(&s.yield_ty, &node_id), - return_ty: self.resolve(&s.return_ty, &node_id), + yield_ty: self.resolve(&s.yield_ty, &hir_id), + return_ty: self.resolve(&s.return_ty, &hir_id), }); - self.tables.generator_sigs.insert(node_id, gen_sig); + self.tables.generator_sigs_mut().insert(hir_id, gen_sig); } } diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 6060312f51e81..75bdfde229308 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1155,7 +1155,8 @@ fn type_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, NodeExpr(&hir::Expr { node: hir::ExprClosure(.., is_generator), .. }) => { if is_generator { - return tcx.typeck_tables_of(def_id).node_id_to_type(node_id); + let hir_id = tcx.hir.node_to_hir_id(node_id); + return tcx.typeck_tables_of(def_id).node_id_to_type(hir_id); } tcx.mk_closure(def_id, Substs::for_item( From 17197c660c9cc2e29d27d496a5c65f7df39fd858 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Tue, 15 Aug 2017 07:55:06 +0200 Subject: [PATCH 090/113] Remove fixme --- src/librustc_typeck/check/writeback.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index 8ebf55258ad68..27dc346af32ce 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -168,7 +168,6 @@ impl<'cx, 'gcx, 'tcx> Visitor<'gcx> for WritebackCx<'cx, 'gcx, 'tcx> { if let hir::ExprClosure(_, _, body, _, _) = e.node { let body = self.fcx.tcx.hir.body(body); - // FIXME: Why visit the args here? for arg in &body.arguments { self.visit_node_id(e.span, arg.hir_id); } From 0697e4b17afbcf2b8d912a42d28c841aba07e088 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 16 Aug 2017 10:27:20 -0700 Subject: [PATCH 091/113] Fix merge conflict --- src/librustc_mir/transform/type_check.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_mir/transform/type_check.rs b/src/librustc_mir/transform/type_check.rs index f331d6252c6f5..586c97e8e7b51 100644 --- a/src/librustc_mir/transform/type_check.rs +++ b/src/librustc_mir/transform/type_check.rs @@ -112,9 +112,9 @@ impl<'a, 'b, 'gcx, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'gcx, 'tcx> { impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> { fn new(cx: &'a mut TypeChecker<'b, 'gcx, 'tcx>, mir: &'a Mir<'tcx>) -> Self { TypeVerifier { - cx, mir, body_id: cx.body_id, + cx, last_span: mir.span, errors_reported: false } From 63477fdeceead5683dfa197c5450ffe1bee3ab04 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 16 Aug 2017 13:05:48 -0700 Subject: [PATCH 092/113] Fix merge conflicts --- src/librustc_mir/transform/borrow_check.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/librustc_mir/transform/borrow_check.rs b/src/librustc_mir/transform/borrow_check.rs index b56d5d31f55fa..47cd183603226 100644 --- a/src/librustc_mir/transform/borrow_check.rs +++ b/src/librustc_mir/transform/borrow_check.rs @@ -293,12 +293,20 @@ impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> DataflowResultsConsumer<'b, 'gcx> (index, span), flow_state); } AssertMessage::Math(_/*const_math_err*/) => {} + AssertMessage::GeneratorResumedAfterReturn => {} + AssertMessage::GeneratorResumedAfterPanic => {} } } + TerminatorKind::Yield { ref value, resume: _, drop: _} => { + self.consume_operand(ContextKind::Yield.new(loc), + Consume, (value, span), flow_state); + } + TerminatorKind::Goto { target: _ } | TerminatorKind::Resume | TerminatorKind::Return | + TerminatorKind::GeneratorDrop | TerminatorKind::Unreachable => { // no data used, thus irrelevant to borrowck } @@ -1120,6 +1128,7 @@ enum ContextKind { CallDest, Assert, StorageDead, + Yield, } impl ContextKind { From a47038f551f05314a3abe569f2a8258c91021538 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 17 Aug 2017 15:20:06 -0700 Subject: [PATCH 093/113] Fix UI tests --- .../ui/generator/no-arguments-on-generators.stderr | 2 +- .../ui/generator/yield-while-local-borrowed.stderr | 10 +--------- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/src/test/ui/generator/no-arguments-on-generators.stderr b/src/test/ui/generator/no-arguments-on-generators.stderr index 4d2e228685ae3..290ad7b7f6c6a 100644 --- a/src/test/ui/generator/no-arguments-on-generators.stderr +++ b/src/test/ui/generator/no-arguments-on-generators.stderr @@ -1,4 +1,4 @@ -error[E0628]: generators cannot have explicit arguments +error[E0625]: generators cannot have explicit arguments --> $DIR/no-arguments-on-generators.rs:14:15 | 14 | let gen = |start| { //~ ERROR generators cannot have explicit arguments diff --git a/src/test/ui/generator/yield-while-local-borrowed.stderr b/src/test/ui/generator/yield-while-local-borrowed.stderr index 46363e5919d37..2fe6c686ce366 100644 --- a/src/test/ui/generator/yield-while-local-borrowed.stderr +++ b/src/test/ui/generator/yield-while-local-borrowed.stderr @@ -1,11 +1,3 @@ -error[E0626]: borrow may still be in use when generator yields - --> $DIR/yield-while-local-borrowed.rs:22:18 - | -22 | let a = &3; //~ ERROR - | ^ -23 | yield(); - | ------- possible yield occurs here - error[E0626]: borrow may still be in use when generator yields --> $DIR/yield-while-local-borrowed.rs:48:22 | @@ -14,5 +6,5 @@ error[E0626]: borrow may still be in use when generator yields 49 | yield(); | ------- possible yield occurs here -error: aborting due to 2 previous errors +error: aborting due to previous error From 9620d2613810b878ff82d31b7069f03c97278496 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 17 Aug 2017 22:52:04 -0700 Subject: [PATCH 094/113] Fix more UI tests --- src/test/ui/generator/no-arguments-on-generators.stderr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/ui/generator/no-arguments-on-generators.stderr b/src/test/ui/generator/no-arguments-on-generators.stderr index 290ad7b7f6c6a..4d2e228685ae3 100644 --- a/src/test/ui/generator/no-arguments-on-generators.stderr +++ b/src/test/ui/generator/no-arguments-on-generators.stderr @@ -1,4 +1,4 @@ -error[E0625]: generators cannot have explicit arguments +error[E0628]: generators cannot have explicit arguments --> $DIR/no-arguments-on-generators.rs:14:15 | 14 | let gen = |start| { //~ ERROR generators cannot have explicit arguments From e70cc2733b9902ae660f60fce7ba0bb5191a0d0c Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 18 Aug 2017 09:40:59 -0700 Subject: [PATCH 095/113] Fix a diagnostic --- src/librustc_borrowck/diagnostics.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_borrowck/diagnostics.rs b/src/librustc_borrowck/diagnostics.rs index 50a9dccaa2bb8..74133c821f0fa 100644 --- a/src/librustc_borrowck/diagnostics.rs +++ b/src/librustc_borrowck/diagnostics.rs @@ -660,7 +660,7 @@ yield point. # #![feature(generators, generator_trait)] # use std::ops::Generator; let mut b = || { - let a = &3; // <-- This borrow... + let a = &String::new(); // <-- This borrow... yield (); // ...is still in scope here, when the yield occurs. println!("{}", a); }; From bf3ebcc98788d805f96b171362d272c93e0a50a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Sun, 20 Aug 2017 14:20:33 +0200 Subject: [PATCH 096/113] Make gathering generator interior types O(n log n) --- .../check/generator_interior.rs | 22 ++++++++++++------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/src/librustc_typeck/check/generator_interior.rs b/src/librustc_typeck/check/generator_interior.rs index f50fb7e4a1326..7b25a3739c3dd 100644 --- a/src/librustc_typeck/check/generator_interior.rs +++ b/src/librustc_typeck/check/generator_interior.rs @@ -23,9 +23,7 @@ use util::nodemap::FxHashMap; struct InteriorVisitor<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { fcx: &'a FnCtxt<'a, 'gcx, 'tcx>, cache: FxHashMap>, - - // FIXME: Use an ordered hash map here - types: Vec>, + types: FxHashMap, usize>, region_maps: Rc, } @@ -46,9 +44,9 @@ impl<'a, 'gcx, 'tcx> InteriorVisitor<'a, 'gcx, 'tcx> { expr, scope, ty, span); } - if !self.types.contains(&ty) { - self.types.push(ty); - } + // Map the type to the number of types added before it + let entries = self.types.len(); + self.types.entry(&ty).or_insert(entries); } else { debug!("no type in expr = {:?}, span = {:?}", expr, expr.map(|e| e.span)); } @@ -62,13 +60,21 @@ pub fn resolve_interior<'a, 'gcx, 'tcx>(fcx: &'a FnCtxt<'a, 'gcx, 'tcx>, let body = fcx.tcx.hir.body(body_id); let mut visitor = InteriorVisitor { fcx, - types: Vec::new(), + types: FxHashMap(), cache: FxHashMap(), region_maps: fcx.tcx.region_maps(def_id), }; intravisit::walk_body(&mut visitor, body); - let tuple = fcx.tcx.intern_tup(&visitor.types, false); + let mut types: Vec<_> = visitor.types.drain().collect(); + + // Sort types by insertion order + types.sort_by_key(|t| t.1); + + // Extract type components + let types: Vec<_> = types.into_iter().map(|t| t.0).collect(); + + let tuple = fcx.tcx.intern_tup(&types, false); debug!("Types in generator {:?}, span = {:?}", tuple, body.value.span); From c74ff320eef258ad1bcd5a4c4b7f8294e4f9cb30 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 21 Aug 2017 22:09:50 -0700 Subject: [PATCH 097/113] More merge conflicts --- src/librustc_mir/shim.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs index 039651b7e9372..1e0858d686451 100644 --- a/src/librustc_mir/shim.rs +++ b/src/librustc_mir/shim.rs @@ -335,6 +335,7 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> { ), IndexVec::new(), self.sig.output(), + None, self.local_decls, self.sig.inputs().len(), vec![], From 0727adec6cd691b023460d49605a89dd962ba628 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 24 Aug 2017 11:40:06 -0700 Subject: [PATCH 098/113] Avoid looking at `closure_kinds` for generators --- src/librustc/middle/mem_categorization.rs | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 8ade87a37e9cc..034861131e86e 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -725,13 +725,12 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { // FnMut | copied -> &'env mut | upvar -> &'env mut -> &'up bk // FnOnce | copied | upvar -> &'up bk - let kind = match self.tables.closure_kinds().get(fn_hir_id) { - Some(&(kind, _)) => kind, - None => { - let ty = self.node_ty(fn_hir_id)?; - match ty.sty { - ty::TyGenerator(..) => ty::ClosureKind::FnOnce, - _ => span_bug!(span, "missing closure kind"), + let kind = match self.node_ty(fn_hir_id)?.sty { + ty::TyGenerator(..) => ty::ClosureKind::FnOnce, + _ => { + match self.tables.closure_kinds().get(fn_hir_id) { + Some(&(kind, _)) => kind, + None => span_bug!(span, "missing closure kind"), } } }; From b44e51cd62a982c8ab97b1b794ada57bdda44e85 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 24 Aug 2017 11:42:32 -0700 Subject: [PATCH 099/113] Touch up a comment on `LocalDecl::internal` --- src/librustc/mir/mod.rs | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index abfff023e892f..802bcf7dab8b2 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -411,14 +411,20 @@ pub struct LocalDecl<'tcx> { /// True if this corresponds to a user-declared local variable. pub is_user_variable: bool, - /// True if this is an internal local. + /// True if this is an internal local + /// /// These locals are not based on types in the source code and are only used /// for drop flags at the moment. - /// The generator transformation will sanity check the locals which are live across - /// a suspension point against the type components of the generator which - /// type checking knows are live across a suspension point. - /// We need to flag drop flags to avoid triggering this check as they are introduced + /// + /// The generator transformation will sanity check the locals which are live + /// across a suspension point against the type components of the generator + /// which type checking knows are live across a suspension point. We need to + /// flag drop flags to avoid triggering this check as they are introduced /// after typeck. + /// + /// This should be sound because the drop flags are fully algebraic, and + /// therefore don't affect the OIBIT or outlives properties of the + /// generator. pub internal: bool, /// Type of this local. From b28aeeb04e7bdc53a2a7601e8a04f4e19a7cfe58 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 25 Aug 2017 07:16:24 -0700 Subject: [PATCH 100/113] Fix indentation --- src/librustc_mir/transform/elaborate_drops.rs | 54 +++++++++---------- src/librustc_typeck/check/mod.rs | 16 +++--- 2 files changed, 35 insertions(+), 35 deletions(-) diff --git a/src/librustc_mir/transform/elaborate_drops.rs b/src/librustc_mir/transform/elaborate_drops.rs index 5d412c15771e0..417083c4ff801 100644 --- a/src/librustc_mir/transform/elaborate_drops.rs +++ b/src/librustc_mir/transform/elaborate_drops.rs @@ -102,37 +102,37 @@ fn find_dead_unwinds<'a, 'tcx>( _ => continue, }; - let mut init_data = InitializationData { - live: flow_inits.sets().on_entry_set_for(bb.index()).to_owned(), - dead: IdxSetBuf::new_empty(env.move_data.move_paths.len()), - }; - debug!("find_dead_unwinds @ {:?}: {:?}; init_data={:?}", - bb, bb_data, init_data.live); - for stmt in 0..bb_data.statements.len() { - let loc = Location { block: bb, statement_index: stmt }; - init_data.apply_location(tcx, mir, env, loc); - } + let mut init_data = InitializationData { + live: flow_inits.sets().on_entry_set_for(bb.index()).to_owned(), + dead: IdxSetBuf::new_empty(env.move_data.move_paths.len()), + }; + debug!("find_dead_unwinds @ {:?}: {:?}; init_data={:?}", + bb, bb_data, init_data.live); + for stmt in 0..bb_data.statements.len() { + let loc = Location { block: bb, statement_index: stmt }; + init_data.apply_location(tcx, mir, env, loc); + } - let path = match env.move_data.rev_lookup.find(location) { - LookupResult::Exact(e) => e, - LookupResult::Parent(..) => { - debug!("find_dead_unwinds: has parent; skipping"); - continue - } - }; + let path = match env.move_data.rev_lookup.find(location) { + LookupResult::Exact(e) => e, + LookupResult::Parent(..) => { + debug!("find_dead_unwinds: has parent; skipping"); + continue + } + }; - debug!("find_dead_unwinds @ {:?}: path({:?})={:?}", bb, location, path); + debug!("find_dead_unwinds @ {:?}: path({:?})={:?}", bb, location, path); - let mut maybe_live = false; - on_all_drop_children_bits(tcx, mir, &env, path, |child| { - let (child_maybe_live, _) = init_data.state(child); - maybe_live |= child_maybe_live; - }); + let mut maybe_live = false; + on_all_drop_children_bits(tcx, mir, &env, path, |child| { + let (child_maybe_live, _) = init_data.state(child); + maybe_live |= child_maybe_live; + }); - debug!("find_dead_unwinds @ {:?}: maybe_live={}", bb, maybe_live); - if !maybe_live { - dead_unwinds.add(&bb); - } + debug!("find_dead_unwinds @ {:?}: maybe_live={}", bb, maybe_live); + if !maybe_live { + dead_unwinds.add(&bb); + } } dead_unwinds diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 3cc568bbbde88..3a18eddaad347 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -3331,15 +3331,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { .join(", "); struct_span_err!(tcx.sess, span, E0063, - "missing field{} {}{} in initializer of `{}`", + "missing field{} {}{} in initializer of `{}`", if remaining_fields.len() == 1 { "" } else { "s" }, - remaining_fields_names, - truncated_fields_error, - adt_ty) - .span_label(span, format!("missing {}{}", - remaining_fields_names, - truncated_fields_error)) - .emit(); + remaining_fields_names, + truncated_fields_error, + adt_ty) + .span_label(span, format!("missing {}{}", + remaining_fields_names, + truncated_fields_error)) + .emit(); } } From 303a26406a136e24dcfe083e2c4b07f4cdad3d93 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 25 Aug 2017 07:17:37 -0700 Subject: [PATCH 101/113] Reorder slightly in `visit_basic_block_data` --- src/librustc_mir/transform/generator.rs | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs index b4d6bb09a157e..748db9ac80365 100644 --- a/src/librustc_mir/transform/generator.rs +++ b/src/librustc_mir/transform/generator.rs @@ -140,18 +140,6 @@ impl<'a, 'tcx> MutVisitor<'tcx> for TransformVisitor<'a, 'tcx> { fn visit_basic_block_data(&mut self, block: BasicBlock, data: &mut BasicBlockData<'tcx>) { - let ret_val = match data.terminator().kind { - TerminatorKind::Return => Some((1, - self.return_block, - Operand::Consume(Lvalue::Local(self.new_ret_local)), - None)), - TerminatorKind::Yield { ref value, resume, drop } => Some((0, - resume, - value.clone(), - drop)), - _ => None - }; - // Remove StorageLive and StorageDead statements for remapped locals data.retain_statements(|s| { match s.kind { @@ -166,6 +154,18 @@ impl<'a, 'tcx> MutVisitor<'tcx> for TransformVisitor<'a, 'tcx> { } }); + let ret_val = match data.terminator().kind { + TerminatorKind::Return => Some((1, + self.return_block, + Operand::Consume(Lvalue::Local(self.new_ret_local)), + None)), + TerminatorKind::Yield { ref value, resume, drop } => Some((0, + resume, + value.clone(), + drop)), + _ => None + }; + if let Some((state_idx, resume, v, drop)) = ret_val { let bb_idx = { let bb_targets = &mut self.bb_targets; From 8c97ffa1d4a1d9f8039a580297988af1880f5665 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 25 Aug 2017 07:18:19 -0700 Subject: [PATCH 102/113] Fix merge conflict --- src/librustc/hir/map/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs index b4e00455a743b..31b0b5c820e3d 100644 --- a/src/librustc/hir/map/mod.rs +++ b/src/librustc/hir/map/mod.rs @@ -153,7 +153,7 @@ impl<'hir> MapEntry<'hir> { EntryLocal(_, _, n) => NodeLocal(n), NotPresent | - RootCrate => return None + RootCrate(_) => return None }) } From 74b93f35dade697b679064f59720d689c1501045 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 25 Aug 2017 07:19:40 -0700 Subject: [PATCH 103/113] Add a `self_arg` convenience --- src/librustc_mir/transform/generator.rs | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs index 748db9ac80365..d47e722de8447 100644 --- a/src/librustc_mir/transform/generator.rs +++ b/src/librustc_mir/transform/generator.rs @@ -52,7 +52,7 @@ impl<'tcx> MutVisitor<'tcx> for DerefArgVisitor { lvalue: &mut Lvalue<'tcx>, context: LvalueContext<'tcx>, location: Location) { - if *lvalue == Lvalue::Local(Local::new(1)) { + if *lvalue == Lvalue::Local(self_arg()) { *lvalue = Lvalue::Projection(Box::new(Projection { base: lvalue.clone(), elem: ProjectionElem::Deref, @@ -63,6 +63,10 @@ impl<'tcx> MutVisitor<'tcx> for DerefArgVisitor { } } +fn self_arg() -> Local { + Local::new(1) +} + struct TransformVisitor<'a, 'tcx: 'a> { tcx: TyCtxt<'a, 'tcx, 'tcx>, state_adt_ref: &'tcx AdtDef, @@ -97,7 +101,7 @@ impl<'a, 'tcx> TransformVisitor<'a, 'tcx> { // Create a Lvalue referencing a generator struct field fn make_field(&self, idx: usize, ty: Ty<'tcx>) -> Lvalue<'tcx> { - let base = Lvalue::Local(Local::new(1)); + let base = Lvalue::Local(self_arg()); let field = Projection { base: base, elem: ProjectionElem::Field(Field::new(idx), ty), @@ -256,7 +260,7 @@ fn locals_live_across_suspend_points<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } // The generator argument is ignored - set.remove(&Local::new(1)); + set.remove(&self_arg()); set } @@ -334,7 +338,7 @@ fn elaborate_generator_drops<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, use shim::DropShimElaborator; let param_env = tcx.param_env(def_id); - let gen = Local::new(1); + let gen = self_arg(); for block in mir.basic_blocks().indices() { let (target, unwind, source_info) = match mir.basic_blocks()[block].terminator() { @@ -452,7 +456,7 @@ fn create_generator_drop_shim<'a, 'tcx>( make_generator_state_argument_indirect(tcx, def_id, &mut mir); // Change the generator argument from &mut to *mut - mir.local_decls[Local::new(1)] = LocalDecl { + mir.local_decls[self_arg()] = LocalDecl { mutability: Mutability::Mut, ty: tcx.mk_ptr(ty::TypeAndMut { ty: gen_ty, @@ -604,7 +608,7 @@ fn insert_clean_drop<'a, 'tcx>(mir: &mut Mir<'tcx>) -> BasicBlock { // Create a block to destroy an unresumed generators. This can only destroy upvars. let drop_clean = BasicBlock::new(mir.basic_blocks().len()); let term = TerminatorKind::Drop { - location: Lvalue::Local(Local::new(1)), + location: Lvalue::Local(self_arg()), target: return_block, unwind: None, }; From ed5bc60d4e87202f6dd290e643038a484e91532d Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 25 Aug 2017 07:31:05 -0700 Subject: [PATCH 104/113] Remove unneeded FIXME for now --- src/librustc_typeck/check/closure.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index 8f8dc71899fcc..a768271f3b825 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -32,8 +32,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { debug!("check_expr_closure(expr={:?},expected={:?})", expr, expected); - // FIXME: Should we adapt deduce_expectations_from_expected_type to work with - // generator traits? It looks like it's conservative to add support for this later. // It's always helpful for inference if we know the kind of // closure sooner rather than later, so first examine the expected From 1917ffe314a0daf7a5df9c0186c05b22a5f89d59 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 25 Aug 2017 07:38:57 -0700 Subject: [PATCH 105/113] Add some suggested comments around drops --- src/librustc_mir/transform/generator.rs | 8 ++++++-- src/librustc_mir/util/elaborate_drops.rs | 3 +++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs index d47e722de8447..f774b748112a5 100644 --- a/src/librustc_mir/transform/generator.rs +++ b/src/librustc_mir/transform/generator.rs @@ -331,12 +331,16 @@ fn insert_entry_point<'tcx>(mir: &mut Mir<'tcx>, } fn elaborate_generator_drops<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - def_id: DefId, - mir: &mut Mir<'tcx>) { + def_id: DefId, + mir: &mut Mir<'tcx>) { use util::elaborate_drops::{elaborate_drop, Unwind}; use util::patch::MirPatch; use shim::DropShimElaborator; + // Note that `elaborate_drops` only drops the upvars of a generator, and + // this is ok because `open_drop` can only be reached within that own + // generator's resume function. + let param_env = tcx.param_env(def_id); let gen = self_arg(); diff --git a/src/librustc_mir/util/elaborate_drops.rs b/src/librustc_mir/util/elaborate_drops.rs index 0abc5c8743171..e1a52ab9723cf 100644 --- a/src/librustc_mir/util/elaborate_drops.rs +++ b/src/librustc_mir/util/elaborate_drops.rs @@ -752,6 +752,9 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> fn open_drop<'a>(&mut self) -> BasicBlock { let ty = self.lvalue_ty(self.lvalue); match ty.sty { + // Note that `elaborate_drops` only drops the upvars of a generator, + // and this is ok because `open_drop` here can only be reached + // within that own generator's resume function. ty::TyClosure(def_id, substs) | ty::TyGenerator(def_id, substs, _) => { let tys : Vec<_> = substs.upvar_tys(def_id, self.tcx()).collect(); From b4c54715cddc8f2e3fc8b420cc7c93ef55ae0d33 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 25 Aug 2017 07:41:30 -0700 Subject: [PATCH 106/113] Comment about generators and drops --- src/librustc/ty/util.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index 82810b7aae1bb..3adad7cf0f856 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -1124,6 +1124,9 @@ fn needs_drop_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty::TyClosure(def_id, ref substs) => substs.upvar_tys(def_id, tcx).any(needs_drop), + // Pessimistically assume that all generators will require destructors + // as we don't know if a destructor is a noop or not until after the MIR + // state transformation pass ty::TyGenerator(..) => true, ty::TyTuple(ref tys, _) => tys.iter().cloned().any(needs_drop), From c71153113b965b6dfd265590a4d20a73d08ee4d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Fri, 25 Aug 2017 00:57:08 +0200 Subject: [PATCH 107/113] Add some comments and fix a typo --- src/librustc_mir/build/expr/as_rvalue.rs | 3 +- src/librustc_mir/transform/generator.rs | 56 ++++++++++++++++++- src/librustc_mir/util/elaborate_drops.rs | 5 +- .../check/generator_interior.rs | 5 ++ 4 files changed, 64 insertions(+), 5 deletions(-) diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs index 188f54f519eb0..da375e791bc4b 100644 --- a/src/librustc_mir/build/expr/as_rvalue.rs +++ b/src/librustc_mir/build/expr/as_rvalue.rs @@ -191,7 +191,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { .map(|upvar| unpack!(block = this.as_operand(block, scope, upvar))) .collect(); let result = if let Some(interior) = interior { - // Add the state operand + // Add the state operand since it follows the upvars in the generator + // struct. See librustc_mir/transform/generator.rs for more details. operands.push(Operand::Constant(box Constant { span: expr_span, ty: this.hir.tcx().types.u32, diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs index f774b748112a5..9bc572c66b6f8 100644 --- a/src/librustc_mir/transform/generator.rs +++ b/src/librustc_mir/transform/generator.rs @@ -8,7 +8,57 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Transforms generators into state machines +//! This is the implementation of the pass which transforms generators into state machines. +//! +//! MIR generation for generators creates a function which has a self argument which +//! passes by value. This argument is effectively a generator type which only contains upvars and +//! is only used for this argument inside the MIR for the generator. +//! It is passed by value to enable upvars to be moved out of it. Drop elaboration runs on that +//! MIR before this pass and creates drop flags for MIR locals. +//! It will also drop the generator argument (which only consists of upvars) if any of the upvars +//! are moved out of. This pass elaborates the drops of upvars / generator argument in the case +//! that none of the upvars were moved out of. This is because we cannot have any drops of this +//! generator in the MIR, since it is used to create the drop glue for the generator. We'd get +//! infinite recursion otherwise. +//! +//! This pass creates the implementation for the Generator::resume function and the drop shim +//! for the generator based on the MIR input. It converts the generator argument from Self to +//! &mut Self adding derefs in the MIR as needed. It computes the final layout of the generator +//! struct which looks like this: +//! First upvars are stored +//! It is followed by the generator state field. +//! Then finally the MIR locals which are live across a suspension point are stored. +//! +//! struct Generator { +//! upvars..., +//! state: u32, +//! mir_locals..., +//! } +//! +//! This pass computes the meaning of the state field and the MIR locals which are live +//! across a suspension point. There are however two hardcoded generator states: +//! 0 - Generator have not been resumed yet +//! 1 - Generator has been poisoned +//! +//! It also rewrites `return x` and `yield y` as setting a new generator state and returning +//! GeneratorState::Complete(x) and GeneratorState::Yielded(y) respectively. +//! MIR locals which are live across a suspension point are moved to the generator struct +//! with references to them being updated with references to the generator struct. +//! +//! The pass creates two functions which have a switch on the generator state giving +//! the action to take. +//! +//! One of them is the implementation of Generator::resume. +//! For generators which have already returned it panics. +//! For generators with state 0 (unresumed) it starts the execution of the generator. +//! For generators with state 1 (poisoned) it panics. +//! Otherwise it continues the execution from the last suspension point. +//! +//! The other function is the drop glue for the generator. +//! For generators which have already returned it does nothing. +//! For generators with state 0 (unresumed) it drops the upvars of the generator. +//! For generators with state 1 (poisoned) it does nothing. +//! Otherwise it drops all the values in scope at the last suspension point. use rustc::hir; use rustc::hir::def_id::DefId; @@ -515,7 +565,7 @@ fn insert_panic_on_resume_after_return<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, }); } -fn creator_generator_resume_function<'a, 'tcx>( +fn create_generator_resume_function<'a, 'tcx>( tcx: TyCtxt<'a, 'tcx, 'tcx>, mut transform: TransformVisitor<'a, 'tcx>, def_id: DefId, @@ -731,6 +781,6 @@ impl MirPass for StateTransform { mir.generator_drop = Some(box drop_shim); // Create the Generator::resume function - creator_generator_resume_function(tcx, transform, def_id, source, mir); + create_generator_resume_function(tcx, transform, def_id, source, mir); } } diff --git a/src/librustc_mir/util/elaborate_drops.rs b/src/librustc_mir/util/elaborate_drops.rs index e1a52ab9723cf..41618960337be 100644 --- a/src/librustc_mir/util/elaborate_drops.rs +++ b/src/librustc_mir/util/elaborate_drops.rs @@ -752,10 +752,13 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> fn open_drop<'a>(&mut self) -> BasicBlock { let ty = self.lvalue_ty(self.lvalue); match ty.sty { + ty::TyClosure(def_id, substs) | // Note that `elaborate_drops` only drops the upvars of a generator, // and this is ok because `open_drop` here can only be reached // within that own generator's resume function. - ty::TyClosure(def_id, substs) | + // This should only happen for the self argument on the resume function. + // It effetively only contains upvars until the generator transformation runs. + // See librustc_mir/transform/generator.rs for more details. ty::TyGenerator(def_id, substs, _) => { let tys : Vec<_> = substs.upvar_tys(def_id, self.tcx()).collect(); self.open_drop_for_tuple(&tys) diff --git a/src/librustc_typeck/check/generator_interior.rs b/src/librustc_typeck/check/generator_interior.rs index 7b25a3739c3dd..e9d400c64393b 100644 --- a/src/librustc_typeck/check/generator_interior.rs +++ b/src/librustc_typeck/check/generator_interior.rs @@ -8,6 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +//! This calculates the types which has storage which lives across a suspension point in a +//! generator from the perspective of typeck. The actual types used at runtime +//! is calculated in `rustc_mir::transform::generator` and may be a subset of the +//! types computed here. + use log; use rustc::hir::def_id::DefId; use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap}; From 536613554fbfc16c0da85615aff6717229d9df6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Fri, 25 Aug 2017 20:10:23 +0200 Subject: [PATCH 108/113] Clean up YieldFinder --- src/librustc/middle/region.rs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index 6374eb3ff9060..944d03737d37d 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -1175,13 +1175,18 @@ struct YieldFinder<'a> { impl<'a> YieldFinder<'a> { fn lookup(&mut self, id: NodeId, f: F) { - if let Some(result) = self.cache.get(&id) { - self.result = *result; + // Don't traverse further if we found a yield expression + if self.result.is_some() { return; } - if self.result.is_some() { + + // See if there's an entry in the cache + if let Some(result) = self.cache.get(&id) { + self.result = *result; return; } + + // Otherwise calculate the result and insert it into the cache f(self); self.cache.insert(id, self.result); } From 7c5780b3564d98aec130ee2f27368b116a3f1160 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Mon, 28 Aug 2017 02:39:17 +0200 Subject: [PATCH 109/113] Update rls --- src/tools/rls | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/rls b/src/tools/rls index 5d4bbd9052fe2..a2de5558059df 160000 --- a/src/tools/rls +++ b/src/tools/rls @@ -1 +1 @@ -Subproject commit 5d4bbd9052fe2af849a7d017b85df98ad002c20f +Subproject commit a2de5558059df72065bed22d34c53e8279e402cd From 8a9e32b3fa5bdd62ccd1b265437bcd554f25a3d0 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Sun, 27 Aug 2017 18:52:02 -0700 Subject: [PATCH 110/113] Update lock file --- src/Cargo.lock | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/Cargo.lock b/src/Cargo.lock index 123c884585c19..1625f4306439a 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -1179,15 +1179,14 @@ dependencies = [ "racer 2.0.10 (registry+https://github.com/rust-lang/crates.io-index)", "rls-analysis 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "rls-data 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rls-rustc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "rls-vfs 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", - "rustfmt-nightly 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rustfmt-nightly 0.2.2 (git+https://github.com/rust-lang-nursery/rustfmt?branch=yield)", "serde 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "url_serde 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1213,6 +1212,11 @@ dependencies = [ "serde_derive 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "rls-rustc" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "rls-span" version = "0.4.0" @@ -1648,7 +1652,7 @@ dependencies = [ [[package]] name = "rustfmt-nightly" version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" +source = "git+https://github.com/rust-lang-nursery/rustfmt?branch=yield#6f56783c8cfd5f06d9b77873a3d4feb56c8d843f" dependencies = [ "diff 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2283,11 +2287,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum regex-syntax 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ad890a5eef7953f55427c50575c680c42841653abd2b028b68cd223d157f62db" "checksum rls-analysis 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d2cb40c0371765897ae428b5706bb17135705ad4f6d1b8b6afbaabcf8c9b5cff" "checksum rls-data 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "11d339f1888e33e74d8032de0f83c40b2bdaaaf04a8cfc03b32186c3481fb534" +"checksum rls-rustc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5fa757c9d547d460427ceff01875f9cac5f5acd8fc6543946e9b0335ba29d537" "checksum rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5d7c7046dc6a92f2ae02ed302746db4382e75131b9ce20ce967259f6b5867a6a" "checksum rls-vfs 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "ffd34691a510938bb67fe0444fb363103c73ffb31c121d1e16bc92d8945ea8ff" "checksum rustc-demangle 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "aee45432acc62f7b9a108cc054142dac51f979e69e71ddce7d6fc7adf29e817e" "checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda" -"checksum rustfmt-nightly 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6eea0d0590ae793fc4d281df56e01dc7531575c8ed9a72fadf5fdc7305a0d32f" +"checksum rustfmt-nightly 0.2.2 (git+https://github.com/rust-lang-nursery/rustfmt?branch=yield)" = "" "checksum same-file 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d931a44fdaa43b8637009e7632a02adc4f2b2e0733c08caa4cf00e8da4a117a7" "checksum scoped-tls 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f417c22df063e9450888a7561788e9bd46d3bb3c1466435b4eccb903807f147d" "checksum scopeguard 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "59a076157c1e2dc561d8de585151ee6965d910dd4dcb5dabb7ae3e83981a6c57" From 9eff522c6de07c2033a6db6ccc4fdd0c4a6cadc4 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Sun, 27 Aug 2017 21:01:16 -0700 Subject: [PATCH 111/113] Update the rls submodule again --- src/tools/rls | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/rls b/src/tools/rls index a2de5558059df..516041e6cf459 160000 --- a/src/tools/rls +++ b/src/tools/rls @@ -1 +1 @@ -Subproject commit a2de5558059df72065bed22d34c53e8279e402cd +Subproject commit 516041e6cf4590ececbfa8a7788e432f3ea8ccaa From 876278f39589ff2acfcefb4d62b20d674905b5d3 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Sun, 27 Aug 2017 23:37:50 -0700 Subject: [PATCH 112/113] Ignore a threaded test on emscripten --- src/test/run-pass/generator/smoke.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/test/run-pass/generator/smoke.rs b/src/test/run-pass/generator/smoke.rs index 48f1b688f2466..e9bdfbf28ea9c 100644 --- a/src/test/run-pass/generator/smoke.rs +++ b/src/test/run-pass/generator/smoke.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-emscripten // compile-flags: --test #![feature(generators, generator_trait)] From a996d5eec70ba6733e23f2e56e762f58e60bb4ff Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 28 Aug 2017 07:14:52 -0700 Subject: [PATCH 113/113] Tweak rls submodule again --- src/Cargo.lock | 9 ++------- src/tools/rls | 2 +- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/src/Cargo.lock b/src/Cargo.lock index 1625f4306439a..cb55fb602e3c7 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -1179,14 +1179,15 @@ dependencies = [ "racer 2.0.10 (registry+https://github.com/rust-lang/crates.io-index)", "rls-analysis 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "rls-data 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rls-rustc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "rls-vfs 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", "rustfmt-nightly 0.2.2 (git+https://github.com/rust-lang-nursery/rustfmt?branch=yield)", "serde 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "url_serde 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1212,11 +1213,6 @@ dependencies = [ "serde_derive 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "rls-rustc" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "rls-span" version = "0.4.0" @@ -2287,7 +2283,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum regex-syntax 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ad890a5eef7953f55427c50575c680c42841653abd2b028b68cd223d157f62db" "checksum rls-analysis 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d2cb40c0371765897ae428b5706bb17135705ad4f6d1b8b6afbaabcf8c9b5cff" "checksum rls-data 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "11d339f1888e33e74d8032de0f83c40b2bdaaaf04a8cfc03b32186c3481fb534" -"checksum rls-rustc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5fa757c9d547d460427ceff01875f9cac5f5acd8fc6543946e9b0335ba29d537" "checksum rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5d7c7046dc6a92f2ae02ed302746db4382e75131b9ce20ce967259f6b5867a6a" "checksum rls-vfs 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "ffd34691a510938bb67fe0444fb363103c73ffb31c121d1e16bc92d8945ea8ff" "checksum rustc-demangle 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "aee45432acc62f7b9a108cc054142dac51f979e69e71ddce7d6fc7adf29e817e" diff --git a/src/tools/rls b/src/tools/rls index 516041e6cf459..144ce17f4d13f 160000 --- a/src/tools/rls +++ b/src/tools/rls @@ -1 +1 @@ -Subproject commit 516041e6cf4590ececbfa8a7788e432f3ea8ccaa +Subproject commit 144ce17f4d13fe10f386d42e3735956e9549167e