Skip to content

Commit fdecb05

Browse files
committed
Auto merge of #45337 - Zoxc:gen-static, r=nikomatsakis
Immovable generators This adds support for immovable generators which allow you to borrow local values inside generator across suspension points. These are declared using a `static` keyword: ```rust let mut generator = static || { let local = &Vec::new(); yield; local.push(0i8); }; generator.resume(); // ERROR moving the generator after it has resumed would invalidate the interior reference // drop(generator); ``` Region inference is no longer affected by the types stored in generators so the regions inside should be similar to other code (and unaffected by the presence of `yield` expressions). The borrow checker is extended to pick up the slack so interior references still result in errors for movable generators. This fixes #44197, #45259 and #45093. This PR depends on [PR #44917 (immovable types)](#44917), I suggest potential reviewers ignore the first commit as it adds immovable types.
2 parents 4e3901d + 55c6c88 commit fdecb05

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

71 files changed

+1116
-228
lines changed

src/librustc/diagnostics.rs

+2
Original file line numberDiff line numberDiff line change
@@ -2118,4 +2118,6 @@ register_diagnostics! {
21182118
E0657, // `impl Trait` can only capture lifetimes bound at the fn level
21192119
E0687, // in-band lifetimes cannot be used in `fn`/`Fn` syntax
21202120
E0688, // in-band lifetimes cannot be mixed with explicit lifetime binders
2121+
2122+
E0906, // closures cannot be static
21212123
}

src/librustc/hir/lowering.rs

+19-7
Original file line numberDiff line numberDiff line change
@@ -2773,7 +2773,7 @@ impl<'a> LoweringContext<'a> {
27732773
arms.iter().map(|x| self.lower_arm(x)).collect(),
27742774
hir::MatchSource::Normal)
27752775
}
2776-
ExprKind::Closure(capture_clause, ref decl, ref body, fn_decl_span) => {
2776+
ExprKind::Closure(capture_clause, movability, ref decl, ref body, fn_decl_span) => {
27772777
self.with_new_scopes(|this| {
27782778
this.with_parent_def(e.id, |this| {
27792779
let mut is_generator = false;
@@ -2782,16 +2782,28 @@ impl<'a> LoweringContext<'a> {
27822782
is_generator = this.is_generator;
27832783
e
27842784
});
2785-
if is_generator && !decl.inputs.is_empty() {
2786-
span_err!(this.sess, fn_decl_span, E0628,
2787-
"generators cannot have explicit arguments");
2788-
this.sess.abort_if_errors();
2789-
}
2785+
let generator_option = if is_generator {
2786+
if !decl.inputs.is_empty() {
2787+
span_err!(this.sess, fn_decl_span, E0628,
2788+
"generators cannot have explicit arguments");
2789+
this.sess.abort_if_errors();
2790+
}
2791+
Some(match movability {
2792+
Movability::Movable => hir::GeneratorMovability::Movable,
2793+
Movability::Static => hir::GeneratorMovability::Static,
2794+
})
2795+
} else {
2796+
if movability == Movability::Static {
2797+
span_err!(this.sess, fn_decl_span, E0906,
2798+
"closures cannot be static");
2799+
}
2800+
None
2801+
};
27902802
hir::ExprClosure(this.lower_capture_clause(capture_clause),
27912803
this.lower_fn_decl(decl, None, false),
27922804
body_id,
27932805
fn_decl_span,
2794-
is_generator)
2806+
generator_option)
27952807
})
27962808
})
27972809
}

src/librustc/hir/mod.rs

+7-1
Original file line numberDiff line numberDiff line change
@@ -1290,7 +1290,7 @@ pub enum Expr_ {
12901290
///
12911291
/// This may also be a generator literal, indicated by the final boolean,
12921292
/// in that case there is an GeneratorClause.
1293-
ExprClosure(CaptureClause, P<FnDecl>, BodyId, Span, bool),
1293+
ExprClosure(CaptureClause, P<FnDecl>, BodyId, Span, Option<GeneratorMovability>),
12941294
/// A block (`{ ... }`)
12951295
ExprBlock(P<Block>),
12961296

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

1469+
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
1470+
pub enum GeneratorMovability {
1471+
Static,
1472+
Movable,
1473+
}
1474+
14691475
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
14701476
pub enum CaptureClause {
14711477
CaptureByValue,

src/librustc/ich/impls_hir.rs

+5
Original file line numberDiff line numberDiff line change
@@ -606,6 +606,11 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for hir::MatchSource {
606606
}
607607
}
608608

609+
impl_stable_hash_for!(enum hir::GeneratorMovability {
610+
Static,
611+
Movable
612+
});
613+
609614
impl_stable_hash_for!(enum hir::CaptureClause {
610615
CaptureByValue,
611616
CaptureByRef

src/librustc/ich/impls_ty.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -431,7 +431,7 @@ for ::middle::const_val::ErrKind<'gcx> {
431431

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

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

436436
impl_stable_hash_for!(struct ty::GenericPredicates<'tcx> {
437437
parent,
@@ -656,6 +656,9 @@ for ty::TypeVariants<'gcx>
656656
closure_substs.hash_stable(hcx, hasher);
657657
interior.hash_stable(hcx, hasher);
658658
}
659+
TyGeneratorWitness(types) => {
660+
types.hash_stable(hcx, hasher)
661+
}
659662
TyTuple(inner_tys, from_diverging_type_var) => {
660663
inner_tys.hash_stable(hcx, hasher);
661664
from_diverging_type_var.hash_stable(hcx, hasher);

src/librustc/infer/error_reporting/nice_region_error/outlives_closure.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ impl<'a, 'gcx, 'tcx> NiceRegionError<'a, 'gcx, 'tcx> {
6060
if let Some(node_id) = hir.as_local_node_id(free_region.scope) {
6161
match hir.get(node_id) {
6262
NodeExpr(Expr {
63-
node: ExprClosure(_, _, _, closure_span, false),
63+
node: ExprClosure(_, _, _, closure_span, None),
6464
..
6565
}) => {
6666
let sup_sp = sup_origin.span();

src/librustc/infer/freshen.rs

+1
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,7 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for TypeFreshener<'a, 'gcx, 'tcx> {
192192
ty::TyForeign(..) |
193193
ty::TyParam(..) |
194194
ty::TyClosure(..) |
195+
ty::TyGeneratorWitness(..) |
195196
ty::TyAnon(..) => {
196197
t.super_fold_with(self)
197198
}

src/librustc/middle/region.rs

+84-4
Original file line numberDiff line numberDiff line change
@@ -453,6 +453,43 @@ struct RegionResolutionVisitor<'a, 'tcx: 'a> {
453453
terminating_scopes: FxHashSet<hir::ItemLocalId>,
454454
}
455455

456+
struct ExprLocatorVisitor {
457+
id: ast::NodeId,
458+
result: Option<usize>,
459+
expr_and_pat_count: usize,
460+
}
461+
462+
// This visitor has to have the same visit_expr calls as RegionResolutionVisitor
463+
// since `expr_count` is compared against the results there.
464+
impl<'tcx> Visitor<'tcx> for ExprLocatorVisitor {
465+
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
466+
NestedVisitorMap::None
467+
}
468+
469+
fn visit_pat(&mut self, pat: &'tcx Pat) {
470+
self.expr_and_pat_count += 1;
471+
472+
intravisit::walk_pat(self, pat);
473+
}
474+
475+
fn visit_expr(&mut self, expr: &'tcx Expr) {
476+
debug!("ExprLocatorVisitor - pre-increment {} expr = {:?}",
477+
self.expr_and_pat_count,
478+
expr);
479+
480+
intravisit::walk_expr(self, expr);
481+
482+
self.expr_and_pat_count += 1;
483+
484+
debug!("ExprLocatorVisitor - post-increment {} expr = {:?}",
485+
self.expr_and_pat_count,
486+
expr);
487+
488+
if expr.id == self.id {
489+
self.result = Some(self.expr_and_pat_count);
490+
}
491+
}
492+
}
456493

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

652+
/// Returns the id of the innermost containing body
653+
pub fn containing_body(&self, mut scope: Scope)-> Option<hir::ItemLocalId> {
654+
loop {
655+
if let ScopeData::CallSite(id) = scope.data() {
656+
return Some(id);
657+
}
658+
659+
match self.opt_encl_scope(scope) {
660+
None => return None,
661+
Some(parent) => scope = parent,
662+
}
663+
}
664+
}
665+
615666
/// Finds the nearest common ancestor (if any) of two scopes. That is, finds the smallest
616667
/// scope which is greater than or equal to both `scope_a` and `scope_b`.
617668
pub fn nearest_common_ancestor(&self,
@@ -768,6 +819,28 @@ impl<'tcx> ScopeTree {
768819
self.yield_in_scope.get(&scope).cloned()
769820
}
770821

822+
/// Checks whether the given scope contains a `yield` and if that yield could execute
823+
/// after `expr`. If so, it returns the span of that `yield`.
824+
/// `scope` must be inside the body.
825+
pub fn yield_in_scope_for_expr(&self,
826+
scope: Scope,
827+
expr: ast::NodeId,
828+
body: &'tcx hir::Body) -> Option<Span> {
829+
self.yield_in_scope(scope).and_then(|(span, count)| {
830+
let mut visitor = ExprLocatorVisitor {
831+
id: expr,
832+
result: None,
833+
expr_and_pat_count: 0,
834+
};
835+
visitor.visit_body(body);
836+
if count >= visitor.result.unwrap() {
837+
Some(span)
838+
} else {
839+
None
840+
}
841+
})
842+
}
843+
771844
/// Gives the number of expressions visited in a body.
772845
/// Used to sanity check visit_expr call count when
773846
/// calculating generator interiors.
@@ -872,9 +945,13 @@ fn resolve_pat<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, pat: &
872945
record_var_lifetime(visitor, pat.hir_id.local_id, pat.span);
873946
}
874947

948+
debug!("resolve_pat - pre-increment {} pat = {:?}", visitor.expr_and_pat_count, pat);
949+
875950
intravisit::walk_pat(visitor, pat);
876951

877952
visitor.expr_and_pat_count += 1;
953+
954+
debug!("resolve_pat - post-increment {} pat = {:?}", visitor.expr_and_pat_count, pat);
878955
}
879956

880957
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:
897974
}
898975

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

902979
let prev_cx = visitor.cx;
903980
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:
9821059

9831060
visitor.expr_and_pat_count += 1;
9841061

1062+
debug!("resolve_expr post-increment {}, expr = {:?}", visitor.expr_and_pat_count, expr);
1063+
9851064
if let hir::ExprYield(..) = expr.node {
9861065
// Mark this expr's scope and all parent scopes as containing `yield`.
9871066
let mut scope = Scope::Node(expr.hir_id.local_id);
@@ -1077,12 +1156,13 @@ fn resolve_local<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>,
10771156
}
10781157
}
10791158

1080-
if let Some(pat) = pat {
1081-
visitor.visit_pat(pat);
1082-
}
1159+
// Make sure we visit the initializer first, so expr_and_pat_count remains correct
10831160
if let Some(expr) = init {
10841161
visitor.visit_expr(expr);
10851162
}
1163+
if let Some(pat) = pat {
1164+
visitor.visit_pat(pat);
1165+
}
10861166

10871167
/// True if `pat` match the `P&` nonterminal:
10881168
///

src/librustc/traits/coherence.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -451,7 +451,10 @@ fn ty_is_local_constructor(ty: Ty, in_crate: InCrate) -> bool {
451451
true
452452
}
453453

454-
ty::TyClosure(..) | ty::TyGenerator(..) | ty::TyAnon(..) => {
454+
ty::TyClosure(..) |
455+
ty::TyGenerator(..) |
456+
ty::TyGeneratorWitness(..) |
457+
ty::TyAnon(..) => {
455458
bug!("ty_is_local invoked on unexpected type: {:?}", ty)
456459
}
457460
}

src/librustc/traits/error_reporting.rs

+1
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
262262
},
263263
ty::TyGenerator(..) => Some(18),
264264
ty::TyForeign(..) => Some(19),
265+
ty::TyGeneratorWitness(..) => Some(20),
265266
ty::TyInfer(..) | ty::TyError => None
266267
}
267268
}

src/librustc/traits/select.rs

+11-5
Original file line numberDiff line numberDiff line change
@@ -2044,8 +2044,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
20442044
ty::TyUint(_) | ty::TyInt(_) | ty::TyBool | ty::TyFloat(_) |
20452045
ty::TyFnDef(..) | ty::TyFnPtr(_) | ty::TyRawPtr(..) |
20462046
ty::TyChar | ty::TyRef(..) | ty::TyGenerator(..) |
2047-
ty::TyArray(..) | ty::TyClosure(..) | ty::TyNever |
2048-
ty::TyError => {
2047+
ty::TyGeneratorWitness(..) | ty::TyArray(..) | ty::TyClosure(..) |
2048+
ty::TyNever | ty::TyError => {
20492049
// safe for everything
20502050
Where(ty::Binder(Vec::new()))
20512051
}
@@ -2095,7 +2095,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
20952095
}
20962096

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

22082208
ty::TyGenerator(def_id, ref substs, interior) => {
2209-
let witness = iter::once(interior.witness);
2210-
substs.upvar_tys(def_id, self.tcx()).chain(witness).collect()
2209+
substs.upvar_tys(def_id, self.tcx()).chain(iter::once(interior.witness)).collect()
2210+
}
2211+
2212+
ty::TyGeneratorWitness(types) => {
2213+
// This is sound because no regions in the witness can refer to
2214+
// the binder outside the witness. So we'll effectivly reuse
2215+
// the implicit binder around the witness.
2216+
types.skip_binder().to_vec()
22112217
}
22122218

22132219
// for `PhantomData<T>`, we pass `T`

src/librustc/ty/context.rs

+7-2
Original file line numberDiff line numberDiff line change
@@ -1672,8 +1672,9 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {
16721672
pub fn print_debug_stats(self) {
16731673
sty_debug_print!(
16741674
self,
1675-
TyAdt, TyArray, TySlice, TyRawPtr, TyRef, TyFnDef, TyFnPtr, TyGenerator, TyForeign,
1676-
TyDynamic, TyClosure, TyTuple, TyParam, TyInfer, TyProjection, TyAnon);
1675+
TyAdt, TyArray, TySlice, TyRawPtr, TyRef, TyFnDef, TyFnPtr,
1676+
TyGenerator, TyGeneratorWitness, TyDynamic, TyClosure, TyTuple,
1677+
TyParam, TyInfer, TyProjection, TyAnon, TyForeign);
16771678

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

2083+
pub fn mk_generator_witness(self, types: ty::Binder<&'tcx Slice<Ty<'tcx>>>) -> Ty<'tcx> {
2084+
self.mk_ty(TyGeneratorWitness(types))
2085+
}
2086+
20822087
pub fn mk_var(self, v: TyVid) -> Ty<'tcx> {
20832088
self.mk_infer(TyVar(v))
20842089
}

src/librustc/ty/error.rs

+1
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,7 @@ impl<'a, 'gcx, 'lcx, 'tcx> ty::TyS<'tcx> {
227227
}
228228
ty::TyClosure(..) => "closure".to_string(),
229229
ty::TyGenerator(..) => "generator".to_string(),
230+
ty::TyGeneratorWitness(..) => "generator witness".to_string(),
230231
ty::TyTuple(..) => "tuple".to_string(),
231232
ty::TyInfer(ty::TyVar(_)) => "inferred type".to_string(),
232233
ty::TyInfer(ty::IntVar(_)) => "integral variable".to_string(),

src/librustc/ty/fast_reject.rs

+6
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ pub enum SimplifiedTypeGen<D>
4646
TraitSimplifiedType(D),
4747
ClosureSimplifiedType(D),
4848
GeneratorSimplifiedType(D),
49+
GeneratorWitnessSimplifiedType(usize),
4950
AnonSimplifiedType(D),
5051
FunctionSimplifiedType(usize),
5152
ParameterSimplifiedType,
@@ -92,6 +93,9 @@ pub fn simplify_type<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
9293
ty::TyGenerator(def_id, _, _) => {
9394
Some(GeneratorSimplifiedType(def_id))
9495
}
96+
ty::TyGeneratorWitness(ref tys) => {
97+
Some(GeneratorWitnessSimplifiedType(tys.skip_binder().len()))
98+
}
9599
ty::TyNever => Some(NeverSimplifiedType),
96100
ty::TyTuple(ref tys, _) => {
97101
Some(TupleSimplifiedType(tys.len()))
@@ -141,6 +145,7 @@ impl<D: Copy + Debug + Ord + Eq + Hash> SimplifiedTypeGen<D> {
141145
TraitSimplifiedType(d) => TraitSimplifiedType(map(d)),
142146
ClosureSimplifiedType(d) => ClosureSimplifiedType(map(d)),
143147
GeneratorSimplifiedType(d) => GeneratorSimplifiedType(map(d)),
148+
GeneratorWitnessSimplifiedType(n) => GeneratorWitnessSimplifiedType(n),
144149
AnonSimplifiedType(d) => AnonSimplifiedType(map(d)),
145150
FunctionSimplifiedType(n) => FunctionSimplifiedType(n),
146151
ParameterSimplifiedType => ParameterSimplifiedType,
@@ -175,6 +180,7 @@ impl<'gcx, D> HashStable<StableHashingContext<'gcx>> for SimplifiedTypeGen<D>
175180
TraitSimplifiedType(d) => d.hash_stable(hcx, hasher),
176181
ClosureSimplifiedType(d) => d.hash_stable(hcx, hasher),
177182
GeneratorSimplifiedType(d) => d.hash_stable(hcx, hasher),
183+
GeneratorWitnessSimplifiedType(n) => n.hash_stable(hcx, hasher),
178184
AnonSimplifiedType(d) => d.hash_stable(hcx, hasher),
179185
FunctionSimplifiedType(n) => n.hash_stable(hcx, hasher),
180186
ForeignSimplifiedType(d) => d.hash_stable(hcx, hasher),

src/librustc/ty/flags.rs

+6
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,12 @@ impl FlagComputation {
9494
self.add_ty(interior.witness);
9595
}
9696

97+
&ty::TyGeneratorWitness(ref ts) => {
98+
let mut computation = FlagComputation::new();
99+
computation.add_tys(&ts.skip_binder()[..]);
100+
self.add_bound_computation(&computation);
101+
}
102+
97103
&ty::TyClosure(_, ref substs) => {
98104
self.add_flags(TypeFlags::HAS_TY_CLOSURE);
99105
self.add_flags(TypeFlags::HAS_LOCAL_NAMES);

0 commit comments

Comments
 (0)