diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs index 58067931d562e..57ed41f2f06e6 100644 --- a/src/librustc/mir/visit.rs +++ b/src/librustc/mir/visit.rs @@ -277,6 +277,13 @@ macro_rules! make_mir_visitor { 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. @@ -852,6 +859,8 @@ pub enum TyContext { /// The return type of the function. ReturnTy(SourceInfo), + YieldTy(SourceInfo), + /// A type found at some location. Location(Location), } diff --git a/src/librustc_mir/borrow_check/nll/constraint_generation.rs b/src/librustc_mir/borrow_check/nll/constraint_generation.rs index 7ca4ebd1cb296..3a39eb5c908de 100644 --- a/src/librustc_mir/borrow_check/nll/constraint_generation.rs +++ b/src/librustc_mir/borrow_check/nll/constraint_generation.rs @@ -69,6 +69,7 @@ impl<'cg, 'cx, 'gcx, 'tcx> Visitor<'tcx> for ConstraintGeneration<'cg, 'cx, 'gcx 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: {:?}", diff --git a/src/librustc_mir/borrow_check/nll/renumber.rs b/src/librustc_mir/borrow_check/nll/renumber.rs index 4aee48b979d61..c54acda8a6252 100644 --- a/src/librustc_mir/borrow_check/nll/renumber.rs +++ b/src/librustc_mir/borrow_check/nll/renumber.rs @@ -9,7 +9,7 @@ // 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}; @@ -90,6 +90,21 @@ impl<'a, 'gcx, 'tcx> MutVisitor<'tcx> for NLLVisitor<'a, 'gcx, 'tcx> { *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={:?})", diff --git a/src/librustc_mir/borrow_check/nll/type_check/input_output.rs b/src/librustc_mir/borrow_check/nll/type_check/input_output.rs index 9e88a632f5c3d..b1aeae0b76bb1 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/input_output.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/input_output.rs @@ -60,6 +60,15 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { 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!( diff --git a/src/librustc_mir/borrow_check/nll/universal_regions.rs b/src/librustc_mir/borrow_check/nll/universal_regions.rs index 7703235b4b741..e47e3c728dff2 100644 --- a/src/librustc_mir/borrow_check/nll/universal_regions.rs +++ b/src/librustc_mir/borrow_check/nll/universal_regions.rs @@ -96,6 +96,8 @@ pub struct UniversalRegions<'tcx> { /// our special inference variable there, we would mess that up. pub region_bound_pairs: Vec<(ty::Region<'tcx>, GenericKind<'tcx>)>, + pub yield_ty: Option>, + relations: UniversalRegionRelations, } @@ -505,6 +507,13 @@ impl<'cx, 'gcx, 'tcx> UniversalRegionsBuilder<'cx, 'gcx, 'tcx> { 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, @@ -516,6 +525,7 @@ impl<'cx, 'gcx, 'tcx> UniversalRegionsBuilder<'cx, 'gcx, 'tcx> { unnormalized_output_ty, unnormalized_input_tys, region_bound_pairs: self.region_bound_pairs, + yield_ty: yield_ty, relations: self.relations, } } @@ -794,10 +804,12 @@ impl<'tcx> UniversalRegionIndices<'tcx> { /// 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) + }) } } diff --git a/src/librustc_mir/util/pretty.rs b/src/librustc_mir/util/pretty.rs index 78d55ad34ed45..6ab5fee79c661 100644 --- a/src/librustc_mir/util/pretty.rs +++ b/src/librustc_mir/util/pretty.rs @@ -518,7 +518,7 @@ pub fn write_mir_intro<'a, 'gcx, 'tcx>( 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> = FxHashMap(); @@ -581,13 +581,20 @@ fn write_mir_sig(tcx: TyCtxt, src: MirSource, mir: &Mir, w: &mut Write) -> io::R 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<()> { diff --git a/src/test/run-pass/generator/yield-subtype.rs b/src/test/run-pass/generator/yield-subtype.rs index 5ea4b1fe93c80..7e8a0d1e2b925 100644 --- a/src/test/run-pass/generator/yield-subtype.rs +++ b/src/test/run-pass/generator/yield-subtype.rs @@ -8,6 +8,9 @@ // 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>() { diff --git a/src/test/ui/nll/generator-distinct-lifetime.rs b/src/test/ui/nll/generator-distinct-lifetime.rs new file mode 100644 index 0000000000000..60f67b1766c2c --- /dev/null +++ b/src/test/ui/nll/generator-distinct-lifetime.rs @@ -0,0 +1,35 @@ +// 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 or the MIT license +// , 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); +}