propagate region_bound_pairs
into MIR type-check
This commit is contained in:
parent
fe89f4ba86
commit
4a967c9df7
8 changed files with 300 additions and 33 deletions
|
@ -85,6 +85,7 @@ pub(in borrow_check) fn compute_regions<'cx, 'gcx, 'tcx>(
|
|||
mir_node_id,
|
||||
param_env,
|
||||
mir,
|
||||
&universal_regions.region_bound_pairs,
|
||||
fr_fn_body,
|
||||
universal_regions.input_tys,
|
||||
universal_regions.output_ty,
|
||||
|
|
|
@ -17,7 +17,7 @@ use dataflow::FlowAtLocation;
|
|||
use dataflow::MaybeInitializedLvals;
|
||||
use dataflow::move_paths::MoveData;
|
||||
use rustc::infer::{InferCtxt, InferOk, InferResult, LateBoundRegionConversionTime, UnitResult};
|
||||
use rustc::infer::region_constraints::RegionConstraintData;
|
||||
use rustc::infer::region_constraints::{GenericKind, RegionConstraintData};
|
||||
use rustc::traits::{self, FulfillmentContext};
|
||||
use rustc::ty::error::TypeError;
|
||||
use rustc::ty::fold::TypeFoldable;
|
||||
|
@ -54,6 +54,8 @@ mod liveness;
|
|||
/// - `body_id` -- body-id of the MIR being checked
|
||||
/// - `param_env` -- parameter environment to use for trait solving
|
||||
/// - `mir` -- MIR to type-check
|
||||
/// - `region_bound_pairs` -- the implied outlives obligations between type parameters
|
||||
/// and lifetimes (e.g., `&'a T` implies `T: 'a`)
|
||||
/// - `implicit_region_bound` -- a region which all generic parameters are assumed
|
||||
/// to outlive; should represent the fn body
|
||||
/// - `input_tys` -- fully liberated, but **not** normalized, expected types of the arguments;
|
||||
|
@ -69,6 +71,7 @@ pub(crate) fn type_check<'gcx, 'tcx>(
|
|||
body_id: ast::NodeId,
|
||||
param_env: ty::ParamEnv<'gcx>,
|
||||
mir: &Mir<'tcx>,
|
||||
region_bound_pairs: &[(ty::Region<'tcx>, GenericKind<'tcx>)],
|
||||
implicit_region_bound: ty::Region<'tcx>,
|
||||
input_tys: &[Ty<'tcx>],
|
||||
output_ty: Ty<'tcx>,
|
||||
|
@ -81,6 +84,7 @@ pub(crate) fn type_check<'gcx, 'tcx>(
|
|||
body_id,
|
||||
param_env,
|
||||
mir,
|
||||
region_bound_pairs,
|
||||
Some(implicit_region_bound),
|
||||
&mut |cx| {
|
||||
liveness::generate(cx, mir, liveness, flow_inits, move_data);
|
||||
|
@ -100,10 +104,17 @@ fn type_check_internal<'gcx, 'tcx>(
|
|||
body_id: ast::NodeId,
|
||||
param_env: ty::ParamEnv<'gcx>,
|
||||
mir: &Mir<'tcx>,
|
||||
region_bound_pairs: &[(ty::Region<'tcx>, GenericKind<'tcx>)],
|
||||
implicit_region_bound: Option<ty::Region<'tcx>>,
|
||||
extra: &mut FnMut(&mut TypeChecker<'_, 'gcx, 'tcx>),
|
||||
) -> MirTypeckRegionConstraints<'tcx> {
|
||||
let mut checker = TypeChecker::new(infcx, body_id, param_env, implicit_region_bound);
|
||||
let mut checker = TypeChecker::new(
|
||||
infcx,
|
||||
body_id,
|
||||
param_env,
|
||||
region_bound_pairs,
|
||||
implicit_region_bound,
|
||||
);
|
||||
let errors_reported = {
|
||||
let mut verifier = TypeVerifier::new(&mut checker, mir);
|
||||
verifier.visit_mir(mir);
|
||||
|
@ -571,6 +582,7 @@ struct TypeChecker<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
|
|||
param_env: ty::ParamEnv<'gcx>,
|
||||
last_span: Span,
|
||||
body_id: ast::NodeId,
|
||||
region_bound_pairs: &'a [(ty::Region<'tcx>, GenericKind<'tcx>)],
|
||||
implicit_region_bound: Option<ty::Region<'tcx>>,
|
||||
reported_errors: FxHashSet<(Ty<'tcx>, Span)>,
|
||||
constraints: MirTypeckRegionConstraints<'tcx>,
|
||||
|
@ -625,6 +637,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
|
|||
infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
|
||||
body_id: ast::NodeId,
|
||||
param_env: ty::ParamEnv<'gcx>,
|
||||
region_bound_pairs: &'a [(ty::Region<'tcx>, GenericKind<'tcx>)],
|
||||
implicit_region_bound: Option<ty::Region<'tcx>>,
|
||||
) -> Self {
|
||||
TypeChecker {
|
||||
|
@ -632,6 +645,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
|
|||
last_span: DUMMY_SP,
|
||||
body_id,
|
||||
param_env,
|
||||
region_bound_pairs,
|
||||
implicit_region_bound,
|
||||
reported_errors: FxHashSet(),
|
||||
constraints: MirTypeckRegionConstraints::default(),
|
||||
|
@ -658,7 +672,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
|
|||
}
|
||||
|
||||
self.infcx.process_registered_region_obligations(
|
||||
&[],
|
||||
self.region_bound_pairs,
|
||||
self.implicit_region_bound,
|
||||
self.param_env,
|
||||
self.body_id,
|
||||
|
@ -764,12 +778,12 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
|
|||
);
|
||||
};
|
||||
}
|
||||
StatementKind::StorageLive(_) |
|
||||
StatementKind::StorageDead(_) |
|
||||
StatementKind::InlineAsm { .. } |
|
||||
StatementKind::EndRegion(_) |
|
||||
StatementKind::Validate(..) |
|
||||
StatementKind::Nop => {}
|
||||
StatementKind::StorageLive(_)
|
||||
| StatementKind::StorageDead(_)
|
||||
| StatementKind::InlineAsm { .. }
|
||||
| StatementKind::EndRegion(_)
|
||||
| StatementKind::Validate(..)
|
||||
| StatementKind::Nop => {}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -782,13 +796,13 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
|
|||
debug!("check_terminator: {:?}", term);
|
||||
let tcx = self.tcx();
|
||||
match term.kind {
|
||||
TerminatorKind::Goto { .. } |
|
||||
TerminatorKind::Resume |
|
||||
TerminatorKind::Return |
|
||||
TerminatorKind::GeneratorDrop |
|
||||
TerminatorKind::Unreachable |
|
||||
TerminatorKind::Drop { .. } |
|
||||
TerminatorKind::FalseEdges { .. } => {
|
||||
TerminatorKind::Goto { .. }
|
||||
| TerminatorKind::Resume
|
||||
| TerminatorKind::Return
|
||||
| TerminatorKind::GeneratorDrop
|
||||
| TerminatorKind::Unreachable
|
||||
| TerminatorKind::Drop { .. }
|
||||
| TerminatorKind::FalseEdges { .. } => {
|
||||
// no checks needed for these
|
||||
}
|
||||
|
||||
|
@ -888,9 +902,11 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
|
|||
// output) types in the signature must be live, since
|
||||
// all the inputs that fed into it were live.
|
||||
for &late_bound_region in map.values() {
|
||||
self.constraints
|
||||
.liveness_set
|
||||
.push((late_bound_region, term_location, Cause::LiveOther(term_location)));
|
||||
self.constraints.liveness_set.push((
|
||||
late_bound_region,
|
||||
term_location,
|
||||
Cause::LiveOther(term_location),
|
||||
));
|
||||
}
|
||||
|
||||
if self.is_box_free(func) {
|
||||
|
@ -1100,9 +1116,9 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
|
|||
}
|
||||
}
|
||||
TerminatorKind::Unreachable => {}
|
||||
TerminatorKind::Drop { target, unwind, .. } |
|
||||
TerminatorKind::DropAndReplace { target, unwind, .. } |
|
||||
TerminatorKind::Assert {
|
||||
TerminatorKind::Drop { target, unwind, .. }
|
||||
| TerminatorKind::DropAndReplace { target, unwind, .. }
|
||||
| TerminatorKind::Assert {
|
||||
target,
|
||||
cleanup: unwind,
|
||||
..
|
||||
|
@ -1358,13 +1374,13 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
|
|||
},
|
||||
|
||||
// FIXME: These other cases have to be implemented in future PRs
|
||||
Rvalue::Use(..) |
|
||||
Rvalue::Ref(..) |
|
||||
Rvalue::Len(..) |
|
||||
Rvalue::BinaryOp(..) |
|
||||
Rvalue::CheckedBinaryOp(..) |
|
||||
Rvalue::UnaryOp(..) |
|
||||
Rvalue::Discriminant(..) => {}
|
||||
Rvalue::Use(..)
|
||||
| Rvalue::Ref(..)
|
||||
| Rvalue::Len(..)
|
||||
| Rvalue::BinaryOp(..)
|
||||
| Rvalue::CheckedBinaryOp(..)
|
||||
| Rvalue::UnaryOp(..)
|
||||
| Rvalue::Discriminant(..) => {}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1498,9 +1514,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
|
|||
let cause = this.misc(this.last_span);
|
||||
let obligations = predicates
|
||||
.iter()
|
||||
.map(|&p| {
|
||||
traits::Obligation::new(cause.clone(), this.param_env, p)
|
||||
})
|
||||
.map(|&p| traits::Obligation::new(cause.clone(), this.param_env, p))
|
||||
.collect();
|
||||
Ok(InferOk {
|
||||
value: (),
|
||||
|
@ -1564,7 +1578,7 @@ impl MirPass for TypeckMir {
|
|||
}
|
||||
let param_env = tcx.param_env(def_id);
|
||||
tcx.infer_ctxt().enter(|infcx| {
|
||||
let _ = type_check_internal(&infcx, id, param_env, mir, None, &mut |_| ());
|
||||
let _ = type_check_internal(&infcx, id, param_env, mir, &[], None, &mut |_| ());
|
||||
|
||||
// For verification purposes, we just ignore the resulting
|
||||
// region constraint sets. Not our problem. =)
|
||||
|
|
56
src/test/ui/nll/ty-outlives/projection-implied-bounds.rs
Normal file
56
src/test/ui/nll/ty-outlives/projection-implied-bounds.rs
Normal file
|
@ -0,0 +1,56 @@
|
|||
// Copyright 2016 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.
|
||||
|
||||
// compile-flags:-Znll -Zborrowck=mir -Zverbose
|
||||
|
||||
// Test that we can deduce when projections like `T::Item` outlive the
|
||||
// function body. Test that this does not imply that `T: 'a` holds.
|
||||
|
||||
#![allow(warnings)]
|
||||
#![feature(rustc_attrs)]
|
||||
|
||||
use std::cell::Cell;
|
||||
|
||||
fn twice<F, T>(mut value: T, mut f: F)
|
||||
where
|
||||
F: FnMut(&T, Cell<&Option<T::Item>>),
|
||||
T: Iterator,
|
||||
{
|
||||
let mut n = value.next();
|
||||
f(&value, Cell::new(&n));
|
||||
f(&value, Cell::new(&n));
|
||||
}
|
||||
|
||||
#[rustc_errors]
|
||||
fn generic1<T: Iterator>(value: T) {
|
||||
// No error here:
|
||||
twice(value, |value_ref, item| invoke1(item));
|
||||
}
|
||||
|
||||
fn invoke1<'a, T>(x: Cell<&'a Option<T>>)
|
||||
where
|
||||
T: 'a,
|
||||
{
|
||||
}
|
||||
|
||||
#[rustc_errors]
|
||||
fn generic2<T: Iterator>(value: T) {
|
||||
twice(value, |value_ref, item| invoke2(value_ref, item));
|
||||
//~^ WARNING not reporting region error due to -Znll
|
||||
//~| ERROR `T` does not outlive
|
||||
}
|
||||
|
||||
fn invoke2<'a, T, U>(a: &T, b: Cell<&'a Option<U>>)
|
||||
where
|
||||
T: 'a,
|
||||
{
|
||||
}
|
||||
|
||||
fn main() {}
|
14
src/test/ui/nll/ty-outlives/projection-implied-bounds.stderr
Normal file
14
src/test/ui/nll/ty-outlives/projection-implied-bounds.stderr
Normal file
|
@ -0,0 +1,14 @@
|
|||
warning: not reporting region error due to -Znll
|
||||
--> $DIR/projection-implied-bounds.rs:45:36
|
||||
|
|
||||
45 | twice(value, |value_ref, item| invoke2(value_ref, item));
|
||||
| ^^^^^^^
|
||||
|
||||
error: `T` does not outlive `'_#0r`
|
||||
--> $DIR/projection-implied-bounds.rs:45:18
|
||||
|
|
||||
45 | twice(value, |value_ref, item| invoke2(value_ref, item));
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
// Copyright 2016 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.
|
||||
|
||||
// compile-flags:-Znll -Zborrowck=mir -Zverbose
|
||||
|
||||
#![allow(warnings)]
|
||||
#![feature(dyn_trait)]
|
||||
#![feature(rustc_attrs)]
|
||||
|
||||
use std::cell::Cell;
|
||||
|
||||
// Invoke in such a way that the callee knows:
|
||||
//
|
||||
// - 'a: 'x
|
||||
//
|
||||
// and it must prove that `T: 'x`. Callee passes along `T: 'a`.
|
||||
fn twice<'a, F, T>(v: Cell<&'a ()>, value: T, mut f: F)
|
||||
where
|
||||
F: for<'x> FnMut(Option<Cell<&'a &'x ()>>, &T),
|
||||
{
|
||||
f(None, &value);
|
||||
f(None, &value);
|
||||
}
|
||||
|
||||
#[rustc_regions]
|
||||
fn generic<T>(value: T) {
|
||||
let cell = Cell::new(&());
|
||||
twice(cell, value, |a, b| invoke(a, b));
|
||||
//~^ WARNING not reporting region error
|
||||
//
|
||||
// This error from the old region solver looks bogus.
|
||||
}
|
||||
|
||||
#[rustc_regions]
|
||||
fn generic_fail<'a, T>(cell: Cell<&'a ()>, value: T) {
|
||||
twice(cell, value, |a, b| invoke(a, b));
|
||||
//~^ WARNING not reporting region error
|
||||
//~| WARNING not reporting region error
|
||||
//~| ERROR `T` does not outlive
|
||||
}
|
||||
|
||||
fn invoke<'a, 'x, T>(x: Option<Cell<&'x &'a ()>>, y: &T)
|
||||
where
|
||||
T: 'x,
|
||||
{
|
||||
}
|
||||
|
||||
fn main() {}
|
|
@ -0,0 +1,85 @@
|
|||
warning: not reporting region error due to -Znll
|
||||
--> $DIR/ty-param-closure-approximate-lower-bound.rs:35:31
|
||||
|
|
||||
35 | twice(cell, value, |a, b| invoke(a, b));
|
||||
| ^^^^^^^^^^^^
|
||||
|
||||
warning: not reporting region error due to -Znll
|
||||
--> $DIR/ty-param-closure-approximate-lower-bound.rs:43:31
|
||||
|
|
||||
43 | twice(cell, value, |a, b| invoke(a, b));
|
||||
| ^^^^^^
|
||||
|
||||
warning: not reporting region error due to -Znll
|
||||
--> $DIR/ty-param-closure-approximate-lower-bound.rs:43:31
|
||||
|
|
||||
43 | twice(cell, value, |a, b| invoke(a, b));
|
||||
| ^^^^^^^^^^^^
|
||||
|
||||
note: External requirements
|
||||
--> $DIR/ty-param-closure-approximate-lower-bound.rs:35:24
|
||||
|
|
||||
35 | twice(cell, value, |a, b| invoke(a, b));
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: defining type: DefId(0/1:14 ~ ty_param_closure_approximate_lower_bound[317d]::generic[0]::{{closure}}[0]) with closure substs [
|
||||
T,
|
||||
i16,
|
||||
for<'r, 's> extern "rust-call" fn((std::option::Option<std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 'r)) ()>>, &ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 's)) T))
|
||||
]
|
||||
= note: number of external vids: 2
|
||||
= note: where T: '_#1r
|
||||
|
||||
note: External requirements
|
||||
--> $DIR/ty-param-closure-approximate-lower-bound.rs:43:24
|
||||
|
|
||||
43 | twice(cell, value, |a, b| invoke(a, b));
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: defining type: DefId(0/1:17 ~ ty_param_closure_approximate_lower_bound[317d]::generic_fail[0]::{{closure}}[0]) with closure substs [
|
||||
T,
|
||||
i16,
|
||||
for<'r, 's> extern "rust-call" fn((std::option::Option<std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 'r)) ()>>, &ReLateBound(DebruijnIndex { depth: 1 }, BrNamed(crate0:DefIndex(0:0), 's)) T))
|
||||
]
|
||||
= note: number of external vids: 2
|
||||
= note: where T: '_#1r
|
||||
|
||||
note: No external requirements
|
||||
--> $DIR/ty-param-closure-approximate-lower-bound.rs:33:1
|
||||
|
|
||||
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 | | }
|
||||
| |_^
|
||||
|
|
||||
= note: defining type: DefId(0/0:5 ~ ty_param_closure_approximate_lower_bound[317d]::generic[0]) with substs [
|
||||
T
|
||||
]
|
||||
|
||||
error: `T` does not outlive `'_#3r`
|
||||
--> $DIR/ty-param-closure-approximate-lower-bound.rs:43:24
|
||||
|
|
||||
43 | twice(cell, value, |a, b| invoke(a, b));
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
note: No external requirements
|
||||
--> $DIR/ty-param-closure-approximate-lower-bound.rs:42:1
|
||||
|
|
||||
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 `T` does not outlive
|
||||
47 | | }
|
||||
| |_^
|
||||
|
|
||||
= note: defining type: DefId(0/0:6 ~ ty_param_closure_approximate_lower_bound[317d]::generic_fail[0]) with substs [
|
||||
T
|
||||
]
|
||||
|
||||
error: aborting due to previous error
|
||||
|
42
src/test/ui/nll/ty-outlives/ty-param-implied-bounds.rs
Normal file
42
src/test/ui/nll/ty-outlives/ty-param-implied-bounds.rs
Normal file
|
@ -0,0 +1,42 @@
|
|||
// Copyright 2016 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.
|
||||
|
||||
// compile-flags:-Znll -Zborrowck=mir -Zverbose
|
||||
// must-compile-successfully
|
||||
|
||||
// Test that we assume that universal types like `T` outlive the
|
||||
// function body.
|
||||
|
||||
#![allow(warnings)]
|
||||
#![feature(rustc_attrs)]
|
||||
|
||||
use std::cell::Cell;
|
||||
|
||||
fn twice<F, T>(value: T, mut f: F)
|
||||
where
|
||||
F: FnMut(Cell<&T>),
|
||||
{
|
||||
f(Cell::new(&value));
|
||||
f(Cell::new(&value));
|
||||
}
|
||||
|
||||
#[rustc_errors]
|
||||
fn generic<T>(value: T) {
|
||||
// No error here:
|
||||
twice(value, |r| invoke(r));
|
||||
}
|
||||
|
||||
fn invoke<'a, T>(x: Cell<&'a T>)
|
||||
where
|
||||
T: 'a,
|
||||
{
|
||||
}
|
||||
|
||||
fn main() {}
|
Loading…
Add table
Add a link
Reference in a new issue