Skip to content

Commit 31ec2e7

Browse files
committed
propagate region_bound_pairs into MIR type-check
1 parent 25446dd commit 31ec2e7

8 files changed

+299
-33
lines changed

src/librustc_mir/borrow_check/nll/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ pub(in borrow_check) fn compute_regions<'cx, 'gcx, 'tcx>(
8585
mir_node_id,
8686
param_env,
8787
mir,
88+
&universal_regions.region_bound_pairs,
8889
fr_fn_body,
8990
universal_regions.input_tys,
9091
universal_regions.output_ty,

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

+47-33
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use dataflow::MaybeInitializedLvals;
1717
use dataflow::flow_in_progress::FlowInProgress;
1818
use dataflow::move_paths::MoveData;
1919
use rustc::infer::{InferCtxt, InferOk, InferResult, LateBoundRegionConversionTime, UnitResult};
20-
use rustc::infer::region_constraints::RegionConstraintData;
20+
use rustc::infer::region_constraints::{GenericKind, RegionConstraintData};
2121
use rustc::traits::{self, FulfillmentContext};
2222
use rustc::ty::error::TypeError;
2323
use rustc::ty::fold::TypeFoldable;
@@ -54,6 +54,8 @@ mod liveness;
5454
/// - `body_id` -- body-id of the MIR being checked
5555
/// - `param_env` -- parameter environment to use for trait solving
5656
/// - `mir` -- MIR to type-check
57+
/// - `region_bound_pairs` -- the implied outlives obligations between type parameters
58+
/// and lifetimes (e.g., `&'a T` implies `T: 'a`)
5759
/// - `implicit_region_bound` -- a region which all generic parameters are assumed
5860
/// to outlive; should represent the fn body
5961
/// - `input_tys` -- fully liberated, but **not** normalized, expected types of the arguments;
@@ -69,6 +71,7 @@ pub(crate) fn type_check<'gcx, 'tcx>(
6971
body_id: ast::NodeId,
7072
param_env: ty::ParamEnv<'gcx>,
7173
mir: &Mir<'tcx>,
74+
region_bound_pairs: &[(ty::Region<'tcx>, GenericKind<'tcx>)],
7275
implicit_region_bound: ty::Region<'tcx>,
7376
input_tys: &[Ty<'tcx>],
7477
output_ty: Ty<'tcx>,
@@ -81,6 +84,7 @@ pub(crate) fn type_check<'gcx, 'tcx>(
8184
body_id,
8285
param_env,
8386
mir,
87+
region_bound_pairs,
8488
Some(implicit_region_bound),
8589
&mut |cx| {
8690
liveness::generate(cx, mir, liveness, flow_inits, move_data);
@@ -100,10 +104,17 @@ fn type_check_internal<'gcx, 'tcx>(
100104
body_id: ast::NodeId,
101105
param_env: ty::ParamEnv<'gcx>,
102106
mir: &Mir<'tcx>,
107+
region_bound_pairs: &[(ty::Region<'tcx>, GenericKind<'tcx>)],
103108
implicit_region_bound: Option<ty::Region<'tcx>>,
104109
extra: &mut FnMut(&mut TypeChecker<'_, 'gcx, 'tcx>),
105110
) -> MirTypeckRegionConstraints<'tcx> {
106-
let mut checker = TypeChecker::new(infcx, body_id, param_env, implicit_region_bound);
111+
let mut checker = TypeChecker::new(
112+
infcx,
113+
body_id,
114+
param_env,
115+
region_bound_pairs,
116+
implicit_region_bound,
117+
);
107118
let errors_reported = {
108119
let mut verifier = TypeVerifier::new(&mut checker, mir);
109120
verifier.visit_mir(mir);
@@ -563,6 +574,7 @@ struct TypeChecker<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
563574
param_env: ty::ParamEnv<'gcx>,
564575
last_span: Span,
565576
body_id: ast::NodeId,
577+
region_bound_pairs: &'a [(ty::Region<'tcx>, GenericKind<'tcx>)],
566578
implicit_region_bound: Option<ty::Region<'tcx>>,
567579
reported_errors: FxHashSet<(Ty<'tcx>, Span)>,
568580
constraints: MirTypeckRegionConstraints<'tcx>,
@@ -617,13 +629,15 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
617629
infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
618630
body_id: ast::NodeId,
619631
param_env: ty::ParamEnv<'gcx>,
632+
region_bound_pairs: &'a [(ty::Region<'tcx>, GenericKind<'tcx>)],
620633
implicit_region_bound: Option<ty::Region<'tcx>>,
621634
) -> Self {
622635
TypeChecker {
623636
infcx,
624637
last_span: DUMMY_SP,
625638
body_id,
626639
param_env,
640+
region_bound_pairs,
627641
implicit_region_bound,
628642
reported_errors: FxHashSet(),
629643
constraints: MirTypeckRegionConstraints::default(),
@@ -650,7 +664,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
650664
}
651665

652666
self.infcx.process_registered_region_obligations(
653-
&[],
667+
self.region_bound_pairs,
654668
self.implicit_region_bound,
655669
self.param_env,
656670
self.body_id,
@@ -756,12 +770,12 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
756770
);
757771
};
758772
}
759-
StatementKind::StorageLive(_) |
760-
StatementKind::StorageDead(_) |
761-
StatementKind::InlineAsm { .. } |
762-
StatementKind::EndRegion(_) |
763-
StatementKind::Validate(..) |
764-
StatementKind::Nop => {}
773+
StatementKind::StorageLive(_)
774+
| StatementKind::StorageDead(_)
775+
| StatementKind::InlineAsm { .. }
776+
| StatementKind::EndRegion(_)
777+
| StatementKind::Validate(..)
778+
| StatementKind::Nop => {}
765779
}
766780
}
767781

@@ -774,13 +788,13 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
774788
debug!("check_terminator: {:?}", term);
775789
let tcx = self.tcx();
776790
match term.kind {
777-
TerminatorKind::Goto { .. } |
778-
TerminatorKind::Resume |
779-
TerminatorKind::Return |
780-
TerminatorKind::GeneratorDrop |
781-
TerminatorKind::Unreachable |
782-
TerminatorKind::Drop { .. } |
783-
TerminatorKind::FalseEdges { .. } => {
791+
TerminatorKind::Goto { .. }
792+
| TerminatorKind::Resume
793+
| TerminatorKind::Return
794+
| TerminatorKind::GeneratorDrop
795+
| TerminatorKind::Unreachable
796+
| TerminatorKind::Drop { .. }
797+
| TerminatorKind::FalseEdges { .. } => {
784798
// no checks needed for these
785799
}
786800

@@ -880,9 +894,11 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
880894
// output) types in the signature must be live, since
881895
// all the inputs that fed into it were live.
882896
for &late_bound_region in map.values() {
883-
self.constraints
884-
.liveness_set
885-
.push((late_bound_region, term_location, Cause::LiveOther(term_location)));
897+
self.constraints.liveness_set.push((
898+
late_bound_region,
899+
term_location,
900+
Cause::LiveOther(term_location),
901+
));
886902
}
887903

888904
if self.is_box_free(func) {
@@ -1092,9 +1108,9 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
10921108
}
10931109
}
10941110
TerminatorKind::Unreachable => {}
1095-
TerminatorKind::Drop { target, unwind, .. } |
1096-
TerminatorKind::DropAndReplace { target, unwind, .. } |
1097-
TerminatorKind::Assert {
1111+
TerminatorKind::Drop { target, unwind, .. }
1112+
| TerminatorKind::DropAndReplace { target, unwind, .. }
1113+
| TerminatorKind::Assert {
10981114
target,
10991115
cleanup: unwind,
11001116
..
@@ -1350,13 +1366,13 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
13501366
},
13511367

13521368
// FIXME: These other cases have to be implemented in future PRs
1353-
Rvalue::Use(..) |
1354-
Rvalue::Ref(..) |
1355-
Rvalue::Len(..) |
1356-
Rvalue::BinaryOp(..) |
1357-
Rvalue::CheckedBinaryOp(..) |
1358-
Rvalue::UnaryOp(..) |
1359-
Rvalue::Discriminant(..) => {}
1369+
Rvalue::Use(..)
1370+
| Rvalue::Ref(..)
1371+
| Rvalue::Len(..)
1372+
| Rvalue::BinaryOp(..)
1373+
| Rvalue::CheckedBinaryOp(..)
1374+
| Rvalue::UnaryOp(..)
1375+
| Rvalue::Discriminant(..) => {}
13601376
}
13611377
}
13621378

@@ -1490,9 +1506,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
14901506
let cause = this.misc(this.last_span);
14911507
let obligations = predicates
14921508
.iter()
1493-
.map(|&p| {
1494-
traits::Obligation::new(cause.clone(), this.param_env, p)
1495-
})
1509+
.map(|&p| traits::Obligation::new(cause.clone(), this.param_env, p))
14961510
.collect();
14971511
Ok(InferOk {
14981512
value: (),
@@ -1556,7 +1570,7 @@ impl MirPass for TypeckMir {
15561570
}
15571571
let param_env = tcx.param_env(def_id);
15581572
tcx.infer_ctxt().enter(|infcx| {
1559-
let _ = type_check_internal(&infcx, id, param_env, mir, None, &mut |_| ());
1573+
let _ = type_check_internal(&infcx, id, param_env, mir, &[], None, &mut |_| ());
15601574

15611575
// For verification purposes, we just ignore the resulting
15621576
// region constraint sets. Not our problem. =)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
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 -Zverbose
12+
13+
// Test that we can deduce when projections like `T::Item` outlive the
14+
// function body. Test that this does not imply that `T: 'a` holds.
15+
16+
#![allow(warnings)]
17+
#![feature(rustc_attrs)]
18+
19+
use std::cell::Cell;
20+
21+
fn twice<F, T>(mut value: T, mut f: F)
22+
where
23+
F: FnMut(&T, Cell<&Option<T::Item>>),
24+
T: Iterator,
25+
{
26+
let mut n = value.next();
27+
f(&value, Cell::new(&n));
28+
f(&value, Cell::new(&n));
29+
}
30+
31+
#[rustc_errors]
32+
fn generic1<T: Iterator>(value: T) {
33+
// No error here:
34+
twice(value, |value_ref, item| invoke1(item));
35+
}
36+
37+
fn invoke1<'a, T>(x: Cell<&'a Option<T>>)
38+
where
39+
T: 'a,
40+
{
41+
}
42+
43+
#[rustc_errors]
44+
fn generic2<T: Iterator>(value: T) {
45+
twice(value, |value_ref, item| invoke2(value_ref, item));
46+
//~^ WARNING not reporting region error due to -Znll
47+
//~| ERROR failed type test
48+
}
49+
50+
fn invoke2<'a, T, U>(a: &T, b: Cell<&'a Option<U>>)
51+
where
52+
T: 'a,
53+
{
54+
}
55+
56+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
warning: not reporting region error due to -Znll
2+
--> $DIR/projection-implied-bounds.rs:45:36
3+
|
4+
45 | twice(value, |value_ref, item| invoke2(value_ref, item));
5+
| ^^^^^^^
6+
7+
error: failed type test: TypeTest { generic_kind: T/#0, lower_bound: '_#0r, point: bb0[3], span: $DIR/projection-implied-bounds.rs:45:18: 45:60, test: IsOutlivedByAnyRegionIn(['_#1r]) }
8+
--> $DIR/projection-implied-bounds.rs:45:18
9+
|
10+
45 | twice(value, |value_ref, item| invoke2(value_ref, item));
11+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
12+
13+
error: aborting due to previous error
14+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
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 -Zverbose
12+
13+
#![allow(warnings)]
14+
#![feature(dyn_trait)]
15+
#![feature(rustc_attrs)]
16+
17+
use std::cell::Cell;
18+
19+
// Invoke in such a way that the callee knows:
20+
//
21+
// - 'a: 'x
22+
//
23+
// and it must prove that `T: 'x`. Callee passes along `T: 'a`.
24+
fn twice<'a, F, T>(v: Cell<&'a ()>, value: T, mut f: F)
25+
where
26+
F: for<'x> FnMut(Option<Cell<&'a &'x ()>>, &T),
27+
{
28+
f(None, &value);
29+
f(None, &value);
30+
}
31+
32+
#[rustc_regions]
33+
fn generic<T>(value: T) {
34+
let cell = Cell::new(&());
35+
twice(cell, value, |a, b| invoke(a, b));
36+
//~^ WARNING not reporting region error
37+
//
38+
// This error from the old region solver looks bogus.
39+
}
40+
41+
#[rustc_regions]
42+
fn generic_fail<'a, T>(cell: Cell<&'a ()>, value: T) {
43+
twice(cell, value, |a, b| invoke(a, b));
44+
//~^ WARNING not reporting region error
45+
//~| WARNING not reporting region error
46+
//~| ERROR failed type test
47+
}
48+
49+
fn invoke<'a, 'x, T>(x: Option<Cell<&'x &'a ()>>, y: &T)
50+
where
51+
T: 'x,
52+
{
53+
}
54+
55+
fn main() {}

0 commit comments

Comments
 (0)