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:
commit
fdc18b3067
8 changed files with 99 additions and 8 deletions
|
@ -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),
|
||||
}
|
||||
|
|
|
@ -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: {:?}",
|
||||
|
|
|
@ -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={:?})",
|
||||
|
|
|
@ -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!(
|
||||
|
|
|
@ -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)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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<()> {
|
||||
|
|
|
@ -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>() {
|
||||
|
|
35
src/test/ui/nll/generator-distinct-lifetime.rs
Normal file
35
src/test/ui/nll/generator-distinct-lifetime.rs
Normal 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);
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue