Skip to content

Commit e9824c5

Browse files
committed
impose inputs/ouputs on MIR after the fact
The input/output types found in `UniversalRegions` are not normalized. The old code used to assign them directly into the MIR, which would lead to errors when there was a projection in a argument or return type. This also led to some special cases in the `renumber` code. We now renumber uniformly but then pass the input/output types into the MIR type-checker, which equates them with the types found in MIR. This allows us to normalize at the same time.
1 parent 3fcb13a commit e9824c5

File tree

6 files changed

+94
-68
lines changed

6 files changed

+94
-68
lines changed

src/librustc_mir/borrow_check/nll/mod.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ pub(in borrow_check) fn replace_regions_in_mir<'cx, 'gcx, 'tcx>(
5353
let universal_regions = UniversalRegions::new(infcx, def_id, param_env);
5454

5555
// Replace all remaining regions with fresh inference variables.
56-
renumber::renumber_mir(infcx, &universal_regions, mir);
56+
renumber::renumber_mir(infcx, mir);
5757

5858
let source = MirSource::item(def_id);
5959
mir_util::dump_mir(infcx.tcx, None, "renumber", &0, source, mir, |_, _| Ok(()));
@@ -86,6 +86,8 @@ pub(in borrow_check) fn compute_regions<'cx, 'gcx, 'tcx>(
8686
param_env,
8787
mir,
8888
fr_fn_body,
89+
universal_regions.input_tys,
90+
universal_regions.output_ty,
8991
&liveness,
9092
flow_inits,
9193
move_data,

src/librustc_mir/borrow_check/nll/renumber.rs

Lines changed: 5 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -8,50 +8,24 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
use rustc_data_structures::indexed_vec::Idx;
1211
use rustc::ty::subst::Substs;
1312
use rustc::ty::{self, ClosureSubsts, Ty, TypeFoldable};
14-
use rustc::mir::{BasicBlock, Local, Location, Mir, Statement, StatementKind};
15-
use rustc::mir::RETURN_PLACE;
13+
use rustc::mir::{BasicBlock, Location, Mir, Statement, StatementKind};
1614
use rustc::mir::visit::{MutVisitor, TyContext};
1715
use rustc::infer::{InferCtxt, NLLRegionVariableOrigin};
1816

19-
use super::ToRegionVid;
20-
use super::universal_regions::UniversalRegions;
21-
2217
/// Replaces all free regions appearing in the MIR with fresh
2318
/// inference variables, returning the number of variables created.
24-
pub fn renumber_mir<'a, 'gcx, 'tcx>(
25-
infcx: &InferCtxt<'a, 'gcx, 'tcx>,
26-
universal_regions: &UniversalRegions<'tcx>,
27-
mir: &mut Mir<'tcx>,
28-
) {
19+
pub fn renumber_mir<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, mir: &mut Mir<'tcx>) {
2920
debug!("renumber_mir()");
3021
debug!("renumber_mir: mir.arg_count={:?}", mir.arg_count);
3122

32-
// Update the return type and types of the arguments based on the
33-
// `universal_regions` computation.
34-
debug!("renumber_mir: output_ty={:?}", universal_regions.output_ty);
35-
mir.local_decls[RETURN_PLACE].ty = universal_regions.output_ty;
36-
for (&input_ty, local) in universal_regions
37-
.input_tys
38-
.iter()
39-
.zip((1..).map(Local::new))
40-
{
41-
debug!("renumber_mir: input_ty={:?} local={:?}", input_ty, local);
42-
mir.local_decls[local].ty = input_ty;
43-
}
44-
45-
let mut visitor = NLLVisitor {
46-
infcx,
47-
arg_count: mir.arg_count,
48-
};
23+
let mut visitor = NLLVisitor { infcx };
4924
visitor.visit_mir(mir);
5025
}
5126

5227
struct NLLVisitor<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
5328
infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
54-
arg_count: usize,
5529
}
5630

5731
impl<'a, 'gcx, 'tcx> NLLVisitor<'a, 'gcx, 'tcx> {
@@ -71,45 +45,13 @@ impl<'a, 'gcx, 'tcx> NLLVisitor<'a, 'gcx, 'tcx> {
7145
self.infcx.next_nll_region_var(origin)
7246
})
7347
}
74-
75-
/// Checks that all the regions appearing in `value` have already
76-
/// been renumbered. `FreeRegions` code should have done this.
77-
fn assert_free_regions_are_renumbered<T>(&self, value: &T)
78-
where
79-
T: TypeFoldable<'tcx>,
80-
{
81-
debug!("assert_free_regions_are_renumbered(value={:?})", value);
82-
83-
self.infcx.tcx.for_each_free_region(value, |region| {
84-
region.to_region_vid(); // will panic if `region` is not renumbered
85-
});
86-
}
87-
88-
fn is_argument_or_return_slot(&self, local: Local) -> bool {
89-
// The first argument is return slot, next N are arguments.
90-
local.index() <= self.arg_count
91-
}
9248
}
9349

9450
impl<'a, 'gcx, 'tcx> MutVisitor<'tcx> for NLLVisitor<'a, 'gcx, 'tcx> {
9551
fn visit_ty(&mut self, ty: &mut Ty<'tcx>, ty_context: TyContext) {
96-
let is_arg = match ty_context {
97-
TyContext::LocalDecl { local, .. } => self.is_argument_or_return_slot(local),
98-
TyContext::ReturnTy(..) => true,
99-
TyContext::Location(..) => false,
100-
};
101-
debug!(
102-
"visit_ty(ty={:?}, is_arg={:?}, ty_context={:?})",
103-
ty,
104-
is_arg,
105-
ty_context
106-
);
52+
debug!("visit_ty(ty={:?}, ty_context={:?})", ty, ty_context);
10753

108-
if is_arg {
109-
self.assert_free_regions_are_renumbered(ty);
110-
} else {
111-
*ty = self.renumber_regions(ty_context, ty);
112-
}
54+
*ty = self.renumber_regions(ty_context, ty);
11355

11456
debug!("visit_ty: ty={:?}", ty);
11557
}

src/librustc_mir/borrow_check/nll/type_check/mod.rs

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,12 +46,31 @@ mod liveness;
4646
/// This phase of type-check ought to be infallible -- this is because
4747
/// the original, HIR-based type-check succeeded. So if any errors
4848
/// occur here, we will get a `bug!` reported.
49+
///
50+
/// # Parameters
51+
///
52+
/// - `infcx` -- inference context to use
53+
/// - `body_id` -- body-id of the MIR being checked
54+
/// - `param_env` -- parameter environment to use for trait solving
55+
/// - `mir` -- MIR to type-check
56+
/// - `implicit_region_bound` -- a region which all generic parameters are assumed
57+
/// to outlive; should represent the fn body
58+
/// - `input_tys` -- fully liberated, but **not** normalized, expected types of the arguments;
59+
/// the types of the input parameters found in the MIR itself will be equated with these
60+
/// - `output_ty` -- fully liberaetd, but **not** normalized, expected return type;
61+
/// the type for the RETURN_PLACE will be equated with this
62+
/// - `liveness` -- results of a liveness computation on the MIR; used to create liveness
63+
/// constraints for the regions in the types of variables
64+
/// - `flow_inits` -- results of a maybe-init dataflow analysis
65+
/// - `move_data` -- move-data constructed when performing the maybe-init dataflow analysis
4966
pub(crate) fn type_check<'gcx, 'tcx>(
5067
infcx: &InferCtxt<'_, 'gcx, 'tcx>,
5168
body_id: ast::NodeId,
5269
param_env: ty::ParamEnv<'gcx>,
5370
mir: &Mir<'tcx>,
5471
implicit_region_bound: ty::Region<'tcx>,
72+
input_tys: &[Ty<'tcx>],
73+
output_ty: Ty<'tcx>,
5574
liveness: &LivenessResults,
5675
flow_inits: &mut FlowAtLocation<MaybeInitializedLvals<'_, 'gcx, 'tcx>>,
5776
move_data: &MoveData<'tcx>,
@@ -62,7 +81,16 @@ pub(crate) fn type_check<'gcx, 'tcx>(
6281
param_env,
6382
mir,
6483
Some(implicit_region_bound),
65-
&mut |cx| liveness::generate(cx, mir, liveness, flow_inits, move_data),
84+
&mut |cx| {
85+
liveness::generate(cx, mir, liveness, flow_inits, move_data);
86+
87+
// Equate the input and output tys given by the user with
88+
// the ones found in the MIR.
89+
cx.equate_input_or_output(output_ty, mir.local_decls[RETURN_PLACE].ty);
90+
for (&input_ty, local) in input_tys.iter().zip((1..).map(Local::new)) {
91+
cx.equate_input_or_output(input_ty, mir.local_decls[local].ty);
92+
}
93+
},
6694
)
6795
}
6896

@@ -666,6 +694,25 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
666694
})
667695
}
668696

697+
fn equate_input_or_output(&mut self, unnormalized_a: Ty<'tcx>, b: Ty<'tcx>) {
698+
let start_position = Location {
699+
block: START_BLOCK,
700+
statement_index: 0,
701+
};
702+
let a = self.normalize(&unnormalized_a, start_position);
703+
if let Err(terr) = self.eq_types(a, b, start_position.at_self()) {
704+
span_mirbug!(
705+
self,
706+
start_position,
707+
"bad input or output {:?} normalized to {:?} should equal {:?} but got error {:?}",
708+
unnormalized_a,
709+
a,
710+
b,
711+
terr
712+
);
713+
}
714+
}
715+
669716
fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> {
670717
self.infcx.tcx
671718
}

src/librustc_mir/borrow_check/nll/universal_regions.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,12 +69,14 @@ pub struct UniversalRegions<'tcx> {
6969
/// closure type, but for a top-level function it's the `TyFnDef`.
7070
pub defining_ty: Ty<'tcx>,
7171

72-
/// The return type of this function, with all regions replaced
73-
/// by their universal `RegionVid` equivalents.
72+
/// The return type of this function, with all regions replaced by
73+
/// their universal `RegionVid` equivalents. This type is **NOT
74+
/// NORMALIZED**.
7475
pub output_ty: Ty<'tcx>,
7576

7677
/// The fully liberated input types of this function, with all
7778
/// regions replaced by their universal `RegionVid` equivalents.
79+
/// This type is **NOT NORMALIZED**.
7880
pub input_tys: &'tcx [Ty<'tcx>],
7981

8082
/// Each RBP `('a, GK)` indicates that `GK: 'a` can be assumed to

src/test/mir-opt/nll/named-lifetimes-basic.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,11 @@ fn main() {
3939
// | '_#2r | {'_#2r, bb0[0], bb0[1]}
4040
// | '_#3r | {'_#3r, bb0[0], bb0[1]}
4141
// | '_#4r | {'_#4r, bb0[0], bb0[1]}
42+
// | '_#5r | {'_#1r, bb0[0], bb0[1]}
43+
// | '_#6r | {'_#2r, bb0[0], bb0[1]}
44+
// | '_#7r | {'_#1r, bb0[0], bb0[1]}
45+
// | '_#8r | {'_#3r, bb0[0], bb0[1]}
4246
// |
4347
// ...
44-
// fn use_x(_1: &'_#1r mut i32, _2: &'_#2r u32, _3: &'_#1r u32, _4: &'_#3r u32) -> bool {
48+
// fn use_x(_1: &'_#5r mut i32, _2: &'_#6r u32, _3: &'_#7r u32, _4: &'_#8r u32) -> bool {
4549
// END rustc.use_x.nll.0.mir

src/test/ui/nll/projection-return.rs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// compile-flags:-Znll -Zborrowck=mir
12+
// must-compile-successfully
13+
14+
#![feature(rustc_attrs)]
15+
16+
trait Foo {
17+
type Bar;
18+
}
19+
20+
impl Foo for () {
21+
type Bar = u32;
22+
}
23+
24+
fn foo() -> <() as Foo>::Bar {
25+
22
26+
}
27+
28+
fn main() { }
29+

0 commit comments

Comments
 (0)