fn super_mir(&mut self,
mir: & $($mutability)* Mir<'tcx>) {
+ if let Some(yield_ty) = &$($mutability)* mir.yield_ty {
+ self.visit_ty(yield_ty, TyContext::YieldTy(SourceInfo {
+ span: mir.span,
+ scope: ARGUMENT_VISIBILITY_SCOPE,
+ }));
+ }
+
// for best performance, we want to use an iterator rather
// than a for-loop, to avoid calling Mir::invalidate for
// each basic block.
/// The return type of the function.
ReturnTy(SourceInfo),
+ YieldTy(SourceInfo),
+
/// A type found at some location.
Location(Location),
}
fn visit_ty(&mut self, ty: &ty::Ty<'tcx>, ty_context: TyContext) {
match ty_context {
TyContext::ReturnTy(source_info) |
+ TyContext::YieldTy(source_info) |
TyContext::LocalDecl { source_info, .. } => {
span_bug!(source_info.span,
"should not be visiting outside of the CFG: {:?}",
// except according to those terms.
use rustc::ty::subst::Substs;
-use rustc::ty::{self, ClosureSubsts, Ty, TypeFoldable};
+use rustc::ty::{self, ClosureSubsts, GeneratorInterior, Ty, TypeFoldable};
use rustc::mir::{BasicBlock, Location, Mir, Statement, StatementKind};
use rustc::mir::visit::{MutVisitor, TyContext};
use rustc::infer::{InferCtxt, NLLRegionVariableOrigin};
*constant = self.renumber_regions(ty_context, &*constant);
}
+ fn visit_generator_interior(&mut self,
+ interior: &mut GeneratorInterior<'tcx>,
+ location: Location) {
+ debug!(
+ "visit_generator_interior(interior={:?}, location={:?})",
+ interior,
+ location,
+ );
+
+ let ty_context = TyContext::Location(location);
+ *interior = self.renumber_regions(ty_context, interior);
+
+ debug!("visit_generator_interior: interior={:?}", interior);
+ }
+
fn visit_closure_substs(&mut self, substs: &mut ClosureSubsts<'tcx>, location: Location) {
debug!(
"visit_closure_substs(substs={:?}, location={:?})",
self.equate_normalized_input_or_output(start_position, input_ty, mir_input_ty);
}
+ assert!(
+ mir.yield_ty.is_some() && universal_regions.yield_ty.is_some() ||
+ mir.yield_ty.is_none() && universal_regions.yield_ty.is_none()
+ );
+ if let Some(mir_yield_ty) = mir.yield_ty {
+ let ur_yield_ty = universal_regions.yield_ty.unwrap();
+ self.equate_normalized_input_or_output(start_position, ur_yield_ty, mir_yield_ty);
+ }
+
// Return types are a bit more complex. They may contain existential `impl Trait`
// types.
debug!(
/// our special inference variable there, we would mess that up.
pub region_bound_pairs: Vec<(ty::Region<'tcx>, GenericKind<'tcx>)>,
+ pub yield_ty: Option<Ty<'tcx>>,
+
relations: UniversalRegionRelations,
}
num_universals
);
+ let yield_ty = match defining_ty {
+ DefiningTy::Generator(def_id, substs, _) => {
+ Some(substs.generator_yield_ty(def_id, self.infcx.tcx))
+ }
+ _ => None,
+ };
+
UniversalRegions {
indices,
fr_static,
unnormalized_output_ty,
unnormalized_input_tys,
region_bound_pairs: self.region_bound_pairs,
+ yield_ty: yield_ty,
relations: self.relations,
}
}
/// during initialization. Relies on the `indices` map having been
/// fully initialized.
pub fn to_region_vid(&self, r: ty::Region<'tcx>) -> RegionVid {
- match r {
- ty::ReEarlyBound(..) | ty::ReStatic => *self.indices.get(&r).unwrap(),
- ty::ReVar(..) => r.to_region_vid(),
- _ => bug!("cannot convert `{:?}` to a region vid", r),
+ if let ty::ReVar(..) = r {
+ r.to_region_vid()
+ } else {
+ *self.indices.get(&r).unwrap_or_else(|| {
+ bug!("cannot convert `{:?}` to a region vid", r)
+ })
}
}
w: &mut Write,
) -> io::Result<()> {
write_mir_sig(tcx, src, mir, w)?;
- writeln!(w, " {{")?;
+ writeln!(w, "{{")?;
// construct a scope tree and write it out
let mut scope_tree: FxHashMap<VisibilityScope, Vec<VisibilityScope>> = FxHashMap();
write!(w, "{:?}: {}", Place::Local(arg), mir.local_decls[arg].ty)?;
}
- write!(w, ") -> {}", mir.return_ty())
+ write!(w, ") -> {}", mir.return_ty())?;
}
(hir::BodyOwnerKind::Const, _) | (hir::BodyOwnerKind::Static(_), _) | (_, Some(_)) => {
assert_eq!(mir.arg_count, 0);
- write!(w, ": {} =", mir.return_ty())
+ write!(w, ": {} =", mir.return_ty())?;
}
}
+
+ if let Some(yield_ty) = mir.yield_ty {
+ writeln!(w)?;
+ writeln!(w, "yields {}", yield_ty)?;
+ }
+
+ Ok(())
}
fn write_temp_decls(mir: &Mir, w: &mut Write) -> io::Result<()> {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+// revisions:lexical nll
+#![cfg_attr(nll, feature(nll))]
+
#![feature(generators)]
fn bar<'a>() {
--- /dev/null
+// 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, nll)]
+
+// Test for issue #47189. Here, both `s` and `t` are live for the
+// generator's lifetime, but within the generator they have distinct
+// lifetimes. We accept this code -- even though the borrow extends
+// over a yield -- because the data that is borrowed (`*x`) is not
+// stored on the stack.
+
+// must-compile-successfully
+
+fn foo(x: &mut u32) {
+ move || {
+ let s = &mut *x;
+ yield;
+ *s += 1;
+
+ let t = &mut *x;
+ yield;
+ *t += 1;
+ };
+}
+
+fn main() {
+ foo(&mut 0);
+}