]> git.lizzy.rs Git - rust.git/commitdiff
Auto merge of #47353 - nikomatsakis:nll-issue-47189, r=pnkfelix+nmatsakis
authorbors <bors@rust-lang.org>
Mon, 22 Jan 2018 11:11:47 +0000 (11:11 +0000)
committerbors <bors@rust-lang.org>
Mon, 22 Jan 2018 11:11:47 +0000 (11:11 +0000)
renumber regions in generators

This fixes #47189, but I think we still have to double check various things around how to treat generators in MIR type check + borrow check (e.g., what borrows should be invalidated by a `Suspend`? What consistency properties should type check be enforcing anyway around the "interior" type?)

Also fixes #47587 thanks to @spastorino's commit.

r? @pnkfelix

src/librustc/mir/visit.rs
src/librustc_mir/borrow_check/nll/constraint_generation.rs
src/librustc_mir/borrow_check/nll/renumber.rs
src/librustc_mir/borrow_check/nll/type_check/input_output.rs
src/librustc_mir/borrow_check/nll/universal_regions.rs
src/librustc_mir/util/pretty.rs
src/test/run-pass/generator/yield-subtype.rs
src/test/ui/nll/generator-distinct-lifetime.rs [new file with mode: 0644]

index 58067931d562eed2e8d157012a001c06db8db556..57ed41f2f06e63c7ef6968409e55754ef44f3dbc 100644 (file)
@@ -277,6 +277,13 @@ fn visit_visibility_scope(&mut self,
 
             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),
 }
index 7ca4ebd1cb29660dd60576d21669f5976a06da05..3a39eb5c908de3660efe06d05d7a7da6e2d4d9a1 100644 (file)
@@ -69,6 +69,7 @@ fn visit_region(&mut self, region: &ty::Region<'tcx>, 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: {:?}",
index 4aee48b979d6150541087aef8e85d8ba65a0ebd4..c54acda8a6252786b26cb30083b1c85663fd7c37 100644 (file)
@@ -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 @@ fn visit_const(&mut self, constant: &mut &'tcx ty::Const<'tcx>, location: Locati
         *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={:?})",
index 9e88a632f5c3dc833d10733bfe4858c2b7fee395..b1aeae0b76bb112b48234a286e1909d050db9dd9 100644 (file)
@@ -60,6 +60,15 @@ pub(super) fn equate_inputs_and_outputs(
             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!(
index 7703235b4b7411acae1f3b74a69f8c19f18aa282..e47e3c728dff21327697f69dbd55674052c23fa4 100644 (file)
@@ -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<Ty<'tcx>>,
+
     relations: UniversalRegionRelations,
 }
 
@@ -505,6 +507,13 @@ fn build(mut self) -> UniversalRegions<'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 @@ fn build(mut self) -> UniversalRegions<'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 @@ fn insert_late_bound_region(&mut self, r: ty::Region<'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)
+            })
         }
     }
 
index 78d55ad34ed45a77fe97d293120c910d543beef6..6ab5fee79c661e72b82d7f7c85cb5dcc1f541c73 100644 (file)
@@ -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<VisibilityScope, Vec<VisibilityScope>> = 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<()> {
index 5ea4b1fe93c8024684954d1995173b6221426aa1..7e8a0d1e2b925de0641fd6c0ae550e83b0560e4e 100644 (file)
@@ -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 (file)
index 0000000..60f67b1
--- /dev/null
@@ -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 <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);
+}