Skip to content

Commit 3a511e0

Browse files
Zoxcarielb1
authored andcommitted
Only consider yields coming after the expressions when computing generator interiors
1 parent 1e6ec9f commit 3a511e0

File tree

7 files changed

+85
-33
lines changed

7 files changed

+85
-33
lines changed

src/librustc/middle/region.rs

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ use ich::{StableHashingContext, NodeIdHashingMode};
1818
use util::nodemap::{FxHashMap, FxHashSet};
1919
use ty;
2020

21-
use std::collections::hash_map::Entry;
2221
use std::mem;
2322
use std::rc::Rc;
2423
use syntax::codemap;
@@ -250,8 +249,9 @@ pub struct ScopeTree {
250249
closure_tree: FxHashMap<hir::ItemLocalId, hir::ItemLocalId>,
251250

252251
/// If there are any `yield` nested within a scope, this map
253-
/// stores the `Span` of the first one.
254-
yield_in_scope: FxHashMap<Scope, Span>,
252+
/// stores the `Span` of the last one and the number of expressions
253+
/// which came before it in a generator body.
254+
yield_in_scope: FxHashMap<Scope, (Span, usize)>,
255255
}
256256

257257
#[derive(Debug, Copy, Clone)]
@@ -274,6 +274,9 @@ pub struct Context {
274274
struct RegionResolutionVisitor<'a, 'tcx: 'a> {
275275
tcx: TyCtxt<'a, 'tcx, 'tcx>,
276276

277+
// The number of expressions visited in the current body
278+
expr_count: usize,
279+
277280
// Generated scope tree:
278281
scope_tree: ScopeTree,
279282

@@ -611,8 +614,9 @@ impl<'tcx> ScopeTree {
611614
}
612615

613616
/// Checks whether the given scope contains a `yield`. If so,
614-
/// returns `Some(span)` with the span of a yield we found.
615-
pub fn yield_in_scope(&self, scope: Scope) -> Option<Span> {
617+
/// returns `Some((span, expr_count))` with the span of a yield we found and
618+
/// the number of expressions appearing before the `yield` in the body.
619+
pub fn yield_in_scope(&self, scope: Scope) -> Option<(Span, usize)> {
616620
self.yield_in_scope.get(&scope).cloned()
617621
}
618622
}
@@ -738,6 +742,8 @@ fn resolve_stmt<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, stmt:
738742
fn resolve_expr<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, expr: &'tcx hir::Expr) {
739743
debug!("resolve_expr(expr.id={:?})", expr.id);
740744

745+
visitor.expr_count += 1;
746+
741747
let prev_cx = visitor.cx;
742748
visitor.enter_node_scope_with_dtor(expr.hir_id.local_id);
743749

@@ -808,14 +814,8 @@ fn resolve_expr<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, expr:
808814
// Mark this expr's scope and all parent scopes as containing `yield`.
809815
let mut scope = Scope::Node(expr.hir_id.local_id);
810816
loop {
811-
match visitor.scope_tree.yield_in_scope.entry(scope) {
812-
// Another `yield` has already been found.
813-
Entry::Occupied(_) => break,
814-
815-
Entry::Vacant(entry) => {
816-
entry.insert(expr.span);
817-
}
818-
}
817+
visitor.scope_tree.yield_in_scope.insert(scope,
818+
(expr.span, visitor.expr_count));
819819

820820
// Keep traversing up while we can.
821821
match visitor.scope_tree.parent_map.get(&scope) {
@@ -1120,6 +1120,7 @@ impl<'a, 'tcx> Visitor<'tcx> for RegionResolutionVisitor<'a, 'tcx> {
11201120
body_id,
11211121
self.cx.parent);
11221122

1123+
let outer_ec = mem::replace(&mut self.expr_count, 0);
11231124
let outer_cx = self.cx;
11241125
let outer_ts = mem::replace(&mut self.terminating_scopes, FxHashSet());
11251126
self.terminating_scopes.insert(body.value.hir_id.local_id);
@@ -1166,6 +1167,7 @@ impl<'a, 'tcx> Visitor<'tcx> for RegionResolutionVisitor<'a, 'tcx> {
11661167
}
11671168

11681169
// Restore context we had at the start.
1170+
self.expr_count = outer_ec;
11691171
self.cx = outer_cx;
11701172
self.terminating_scopes = outer_ts;
11711173
}
@@ -1200,6 +1202,7 @@ fn region_scope_tree<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
12001202
let mut visitor = RegionResolutionVisitor {
12011203
tcx,
12021204
scope_tree: ScopeTree::default(),
1205+
expr_count: 0,
12031206
cx: Context {
12041207
root_id: None,
12051208
parent: None,

src/librustc_borrowck/borrowck/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -857,7 +857,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
857857
None
858858
};
859859

860-
if let Some(yield_span) = maybe_borrow_across_yield {
860+
if let Some((yield_span, _)) = maybe_borrow_across_yield {
861861
debug!("err_out_of_scope: opt_yield_span = {:?}", yield_span);
862862
struct_span_err!(self.tcx.sess,
863863
error_span,

src/librustc_typeck/check/generator_interior.rs

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
1616
use rustc::hir::def_id::DefId;
1717
use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
18-
use rustc::hir::{self, Body, Pat, PatKind, Expr};
18+
use rustc::hir::{self, Pat, PatKind, Expr};
1919
use rustc::middle::region;
2020
use rustc::ty::Ty;
2121
use std::rc::Rc;
@@ -26,14 +26,27 @@ struct InteriorVisitor<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
2626
fcx: &'a FnCtxt<'a, 'gcx, 'tcx>,
2727
types: FxHashMap<Ty<'tcx>, usize>,
2828
region_scope_tree: Rc<region::ScopeTree>,
29+
expr_count: usize,
2930
}
3031

3132
impl<'a, 'gcx, 'tcx> InteriorVisitor<'a, 'gcx, 'tcx> {
3233
fn record(&mut self, ty: Ty<'tcx>, scope: Option<region::Scope>, expr: Option<&'tcx Expr>) {
3334
use syntax_pos::DUMMY_SP;
3435

36+
if self.fcx.tcx.sess.verbose() {
37+
let span = scope.map_or(DUMMY_SP, |s| s.span(self.fcx.tcx, &self.region_scope_tree));
38+
self.fcx.tcx.sess.span_warn(span, &format!("temporary scope for node id {:?}", expr));
39+
}
40+
3541
let live_across_yield = scope.map_or(Some(DUMMY_SP), |s| {
36-
self.region_scope_tree.yield_in_scope(s)
42+
self.region_scope_tree.yield_in_scope(s).and_then(|(span, expr_count)| {
43+
// Check if the span in the region comes after the expression
44+
if expr_count > self.expr_count {
45+
Some(span)
46+
} else {
47+
None
48+
}
49+
})
3750
});
3851

3952
if let Some(span) = live_across_yield {
@@ -60,6 +73,7 @@ pub fn resolve_interior<'a, 'gcx, 'tcx>(fcx: &'a FnCtxt<'a, 'gcx, 'tcx>,
6073
fcx,
6174
types: FxHashMap(),
6275
region_scope_tree: fcx.tcx.region_scope_tree(def_id),
76+
expr_count: 0,
6377
};
6478
intravisit::walk_body(&mut visitor, body);
6579

@@ -82,15 +96,14 @@ pub fn resolve_interior<'a, 'gcx, 'tcx>(fcx: &'a FnCtxt<'a, 'gcx, 'tcx>,
8296
}
8397
}
8498

99+
// This visitor has to have the same visit_expr calls as RegionResolutionVisitor in
100+
// librustc/middle/region.rs since `expr_count` is compared against the results
101+
// there.
85102
impl<'a, 'gcx, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'gcx, 'tcx> {
86103
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
87104
NestedVisitorMap::None
88105
}
89106

90-
fn visit_body(&mut self, _body: &'tcx Body) {
91-
// Closures inside are not considered part of the generator interior
92-
}
93-
94107
fn visit_pat(&mut self, pat: &'tcx Pat) {
95108
if let PatKind::Binding(..) = pat.node {
96109
let scope = self.region_scope_tree.var_scope(pat.hir_id.local_id);
@@ -102,7 +115,15 @@ impl<'a, 'gcx, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'gcx, 'tcx> {
102115
}
103116

104117
fn visit_expr(&mut self, expr: &'tcx Expr) {
118+
self.expr_count += 1;
119+
120+
if self.fcx.tcx.sess.verbose() {
121+
self.fcx.tcx.sess.span_warn(expr.span, &format!("node id {:?}", expr.id));
122+
}
123+
105124
let scope = self.region_scope_tree.temporary_scope(expr.hir_id.local_id);
125+
126+
106127
let ty = self.fcx.tables.borrow().expr_ty_adjusted(expr);
107128
self.record(ty, scope, Some(expr));
108129

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![feature(generators)]
12+
13+
fn main() {
14+
let _a = || {
15+
yield;
16+
let a = String::new();
17+
a.len()
18+
};
19+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![feature(generators, generator_trait, conservative_impl_trait)]
12+
13+
use std::ops::Generator;
14+
15+
fn bar(baz: String) -> impl Generator<Yield=(), Return=()> {
16+
move || {
17+
yield drop(&baz);
18+
}
19+
}
20+
21+
fn main() {}

src/test/ui/generator/yield-in-args-rev.rs renamed to src/test/run-pass/generator/yield-in-args-rev.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,10 @@
1212

1313
fn foo(_a: (), _b: &bool) {}
1414

15-
// Some examples that probably *could* be accepted, but which we reject for now.
16-
1715
fn bar() {
1816
|| {
1917
let b = true;
20-
foo(yield, &b); //~ ERROR
18+
foo(yield, &b);
2119
};
2220
}
2321

src/test/ui/generator/yield-in-args-rev.stderr

Lines changed: 0 additions & 10 deletions
This file was deleted.

0 commit comments

Comments
 (0)