Skip to content

Immovable generators #45337

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Jan 24, 2018
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/librustc/diagnostics.rs
Original file line number Diff line number Diff line change
@@ -2118,4 +2118,6 @@ register_diagnostics! {
E0657, // `impl Trait` can only capture lifetimes bound at the fn level
E0687, // in-band lifetimes cannot be used in `fn`/`Fn` syntax
E0688, // in-band lifetimes cannot be mixed with explicit lifetime binders

E0906, // closures cannot be static
}
26 changes: 19 additions & 7 deletions src/librustc/hir/lowering.rs
Original file line number Diff line number Diff line change
@@ -2768,7 +2768,7 @@ impl<'a> LoweringContext<'a> {
arms.iter().map(|x| self.lower_arm(x)).collect(),
hir::MatchSource::Normal)
}
ExprKind::Closure(capture_clause, ref decl, ref body, fn_decl_span) => {
ExprKind::Closure(capture_clause, movability, ref decl, ref body, fn_decl_span) => {
self.with_new_scopes(|this| {
this.with_parent_def(e.id, |this| {
let mut is_generator = false;
@@ -2777,16 +2777,28 @@ impl<'a> LoweringContext<'a> {
is_generator = this.is_generator;
e
});
if is_generator && !decl.inputs.is_empty() {
span_err!(this.sess, fn_decl_span, E0628,
"generators cannot have explicit arguments");
this.sess.abort_if_errors();
}
let generator_option = if is_generator {
if !decl.inputs.is_empty() {
span_err!(this.sess, fn_decl_span, E0628,
"generators cannot have explicit arguments");
this.sess.abort_if_errors();
}
Some(match movability {
Movability::Movable => hir::GeneratorMovability::Movable,
Movability::Static => hir::GeneratorMovability::Static,
})
} else {
if movability == Movability::Static {
span_err!(this.sess, fn_decl_span, E0906,
"closures cannot be static");
}
None
};
hir::ExprClosure(this.lower_capture_clause(capture_clause),
this.lower_fn_decl(decl, None, false),
body_id,
fn_decl_span,
is_generator)
generator_option)
})
})
}
8 changes: 7 additions & 1 deletion src/librustc/hir/mod.rs
Original file line number Diff line number Diff line change
@@ -1290,7 +1290,7 @@ pub enum Expr_ {
///
/// This may also be a generator literal, indicated by the final boolean,
/// in that case there is an GeneratorClause.
ExprClosure(CaptureClause, P<FnDecl>, BodyId, Span, bool),
ExprClosure(CaptureClause, P<FnDecl>, BodyId, Span, Option<GeneratorMovability>),
/// A block (`{ ... }`)
ExprBlock(P<Block>),

@@ -1466,6 +1466,12 @@ pub struct Destination {
pub target_id: ScopeTarget,
}

#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
pub enum GeneratorMovability {
Static,
Movable,
}

#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
pub enum CaptureClause {
CaptureByValue,
5 changes: 5 additions & 0 deletions src/librustc/ich/impls_hir.rs
Original file line number Diff line number Diff line change
@@ -606,6 +606,11 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for hir::MatchSource {
}
}

impl_stable_hash_for!(enum hir::GeneratorMovability {
Static,
Movable
});

impl_stable_hash_for!(enum hir::CaptureClause {
CaptureByValue,
CaptureByRef
5 changes: 4 additions & 1 deletion src/librustc/ich/impls_ty.rs
Original file line number Diff line number Diff line change
@@ -431,7 +431,7 @@ for ::middle::const_val::ErrKind<'gcx> {

impl_stable_hash_for!(struct ty::ClosureSubsts<'tcx> { substs });

impl_stable_hash_for!(struct ty::GeneratorInterior<'tcx> { witness });
impl_stable_hash_for!(struct ty::GeneratorInterior<'tcx> { witness, movable });

impl_stable_hash_for!(struct ty::GenericPredicates<'tcx> {
parent,
@@ -656,6 +656,9 @@ for ty::TypeVariants<'gcx>
closure_substs.hash_stable(hcx, hasher);
interior.hash_stable(hcx, hasher);
}
TyGeneratorWitness(types) => {
types.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);
Original file line number Diff line number Diff line change
@@ -60,7 +60,7 @@ impl<'a, 'gcx, 'tcx> NiceRegionError<'a, 'gcx, 'tcx> {
if let Some(node_id) = hir.as_local_node_id(free_region.scope) {
match hir.get(node_id) {
NodeExpr(Expr {
node: ExprClosure(_, _, _, closure_span, false),
node: ExprClosure(_, _, _, closure_span, None),
..
}) => {
let sup_sp = sup_origin.span();
1 change: 1 addition & 0 deletions src/librustc/infer/freshen.rs
Original file line number Diff line number Diff line change
@@ -192,6 +192,7 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for TypeFreshener<'a, 'gcx, 'tcx> {
ty::TyForeign(..) |
ty::TyParam(..) |
ty::TyClosure(..) |
ty::TyGeneratorWitness(..) |
ty::TyAnon(..) => {
t.super_fold_with(self)
}
88 changes: 84 additions & 4 deletions src/librustc/middle/region.rs
Original file line number Diff line number Diff line change
@@ -453,6 +453,43 @@ struct RegionResolutionVisitor<'a, 'tcx: 'a> {
terminating_scopes: FxHashSet<hir::ItemLocalId>,
}

struct ExprLocatorVisitor {
id: ast::NodeId,
result: Option<usize>,
expr_and_pat_count: usize,
}

// This visitor has to have the same visit_expr calls as RegionResolutionVisitor
// since `expr_count` is compared against the results there.
impl<'tcx> Visitor<'tcx> for ExprLocatorVisitor {
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
NestedVisitorMap::None
}

fn visit_pat(&mut self, pat: &'tcx Pat) {
self.expr_and_pat_count += 1;

intravisit::walk_pat(self, pat);
}

fn visit_expr(&mut self, expr: &'tcx Expr) {
debug!("ExprLocatorVisitor - pre-increment {} expr = {:?}",
self.expr_and_pat_count,
expr);

intravisit::walk_expr(self, expr);

self.expr_and_pat_count += 1;

debug!("ExprLocatorVisitor - post-increment {} expr = {:?}",
self.expr_and_pat_count,
expr);

if expr.id == self.id {
self.result = Some(self.expr_and_pat_count);
}
}
}

impl<'tcx> ScopeTree {
pub fn record_scope_parent(&mut self, child: Scope, parent: Option<Scope>) {
@@ -612,6 +649,20 @@ impl<'tcx> ScopeTree {
return true;
}

/// Returns the id of the innermost containing body
pub fn containing_body(&self, mut scope: Scope)-> Option<hir::ItemLocalId> {
loop {
if let ScopeData::CallSite(id) = scope.data() {
return Some(id);
}

match self.opt_encl_scope(scope) {
None => return None,
Some(parent) => scope = parent,
}
}
}

/// Finds the nearest common ancestor (if any) of two scopes. That is, finds the smallest
/// scope which is greater than or equal to both `scope_a` and `scope_b`.
pub fn nearest_common_ancestor(&self,
@@ -768,6 +819,28 @@ impl<'tcx> ScopeTree {
self.yield_in_scope.get(&scope).cloned()
}

/// Checks whether the given scope contains a `yield` and if that yield could execute
/// after `expr`. If so, it returns the span of that `yield`.
/// `scope` must be inside the body.
pub fn yield_in_scope_for_expr(&self,
scope: Scope,
expr: ast::NodeId,
body: &'tcx hir::Body) -> Option<Span> {
self.yield_in_scope(scope).and_then(|(span, count)| {
let mut visitor = ExprLocatorVisitor {
id: expr,
result: None,
expr_and_pat_count: 0,
};
visitor.visit_body(body);
if count >= visitor.result.unwrap() {
Some(span)
} else {
None
}
})
}

/// Gives the number of expressions visited in a body.
/// Used to sanity check visit_expr call count when
/// calculating generator interiors.
@@ -872,9 +945,13 @@ fn resolve_pat<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, pat: &
record_var_lifetime(visitor, pat.hir_id.local_id, pat.span);
}

debug!("resolve_pat - pre-increment {} pat = {:?}", visitor.expr_and_pat_count, pat);

intravisit::walk_pat(visitor, pat);

visitor.expr_and_pat_count += 1;

debug!("resolve_pat - post-increment {} pat = {:?}", visitor.expr_and_pat_count, pat);
}

fn resolve_stmt<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, stmt: &'tcx hir::Stmt) {
@@ -897,7 +974,7 @@ fn resolve_stmt<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, stmt:
}

fn resolve_expr<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, expr: &'tcx hir::Expr) {
debug!("resolve_expr(expr.id={:?})", expr.id);
debug!("resolve_expr - pre-increment {} expr = {:?}", visitor.expr_and_pat_count, expr);

let prev_cx = visitor.cx;
visitor.enter_node_scope_with_dtor(expr.hir_id.local_id);
@@ -982,6 +1059,8 @@ fn resolve_expr<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, expr:

visitor.expr_and_pat_count += 1;

debug!("resolve_expr post-increment {}, expr = {:?}", visitor.expr_and_pat_count, expr);

if let hir::ExprYield(..) = expr.node {
// Mark this expr's scope and all parent scopes as containing `yield`.
let mut scope = Scope::Node(expr.hir_id.local_id);
@@ -1077,12 +1156,13 @@ fn resolve_local<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>,
}
}

if let Some(pat) = pat {
visitor.visit_pat(pat);
}
// Make sure we visit the initializer first, so expr_and_pat_count remains correct
if let Some(expr) = init {
visitor.visit_expr(expr);
}
if let Some(pat) = pat {
visitor.visit_pat(pat);
}

/// True if `pat` match the `P&` nonterminal:
///
5 changes: 4 additions & 1 deletion src/librustc/traits/coherence.rs
Original file line number Diff line number Diff line change
@@ -451,7 +451,10 @@ fn ty_is_local_constructor(ty: Ty, in_crate: InCrate) -> bool {
true
}

ty::TyClosure(..) | ty::TyGenerator(..) | ty::TyAnon(..) => {
ty::TyClosure(..) |
ty::TyGenerator(..) |
ty::TyGeneratorWitness(..) |
ty::TyAnon(..) => {
bug!("ty_is_local invoked on unexpected type: {:?}", ty)
}
}
1 change: 1 addition & 0 deletions src/librustc/traits/error_reporting.rs
Original file line number Diff line number Diff line change
@@ -262,6 +262,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
},
ty::TyGenerator(..) => Some(18),
ty::TyForeign(..) => Some(19),
ty::TyGeneratorWitness(..) => Some(20),
ty::TyInfer(..) | ty::TyError => None
}
}
16 changes: 11 additions & 5 deletions src/librustc/traits/select.rs
Original file line number Diff line number Diff line change
@@ -2044,8 +2044,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
ty::TyUint(_) | ty::TyInt(_) | ty::TyBool | ty::TyFloat(_) |
ty::TyFnDef(..) | ty::TyFnPtr(_) | ty::TyRawPtr(..) |
ty::TyChar | ty::TyRef(..) | ty::TyGenerator(..) |
ty::TyArray(..) | ty::TyClosure(..) | ty::TyNever |
ty::TyError => {
ty::TyGeneratorWitness(..) | ty::TyArray(..) | ty::TyClosure(..) |
ty::TyNever | ty::TyError => {
// safe for everything
Where(ty::Binder(Vec::new()))
}
@@ -2095,7 +2095,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
}

ty::TyDynamic(..) | ty::TyStr | ty::TySlice(..) |
ty::TyGenerator(..) | ty::TyForeign(..) |
ty::TyGenerator(..) | ty::TyGeneratorWitness(..) | ty::TyForeign(..) |
ty::TyRef(_, ty::TypeAndMut { ty: _, mutbl: hir::MutMutable }) => {
Never
}
@@ -2206,8 +2206,14 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
}

ty::TyGenerator(def_id, ref substs, interior) => {
let witness = iter::once(interior.witness);
substs.upvar_tys(def_id, self.tcx()).chain(witness).collect()
substs.upvar_tys(def_id, self.tcx()).chain(iter::once(interior.witness)).collect()
}

ty::TyGeneratorWitness(types) => {
// This is sound because no regions in the witness can refer to
// the binder outside the witness. So we'll effectivly reuse
// the implicit binder around the witness.
types.skip_binder().to_vec()
}

// for `PhantomData<T>`, we pass `T`
9 changes: 7 additions & 2 deletions src/librustc/ty/context.rs
Original file line number Diff line number Diff line change
@@ -1672,8 +1672,9 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {
pub fn print_debug_stats(self) {
sty_debug_print!(
self,
TyAdt, TyArray, TySlice, TyRawPtr, TyRef, TyFnDef, TyFnPtr, TyGenerator, TyForeign,
TyDynamic, TyClosure, TyTuple, TyParam, TyInfer, TyProjection, TyAnon);
TyAdt, TyArray, TySlice, TyRawPtr, TyRef, TyFnDef, TyFnPtr,
TyGenerator, TyGeneratorWitness, TyDynamic, TyClosure, TyTuple,
TyParam, TyInfer, TyProjection, TyAnon, TyForeign);

println!("Substs interner: #{}", self.interners.substs.borrow().len());
println!("Region interner: #{}", self.interners.region.borrow().len());
@@ -2079,6 +2080,10 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
self.mk_ty(TyGenerator(id, closure_substs, interior))
}

pub fn mk_generator_witness(self, types: ty::Binder<&'tcx Slice<Ty<'tcx>>>) -> Ty<'tcx> {
self.mk_ty(TyGeneratorWitness(types))
}

pub fn mk_var(self, v: TyVid) -> Ty<'tcx> {
self.mk_infer(TyVar(v))
}
1 change: 1 addition & 0 deletions src/librustc/ty/error.rs
Original file line number Diff line number Diff line change
@@ -227,6 +227,7 @@ impl<'a, 'gcx, 'lcx, 'tcx> ty::TyS<'tcx> {
}
ty::TyClosure(..) => "closure".to_string(),
ty::TyGenerator(..) => "generator".to_string(),
ty::TyGeneratorWitness(..) => "generator witness".to_string(),
ty::TyTuple(..) => "tuple".to_string(),
ty::TyInfer(ty::TyVar(_)) => "inferred type".to_string(),
ty::TyInfer(ty::IntVar(_)) => "integral variable".to_string(),
6 changes: 6 additions & 0 deletions src/librustc/ty/fast_reject.rs
Original file line number Diff line number Diff line change
@@ -46,6 +46,7 @@ pub enum SimplifiedTypeGen<D>
TraitSimplifiedType(D),
ClosureSimplifiedType(D),
GeneratorSimplifiedType(D),
GeneratorWitnessSimplifiedType(usize),
AnonSimplifiedType(D),
FunctionSimplifiedType(usize),
ParameterSimplifiedType,
@@ -92,6 +93,9 @@ pub fn simplify_type<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
ty::TyGenerator(def_id, _, _) => {
Some(GeneratorSimplifiedType(def_id))
}
ty::TyGeneratorWitness(ref tys) => {
Some(GeneratorWitnessSimplifiedType(tys.skip_binder().len()))
}
ty::TyNever => Some(NeverSimplifiedType),
ty::TyTuple(ref tys, _) => {
Some(TupleSimplifiedType(tys.len()))
@@ -141,6 +145,7 @@ impl<D: Copy + Debug + Ord + Eq + Hash> SimplifiedTypeGen<D> {
TraitSimplifiedType(d) => TraitSimplifiedType(map(d)),
ClosureSimplifiedType(d) => ClosureSimplifiedType(map(d)),
GeneratorSimplifiedType(d) => GeneratorSimplifiedType(map(d)),
GeneratorWitnessSimplifiedType(n) => GeneratorWitnessSimplifiedType(n),
AnonSimplifiedType(d) => AnonSimplifiedType(map(d)),
FunctionSimplifiedType(n) => FunctionSimplifiedType(n),
ParameterSimplifiedType => ParameterSimplifiedType,
@@ -175,6 +180,7 @@ impl<'gcx, D> HashStable<StableHashingContext<'gcx>> for SimplifiedTypeGen<D>
TraitSimplifiedType(d) => d.hash_stable(hcx, hasher),
ClosureSimplifiedType(d) => d.hash_stable(hcx, hasher),
GeneratorSimplifiedType(d) => d.hash_stable(hcx, hasher),
GeneratorWitnessSimplifiedType(n) => n.hash_stable(hcx, hasher),
AnonSimplifiedType(d) => d.hash_stable(hcx, hasher),
FunctionSimplifiedType(n) => n.hash_stable(hcx, hasher),
ForeignSimplifiedType(d) => d.hash_stable(hcx, hasher),
6 changes: 6 additions & 0 deletions src/librustc/ty/flags.rs
Original file line number Diff line number Diff line change
@@ -94,6 +94,12 @@ impl FlagComputation {
self.add_ty(interior.witness);
}

&ty::TyGeneratorWitness(ref ts) => {
let mut computation = FlagComputation::new();
computation.add_tys(&ts.skip_binder()[..]);
self.add_bound_computation(&computation);
}

&ty::TyClosure(_, ref substs) => {
self.add_flags(TypeFlags::HAS_TY_CLOSURE);
self.add_flags(TypeFlags::HAS_LOCAL_NAMES);
Loading