Skip to content

Commit

Permalink
Auto merge of #47353 - nikomatsakis:nll-issue-47189, r=pnkfelix+nmats…
Browse files Browse the repository at this point in the history
…akis

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
  • Loading branch information
bors committed Jan 22, 2018
2 parents b887317 + 8f2cc02 commit fdc18b3
Show file tree
Hide file tree
Showing 8 changed files with 99 additions and 8 deletions.
9 changes: 9 additions & 0 deletions src/librustc/mir/visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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),
}
Expand Down
1 change: 1 addition & 0 deletions src/librustc_mir/borrow_check/nll/constraint_generation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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: {:?}",
Expand Down
17 changes: 16 additions & 1 deletion src/librustc_mir/borrow_check/nll/renumber.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -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={:?})",
Expand Down
9 changes: 9 additions & 0 deletions src/librustc_mir/borrow_check/nll/type_check/input_output.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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!(
Expand Down
20 changes: 16 additions & 4 deletions src/librustc_mir/borrow_check/nll/universal_regions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
}

Expand Down Expand Up @@ -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,
Expand All @@ -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,
}
}
Expand Down Expand Up @@ -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)
})
}
}

Expand Down
13 changes: 10 additions & 3 deletions src/librustc_mir/util/pretty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -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<()> {
Expand Down
3 changes: 3 additions & 0 deletions src/test/run-pass/generator/yield-subtype.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>() {
Expand Down
35 changes: 35 additions & 0 deletions src/test/ui/nll/generator-distinct-lifetime.rs
Original file line number Diff line number Diff line change
@@ -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);
}

0 comments on commit fdc18b3

Please sign in to comment.