Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
int
Rust
提交
cafbd99c
R
Rust
项目概览
int
/
Rust
接近 1 年 前同步成功
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
R
Rust
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
cafbd99c
编写于
10月 30, 2017
作者:
N
Niko Matsakis
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
extend NLL regions to include free region indices and add outlives
上级
7b30e8d6
变更
7
隐藏空白更改
内联
并排
Showing
7 changed file
with
297 addition
and
113 deletion
+297
-113
src/librustc_mir/dataflow/impls/borrows.rs
src/librustc_mir/dataflow/impls/borrows.rs
+3
-3
src/librustc_mir/transform/nll/constraint_generation.rs
src/librustc_mir/transform/nll/constraint_generation.rs
+2
-2
src/librustc_mir/transform/nll/free_regions.rs
src/librustc_mir/transform/nll/free_regions.rs
+88
-0
src/librustc_mir/transform/nll/mod.rs
src/librustc_mir/transform/nll/mod.rs
+22
-8
src/librustc_mir/transform/nll/region_infer.rs
src/librustc_mir/transform/nll/region_infer.rs
+99
-72
src/librustc_mir/transform/nll/renumber.rs
src/librustc_mir/transform/nll/renumber.rs
+78
-28
src/test/compile-fail/nll/region-error.rs
src/test/compile-fail/nll/region-error.rs
+5
-0
未找到文件。
src/librustc_mir/dataflow/impls/borrows.rs
浏览文件 @
cafbd99c
...
...
@@ -38,7 +38,7 @@ pub struct Borrows<'a, 'gcx: 'tcx, 'tcx: 'a> {
location_map
:
FxHashMap
<
Location
,
BorrowIndex
>
,
region_map
:
FxHashMap
<
Region
<
'tcx
>
,
FxHashSet
<
BorrowIndex
>>
,
region_span_map
:
FxHashMap
<
RegionKind
,
Span
>
,
nonlexical_regioncx
:
Option
<&
'a
RegionInferenceContext
>
,
nonlexical_regioncx
:
Option
<&
'a
RegionInferenceContext
<
'tcx
>
>
,
}
// temporarily allow some dead fields: `kind` and `region` will be
...
...
@@ -69,7 +69,7 @@ fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result {
impl
<
'a
,
'gcx
,
'tcx
>
Borrows
<
'a
,
'gcx
,
'tcx
>
{
pub
fn
new
(
tcx
:
TyCtxt
<
'a
,
'gcx
,
'tcx
>
,
mir
:
&
'a
Mir
<
'tcx
>
,
nonlexical_regioncx
:
Option
<&
'a
RegionInferenceContext
>
)
nonlexical_regioncx
:
Option
<&
'a
RegionInferenceContext
<
'tcx
>
>
)
->
Self
{
let
mut
visitor
=
GatherBorrows
{
idx_vec
:
IndexVec
::
new
(),
location_map
:
FxHashMap
(),
...
...
@@ -140,7 +140,7 @@ fn kill_loans_out_of_scope_at_location(&self,
if
let
Some
(
regioncx
)
=
self
.nonlexical_regioncx
{
for
(
borrow_index
,
borrow_data
)
in
self
.borrows
.iter_enumerated
()
{
let
borrow_region
=
regioncx
.region_value
(
borrow_data
.region
.to_region_index
());
if
!
borrow_region
.may_contain
(
location
)
&&
location
!=
borrow_data
.location
{
if
!
borrow_region
.may_contain
_point
(
location
)
&&
location
!=
borrow_data
.location
{
debug!
(
"kill_loans_out_of_scope_at_location: kill{:?}
\
location={:?} borrow_data={:?}"
,
borrow_index
,
location
,
borrow_data
);
sets
.kill
(
&
borrow_index
);
...
...
src/librustc_mir/transform/nll/constraint_generation.rs
浏览文件 @
cafbd99c
...
...
@@ -29,7 +29,7 @@
pub
(
super
)
fn
generate_constraints
<
'a
,
'gcx
,
'tcx
>
(
infcx
:
&
InferCtxt
<
'a
,
'gcx
,
'tcx
>
,
regioncx
:
&
mut
RegionInferenceContext
,
regioncx
:
&
mut
RegionInferenceContext
<
'tcx
>
,
mir
:
&
Mir
<
'tcx
>
,
mir_source
:
MirSource
,
liveness
:
&
LivenessResults
,
...
...
@@ -45,7 +45,7 @@ pub(super) fn generate_constraints<'a, 'gcx, 'tcx>(
struct
ConstraintGeneration
<
'cx
,
'gcx
:
'tcx
,
'tcx
:
'cx
>
{
infcx
:
&
'cx
InferCtxt
<
'cx
,
'gcx
,
'tcx
>
,
regioncx
:
&
'cx
mut
RegionInferenceContext
,
regioncx
:
&
'cx
mut
RegionInferenceContext
<
'tcx
>
,
mir
:
&
'cx
Mir
<
'tcx
>
,
liveness
:
&
'cx
LivenessResults
,
mir_source
:
MirSource
,
...
...
src/librustc_mir/transform/nll/free_regions.rs
0 → 100644
浏览文件 @
cafbd99c
// 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.
//! Code to extract the free regions declared on a function and the
//! relationships between them. For example:
//!
//! ```
//! fn foo<'a, 'b, 'c: 'b>() { }
//! ```
//!
//! here we would be returning a map assigning each of `{'a, 'b, 'c}`
//! to an index, as well as the `FreeRegionMap` which can compute
//! relationships between them.
//!
//! The code in this file doesn't *do anything* with those results; it
//! just returns them for other code to use.
use
rustc
::
infer
::
InferCtxt
;
use
rustc
::
middle
::
free_region
::
FreeRegionMap
;
use
rustc
::
mir
::
transform
::
MirSource
;
use
rustc
::
ty
;
use
rustc
::
ty
::
subst
::
Substs
;
use
rustc
::
util
::
nodemap
::
FxHashMap
;
#[derive(Debug)]
pub
struct
FreeRegions
<
'tcx
>
{
/// Given a free region defined on this function (either early- or
/// late-bound), this maps it to its internal region index. The
/// corresponding variable will be "capped" so that it cannot
/// grow.
pub
indices
:
FxHashMap
<
ty
::
Region
<
'tcx
>
,
usize
>
,
/// The map from the typeck tables telling us how to relate free regions.
pub
free_region_map
:
&
'tcx
FreeRegionMap
<
'tcx
>
,
}
pub
fn
free_regions
<
'a
,
'gcx
,
'tcx
>
(
infcx
:
&
InferCtxt
<
'a
,
'gcx
,
'tcx
>
,
source
:
MirSource
,
)
->
FreeRegions
<
'tcx
>
{
debug!
(
"free_regions(source={:?})"
,
source
);
let
item_id
=
source
.item_id
();
let
item_def_id
=
infcx
.tcx.hir
.local_def_id
(
item_id
);
let
mut
indices
=
FxHashMap
();
// Extract the early regions.
let
item_substs
=
Substs
::
identity_for_item
(
infcx
.tcx
,
item_def_id
);
for
item_subst
in
item_substs
{
if
let
Some
(
region
)
=
item_subst
.as_region
()
{
insert_free_region
(
&
mut
indices
,
region
);
}
}
// Extract the late-bound regions. Use the liberated fn sigs,
// where the late-bound regions will have been converted into free
// regions, and add them to the map.
let
fn_hir_id
=
infcx
.tcx.hir
.node_to_hir_id
(
item_id
);
let
tables
=
infcx
.tcx
.typeck_tables_of
(
item_def_id
);
let
fn_sig
=
tables
.liberated_fn_sigs
()[
fn_hir_id
]
.clone
();
infcx
.tcx
.for_each_free_region
(
&
fn_sig
.inputs_and_output
,
|
region
|
{
if
let
ty
::
ReFree
(
_
)
=
*
region
{
insert_free_region
(
&
mut
indices
,
region
);
}
});
debug!
(
"free_regions: indices={:#?}"
,
indices
);
FreeRegions
{
indices
,
free_region_map
:
&
tables
.free_region_map
}
}
fn
insert_free_region
<
'tcx
>
(
free_regions
:
&
mut
FxHashMap
<
ty
::
Region
<
'tcx
>
,
usize
>
,
region
:
ty
::
Region
<
'tcx
>
,
)
{
let
len
=
free_regions
.len
();
free_regions
.entry
(
region
)
.or_insert
(
len
);
}
src/librustc_mir/transform/nll/mod.rs
浏览文件 @
cafbd99c
...
...
@@ -22,6 +22,7 @@
use
self
::
mir_util
::
PassWhere
;
mod
constraint_generation
;
mod
free_regions
;
mod
subtype
;
pub
(
crate
)
mod
region_infer
;
...
...
@@ -36,9 +37,12 @@ pub fn compute_regions<'a, 'gcx, 'tcx>(
infcx
:
&
InferCtxt
<
'a
,
'gcx
,
'tcx
>
,
source
:
MirSource
,
mir
:
&
mut
Mir
<
'tcx
>
,
)
->
RegionInferenceContext
{
)
->
RegionInferenceContext
<
'tcx
>
{
// Compute named region information.
let
free_regions
=
&
free_regions
::
free_regions
(
infcx
,
source
);
// Replace all regions with fresh inference variables.
let
num_region_variables
=
renumber
::
renumber_mir
(
infcx
,
mir
);
let
num_region_variables
=
renumber
::
renumber_mir
(
infcx
,
free_regions
,
mir
);
// Compute what is live where.
let
liveness
=
&
LivenessResults
{
...
...
@@ -61,11 +65,9 @@ pub fn compute_regions<'a, 'gcx, 'tcx>(
// Create the region inference context, generate the constraints,
// and then solve them.
let
mut
regioncx
=
RegionInferenceContext
::
new
(
num_region_variables
);
let
mut
regioncx
=
RegionInferenceContext
::
new
(
free_regions
,
num_region_variables
,
mir
);
constraint_generation
::
generate_constraints
(
infcx
,
&
mut
regioncx
,
&
mir
,
source
,
liveness
);
let
errors
=
regioncx
.solve
(
infcx
,
&
mir
);
assert
!
(
errors
.is_empty
(),
"FIXME: report region inference failures"
);
regioncx
.solve
(
infcx
,
&
mir
);
// Dump MIR results into a file, if that is enabled. This let us
// write unit-tests.
...
...
@@ -152,11 +154,15 @@ fn dump_mir_results<'a, 'gcx, 'tcx>(
#[derive(Clone,
Default,
PartialEq,
Eq)]
pub
struct
Region
{
points
:
BTreeSet
<
Location
>
,
free_regions
:
BTreeSet
<
RegionIndex
>
,
}
impl
fmt
::
Debug
for
Region
{
fn
fmt
(
&
self
,
formatter
:
&
mut
fmt
::
Formatter
)
->
Result
<
(),
fmt
::
Error
>
{
write!
(
formatter
,
"{:?}"
,
self
.points
)
formatter
.debug_set
()
.entries
(
&
self
.points
)
.entries
(
&
self
.free_regions
)
.finish
()
}
}
...
...
@@ -165,9 +171,17 @@ pub fn add_point(&mut self, point: Location) -> bool {
self
.points
.insert
(
point
)
}
pub
fn
may_contain
(
&
self
,
point
:
Location
)
->
bool
{
pub
fn
add_free_region
(
&
mut
self
,
region
:
RegionIndex
)
->
bool
{
self
.free_regions
.insert
(
region
)
}
pub
fn
may_contain_point
(
&
self
,
point
:
Location
)
->
bool
{
self
.points
.contains
(
&
point
)
}
pub
fn
may_contain_free_region
(
&
self
,
region
:
RegionIndex
)
->
bool
{
self
.free_regions
.contains
(
&
region
)
}
}
newtype_index!
(
RegionIndex
{
...
...
src/librustc_mir/transform/nll/region_infer.rs
浏览文件 @
cafbd99c
...
...
@@ -9,37 +9,49 @@
// except according to those terms.
use
super
::{
Region
,
RegionIndex
};
use
s
td
::
mem
;
use
s
uper
::
free_regions
::
FreeRegions
;
use
rustc
::
infer
::
InferCtxt
;
use
rustc
::
mir
::{
Location
,
Mir
};
use
rustc_data_structures
::
indexed_vec
::
IndexVec
;
use
rustc
::
ty
;
use
rustc_data_structures
::
indexed_vec
::{
Idx
,
IndexVec
};
use
rustc_data_structures
::
fx
::
FxHashSet
;
pub
struct
RegionInferenceContext
{
pub
struct
RegionInferenceContext
<
'tcx
>
{
/// Contains the definition for every region variable. Region
/// variables are identified by their index (`RegionIndex`). The
/// definition contains information about where the region came
/// from as well as its final inferred value.
definitions
:
IndexVec
<
RegionIndex
,
RegionDefinition
>
,
definitions
:
IndexVec
<
RegionIndex
,
RegionDefinition
<
'tcx
>>
,
/// The indices of all "free regions" in scope. These are the
/// lifetime parameters (anonymous and named) declared in the
/// function signature:
///
/// fn foo<'a, 'b>(x: &Foo<'a, 'b>)
/// ^^ ^^ ^
///
/// These indices will be from 0..N, as it happens, but we collect
/// them into a vector for convenience.
free_regions
:
Vec
<
RegionIndex
>
,
/// The constraints we have accumulated and used during solving.
constraints
:
Vec
<
Constraint
>
,
/// List of errors we have accumulated as we add constraints.
/// After solving is done, this is replaced with an empty vector.
errors
:
Vec
<
InferenceError
>
,
}
pub
struct
InferenceError
{
pub
constraint_point
:
Location
,
pub
name
:
(),
// FIXME(nashenas88) RegionName
}
#[derive(Default)]
struct
RegionDefinition
{
name
:
(),
// FIXME(nashenas88) RegionName
struct
RegionDefinition
<
'tcx
>
{
/// If this is a free-region, then this is `Some(X)` where `X` is
/// the name of the region.
name
:
Option
<
ty
::
Region
<
'tcx
>>
,
/// If true, this is a constant region which cannot grow larger.
/// This is used for named regions as well as `'static`.
constant
:
bool
,
/// The current value of this inference variable. This starts out
/// empty, but grows as we add constraints. The final value is
/// determined when `solve()` is executed.
value
:
Region
,
capped
:
bool
,
}
#[derive(Copy,
Clone,
Debug,
PartialEq,
Eq,
Hash)]
...
...
@@ -49,14 +61,73 @@ pub struct Constraint {
point
:
Location
,
}
impl
RegionInferenceContext
{
pub
fn
new
(
num_region_variables
:
usize
)
->
Self
{
Self
{
impl
<
'tcx
>
RegionInferenceContext
<
'tcx
>
{
/// Creates a new region inference context with a total of
/// `num_region_variables` valid inference variables; the first N
/// of those will be constant regions representing the free
/// regions defined in `free_regions`.
pub
fn
new
(
free_regions
:
&
FreeRegions
<
'tcx
>
,
num_region_variables
:
usize
,
mir
:
&
Mir
<
'tcx
>
)
->
Self
{
let
mut
result
=
Self
{
definitions
:
(
0
..
num_region_variables
)
.map
(|
_
|
RegionDefinition
::
default
())
.collect
(),
constraints
:
Vec
::
new
(),
errors
:
Vec
::
new
(),
free_regions
:
Vec
::
new
(),
};
result
.init_free_regions
(
free_regions
,
mir
);
result
}
fn
init_free_regions
(
&
mut
self
,
free_regions
:
&
FreeRegions
<
'tcx
>
,
mir
:
&
Mir
<
'tcx
>
)
{
let
&
FreeRegions
{
ref
indices
,
ref
free_region_map
}
=
free_regions
;
// For each free region variable X, it should contain:
//
// (a) the entire CFG
// (b) `end(Y)` for all regions Y such that X: Y (or Y <= X)
//
// we add however the regions for clause (b) somewhat in
// reverse, because of how the data structure in
// `free_regions` is organized.
for
(
free_region
,
index
)
in
indices
{
let
variable
=
RegionIndex
::
new
(
*
index
);
self
.free_regions
.push
(
variable
);
self
.definitions
[
variable
]
.name
=
Some
(
free_region
);
self
.definitions
[
variable
]
.constant
=
true
;
// Add all nodes in the CFG to `definition.value`.
for
(
block
,
block_data
)
in
mir
.basic_blocks
()
.iter_enumerated
()
{
let
definition
=
&
mut
self
.definitions
[
variable
];
for
statement_index
in
0
..
block_data
.statements
.len
()
+
1
{
let
location
=
Location
{
block
,
statement_index
};
definition
.value
.add_point
(
location
);
}
}
// Add `end(X)` into the set for X.
self
.definitions
[
variable
]
.value
.add_free_region
(
variable
);
// Go through each region Y that outlives X (i.e., where
// Y: X is true). Add `end(X)` into the set for `Y`.
for
superregion
in
free_region_map
.regions_that_outlive
(
&
free_region
)
{
let
superregion_index
=
RegionIndex
::
new
(
indices
[
superregion
]);
self
.definitions
[
superregion_index
]
.value
.add_free_region
(
variable
);
}
debug!
(
"init_free_regions: region variable for `{:?}` is `{:?}` with value `{:?}`"
,
free_region
,
variable
,
self
.definitions
[
variable
]
.value
);
}
}
...
...
@@ -72,42 +143,25 @@ pub fn region_value(&self, r: RegionIndex) -> &Region {
&
self
.definitions
[
r
]
.value
}
/// Flags a region as being "capped" -- this means that if its
/// value is required to grow as a result of some constraint
/// (e.g., `add_live_point` or `add_outlives`), that indicates an
/// error. This is used for the regions representing named
/// lifetime parameters on a function: they get initialized to
/// their complete value, and then "capped" so that they can no
/// longer grow.
#[allow(dead_code)]
pub
(
super
)
fn
cap_var
(
&
mut
self
,
v
:
RegionIndex
)
{
self
.definitions
[
v
]
.capped
=
true
;
}
/// Indicates that the region variable `v` is live at the point `point`.
pub
(
super
)
fn
add_live_point
(
&
mut
self
,
v
:
RegionIndex
,
point
:
Location
)
{
debug!
(
"add_live_point({:?}, {:?})"
,
v
,
point
);
let
definition
=
&
mut
self
.definitions
[
v
];
if
definition
.value
.add_point
(
point
)
{
if
definition
.capped
{
self
.errors
.push
(
InferenceError
{
constraint_point
:
point
,
name
:
definition
.name
,
});
}
}
definition
.value
.add_point
(
point
);
}
/// Indicates that the region variable `sup` must outlive `sub` is live at the point `point`.
pub
(
super
)
fn
add_outlives
(
&
mut
self
,
sup
:
RegionIndex
,
sub
:
RegionIndex
,
point
:
Location
)
{
debug!
(
"add_outlives({:?}: {:?} @ {:?}"
,
sup
,
sub
,
point
);
self
.constraints
.push
(
Constraint
{
sup
,
sub
,
point
});
}
/// Perform region inference.
pub
(
super
)
fn
solve
<
'a
,
'gcx
,
'tcx
>
(
pub
(
super
)
fn
solve
<
'a
,
'gcx
>
(
&
mut
self
,
infcx
:
&
'a
InferCtxt
<
'a
,
'gcx
,
'tcx
>
,
mir
:
&
'a
Mir
<
'tcx
>
,
)
->
Vec
<
InferenceError
>
)
where
'gcx
:
'tcx
+
'a
,
'tcx
:
'a
,
...
...
@@ -125,23 +179,6 @@ pub(super) fn solve<'a, 'gcx, 'tcx>(
if
dfs
.copy
(
sub
,
&
mut
sup_def
.value
,
constraint
.point
)
{
changed
=
true
;
if
sup_def
.capped
{
// This is kind of a hack, but when we add a
// constraint, the "point" is always the point
// AFTER the action that induced the
// constraint. So report the error on the
// action BEFORE that.
assert
!
(
constraint
.point.statement_index
>
0
);
let
p
=
Location
{
block
:
constraint
.point.block
,
statement_index
:
constraint
.point.statement_index
-
1
,
};
self
.errors
.push
(
InferenceError
{
constraint_point
:
p
,
name
:
sup_def
.name
,
});
}
}
debug!
(
" sup (after) : {:?}"
,
sup_def
.value
);
...
...
@@ -149,8 +186,6 @@ pub(super) fn solve<'a, 'gcx, 'tcx>(
}
debug!
(
"
\n
"
);
}
mem
::
replace
(
&
mut
self
.errors
,
Vec
::
new
())
}
}
...
...
@@ -179,7 +214,7 @@ fn copy(
while
let
Some
(
p
)
=
stack
.pop
()
{
debug!
(
" dfs: p={:?}"
,
p
);
if
!
from_region
.may_contain
(
p
)
{
if
!
from_region
.may_contain
_point
(
p
)
{
debug!
(
" not in from-region"
);
continue
;
}
...
...
@@ -214,19 +249,11 @@ fn copy(
};
if
successor_points
.is_empty
()
{
// FIXME handle free regions
// If we reach the END point in the graph, then copy
// over any skolemized end points in the `from_region`
// and make sure they are included in the `to_region`.
// for region_decl in self.infcx.tcx.tables.borrow().free_region_map() {
// // FIXME(nashenas88) figure out skolemized_end points
// let block = self.env.graph.skolemized_end(region_decl.name);
// let skolemized_end_point = Location {
// block,
// statement_index: 0,
// };
// changed |= to_region.add_point(skolemized_end_point);
// }
to_region
.free_regions
.extend
(
&
from_region
.free_regions
);
}
else
{
stack
.extend
(
successor_points
);
}
...
...
src/librustc_mir/transform/nll/renumber.rs
浏览文件 @
cafbd99c
...
...
@@ -8,22 +8,40 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use
rustc
::
ty
::
TypeFoldable
;
use
rustc
_data_structures
::
indexed_vec
::
Idx
;
use
rustc
::
ty
::
subst
::{
Kind
,
Substs
};
use
rustc
::
ty
::{
Ty
,
ClosureSubsts
,
RegionVid
,
RegionKind
};
use
rustc
::
mir
::{
Mir
,
Location
,
Rvalue
,
BasicBlock
,
Statement
,
StatementKind
};
use
rustc
::
ty
::{
self
,
ClosureSubsts
,
RegionKind
,
RegionVid
,
Ty
,
TypeFoldable
};
use
rustc
::
mir
::{
BasicBlock
,
Local
,
Location
,
Mir
,
Rvalue
,
Statement
,
StatementKind
};
use
rustc
::
mir
::
visit
::{
MutVisitor
,
TyContext
};
use
rustc
::
infer
::{
self
as
rustc_infer
,
InferCtxt
};
use
syntax_pos
::
DUMMY_SP
;
use
std
::
collections
::
HashMap
;
use
super
::
free_regions
::
FreeRegions
;
/// Replaces all free regions appearing in the MIR with fresh
/// inference variables, returning the number of variables created.
pub
fn
renumber_mir
<
'a
,
'gcx
,
'tcx
>
(
infcx
:
&
InferCtxt
<
'a
,
'gcx
,
'tcx
>
,
mir
:
&
mut
Mir
<
'tcx
>
)
->
usize
{
let
mut
visitor
=
NLLVisitor
::
new
(
infcx
);
pub
fn
renumber_mir
<
'a
,
'gcx
,
'tcx
>
(
infcx
:
&
InferCtxt
<
'a
,
'gcx
,
'tcx
>
,
free_regions
:
&
FreeRegions
<
'tcx
>
,
mir
:
&
mut
Mir
<
'tcx
>
,
)
->
usize
{
// Create inference variables for each of the free regions
// declared on the function signature.
let
free_region_inference_vars
=
(
0
..
free_regions
.indices
.len
())
.map
(|
_
|
{
infcx
.next_region_var
(
rustc_infer
::
MiscVariable
(
DUMMY_SP
))
})
.collect
();
let
mut
visitor
=
NLLVisitor
{
infcx
,
lookup_map
:
HashMap
::
new
(),
num_region_variables
:
free_regions
.indices
.len
(),
free_regions
,
free_region_inference_vars
,
arg_count
:
mir
.arg_count
,
};
visitor
.visit_mir
(
mir
);
visitor
.num_region_variables
}
...
...
@@ -32,22 +50,40 @@ struct NLLVisitor<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
lookup_map
:
HashMap
<
RegionVid
,
TyContext
>
,
num_region_variables
:
usize
,
infcx
:
&
'a
InferCtxt
<
'a
,
'gcx
,
'tcx
>
,
free_regions
:
&
'a
FreeRegions
<
'tcx
>
,
free_region_inference_vars
:
Vec
<
ty
::
Region
<
'tcx
>>
,
arg_count
:
usize
,
}
impl
<
'a
,
'gcx
,
'tcx
>
NLLVisitor
<
'a
,
'gcx
,
'tcx
>
{
pub
fn
new
(
infcx
:
&
'a
InferCtxt
<
'a
,
'gcx
,
'tcx
>
)
->
Self
{
NLLVisitor
{
infcx
,
lookup_map
:
HashMap
::
new
(),
num_region_variables
:
0
}
/// Replaces all regions appearing in `value` with fresh inference
/// variables. This is what we do for almost the entire MIR, with
/// the exception of the declared types of our arguments.
fn
renumber_regions
<
T
>
(
&
mut
self
,
value
:
&
T
)
->
T
where
T
:
TypeFoldable
<
'tcx
>
,
{
self
.infcx
.tcx
.fold_regions
(
value
,
&
mut
false
,
|
_
region
,
_
depth
|
{
self
.num_region_variables
+=
1
;
self
.infcx
.next_region_var
(
rustc_infer
::
MiscVariable
(
DUMMY_SP
))
})
}
fn
renumber_regions
<
T
>
(
&
mut
self
,
value
:
&
T
)
->
T
where
T
:
TypeFoldable
<
'tcx
>
{
self
.infcx.tcx
.fold_regions
(
value
,
&
mut
false
,
|
_
region
,
_
depth
|
{
self
.num_region_variables
+=
1
;
self
.infcx
.next_region_var
(
rustc_infer
::
MiscVariable
(
DUMMY_SP
))
})
/// Renumbers the regions appearing in `value`, but those regions
/// are expected to be free regions from the function signature.
fn
renumber_free_regions
<
T
>
(
&
mut
self
,
value
:
&
T
)
->
T
where
T
:
TypeFoldable
<
'tcx
>
,
{
self
.infcx
.tcx
.fold_regions
(
value
,
&
mut
false
,
|
region
,
_
depth
|
{
let
index
=
self
.free_regions.indices
[
&
region
];
self
.free_region_inference_vars
[
index
]
})
}
fn
store_region
(
&
mut
self
,
region
:
&
RegionKind
,
lookup
:
TyContext
)
{
...
...
@@ -69,17 +105,31 @@ fn store_kind_regions(&mut self, kind: &'tcx Kind, ty_context: TyContext) {
self
.store_region
(
region
,
ty_context
);
}
}
fn
is_argument_or_return_slot
(
&
self
,
local
:
Local
)
->
bool
{
// The first argument is return slot, next N are arguments.
local
.index
()
<=
self
.arg_count
}
}
impl
<
'a
,
'gcx
,
'tcx
>
MutVisitor
<
'tcx
>
for
NLLVisitor
<
'a
,
'gcx
,
'tcx
>
{
fn
visit_ty
(
&
mut
self
,
ty
:
&
mut
Ty
<
'tcx
>
,
ty_context
:
TyContext
)
{
let
is_arg
=
match
ty_context
{
TyContext
::
LocalDecl
{
local
,
..
}
=>
self
.is_argument_or_return_slot
(
local
),
_
=>
false
,
};
let
old_ty
=
*
ty
;
*
ty
=
self
.renumber_regions
(
&
old_ty
);
*
ty
=
if
is_arg
{
self
.renumber_free_regions
(
&
old_ty
)
}
else
{
self
.renumber_regions
(
&
old_ty
)
};
self
.store_ty_regions
(
ty
,
ty_context
);
}
fn
visit_substs
(
&
mut
self
,
substs
:
&
mut
&
'tcx
Substs
<
'tcx
>
,
location
:
Location
)
{
*
substs
=
self
.renumber_regions
(
&
{
*
substs
});
*
substs
=
self
.renumber_regions
(
&
{
*
substs
});
let
ty_context
=
TyContext
::
Location
(
location
);
for
kind
in
*
substs
{
self
.store_kind_regions
(
kind
,
ty_context
);
...
...
@@ -110,9 +160,7 @@ fn visit_rvalue(&mut self, rvalue: &mut Rvalue<'tcx>, location: Location) {
self
.super_rvalue
(
rvalue
,
location
);
}
fn
visit_closure_substs
(
&
mut
self
,
substs
:
&
mut
ClosureSubsts
<
'tcx
>
,
location
:
Location
)
{
fn
visit_closure_substs
(
&
mut
self
,
substs
:
&
mut
ClosureSubsts
<
'tcx
>
,
location
:
Location
)
{
*
substs
=
self
.renumber_regions
(
substs
);
let
ty_context
=
TyContext
::
Location
(
location
);
for
kind
in
substs
.substs
{
...
...
@@ -120,10 +168,12 @@ fn visit_closure_substs(&mut self,
}
}
fn
visit_statement
(
&
mut
self
,
block
:
BasicBlock
,
statement
:
&
mut
Statement
<
'tcx
>
,
location
:
Location
)
{
fn
visit_statement
(
&
mut
self
,
block
:
BasicBlock
,
statement
:
&
mut
Statement
<
'tcx
>
,
location
:
Location
,
)
{
if
let
StatementKind
::
EndRegion
(
_
)
=
statement
.kind
{
statement
.kind
=
StatementKind
::
Nop
;
}
...
...
src/test/compile-fail/nll/region-error.rs
0 → 100644
浏览文件 @
cafbd99c
fn
foo
<
'a
,
'b
>
(
x
:
&
'a
u32
,
y
:
&
'b
u32
)
->
&
'b
u32
{
&*
x
}
fn
main
()
{
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录