1
Fork 0

Auto merge of #47353 - nikomatsakis:nll-issue-47189, r=pnkfelix+nmatsakis

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
This commit is contained in:
bors 2018-01-22 11:11:47 +00:00
commit fdc18b3067
8 changed files with 99 additions and 8 deletions

View file

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

View file

@ -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: {:?}",

View 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 @@ 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={:?})",

View file

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

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

View 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<()> {

View 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>() {

View file

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