Initial pass review comments

This commit is contained in:
Alex Crichton 2017-08-09 13:56:19 -07:00
parent c25ddf21f1
commit 352577f4bb
28 changed files with 253 additions and 207 deletions

View File

@ -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,

View File

@ -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.

View File

@ -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()
}

View File

@ -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) => {

View File

@ -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`

View File

@ -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))
}
}

View File

@ -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<Self::Lifted> {
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<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
self.0.visit_with(visitor)
self.witness.visit_with(visitor)
}
}

View File

@ -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<Ty<'tcx>> {
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<GenSig<'tcx>>;
#[allow(warnings)]
impl<'tcx> PolyGenSig<'tcx> {
pub fn yield_ty(&self) -> ty::Binder<Ty<'tcx>> {
self.map_bound_ref(|sig| sig.yield_ty)

View File

@ -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()
}

View File

@ -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());

View File

@ -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)
}
}

View File

@ -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<T: Idx> IdxSet<T> {
pub fn subtract(&mut self, other: &IdxSet<T>) -> bool {
bitwise(self.words_mut(), other.words(), &Subtract)
}
pub fn iter(&self) -> Iter<T> {
Iter {
cur: None,
iter: self.words().iter().enumerate(),
_pd: PhantomData,
}
}
}
pub struct Iter<'a, T: Idx> {
cur: Option<(Word, usize)>,
iter: iter::Enumerate<slice::Iter<'a, Word>>,
_pd: PhantomData<fn(&T)>,
}
impl<'a, T: Idx> Iterator for Iter<'a, T> {
type Item = T;
fn next(&mut self) -> Option<T> {
let word_bits = mem::size_of::<Word>() * 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,
}
}
}
}

View File

@ -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::FnOnce => {
Expr {
ty: closure_ty,
temp_lifetime: temp_lifetime,
span: expr.span,
kind: ExprKind::SelfRef,
}
}
}
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,
}
}
}
} else {
Expr {
ty: closure_ty,

View File

@ -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<Local, (Ty<'tcx>, 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<BasicBlock>,
@ -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);
}
}

View File

@ -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 |

View File

@ -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)
}

View File

@ -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

View File

@ -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) {

View File

@ -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();
}
}
}

View File

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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<Yield = (), Return = ()> {
|| {
if bar() {
yield;
}
}
}

View File

@ -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);

View File

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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),
}
}