Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
int
Rust
提交
ab1c1bc6
R
Rust
项目概览
int
/
Rust
11 个月 前同步成功
通知
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,发现更多精彩内容 >>
提交
ab1c1bc6
编写于
11月 22, 2017
作者:
N
Niko Matsakis
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
mir-borrowck returns closure requirements, mir-typeck enforces
上级
2ec959fc
变更
14
展开全部
隐藏空白更改
内联
并排
Showing
14 changed file
with
1121 addition
and
184 deletion
+1121
-184
src/librustc/ich/impls_mir.rs
src/librustc/ich/impls_mir.rs
+12
-0
src/librustc/ich/impls_ty.rs
src/librustc/ich/impls_ty.rs
+10
-0
src/librustc/infer/mod.rs
src/librustc/infer/mod.rs
+5
-0
src/librustc/mir/mod.rs
src/librustc/mir/mod.rs
+69
-0
src/librustc/ty/maps/mod.rs
src/librustc/ty/maps/mod.rs
+4
-2
src/librustc/ty/sty.rs
src/librustc/ty/sty.rs
+40
-0
src/librustc_driver/driver.rs
src/librustc_driver/driver.rs
+1
-1
src/librustc_mir/borrow_check/mod.rs
src/librustc_mir/borrow_check/mod.rs
+19
-10
src/librustc_mir/borrow_check/nll/mod.rs
src/librustc_mir/borrow_check/nll/mod.rs
+15
-16
src/librustc_mir/borrow_check/nll/region_infer/mod.rs
src/librustc_mir/borrow_check/nll/region_infer/mod.rs
+235
-66
src/librustc_mir/borrow_check/nll/renumber.rs
src/librustc_mir/borrow_check/nll/renumber.rs
+28
-33
src/librustc_mir/borrow_check/nll/subtype_constraint_generation.rs
...stc_mir/borrow_check/nll/subtype_constraint_generation.rs
+1
-8
src/librustc_mir/borrow_check/nll/universal_regions.rs
src/librustc_mir/borrow_check/nll/universal_regions.rs
+648
-46
src/librustc_mir/transform/type_check.rs
src/librustc_mir/transform/type_check.rs
+34
-2
未找到文件。
src/librustc/ich/impls_mir.rs
浏览文件 @
ab1c1bc6
...
...
@@ -572,3 +572,15 @@ fn hash_stable<W: StableHasherResult>(&self,
}
impl_stable_hash_for!
(
struct
mir
::
Location
{
block
,
statement_index
});
impl_stable_hash_for!
(
struct
mir
::
ClosureRegionRequirements
{
num_external_vids
,
outlives_requirements
});
impl_stable_hash_for!
(
struct
mir
::
ClosureOutlivesRequirement
{
free_region
,
outlived_free_region
,
blame_span
});
src/librustc/ich/impls_ty.rs
浏览文件 @
ab1c1bc6
...
...
@@ -84,6 +84,16 @@ fn hash_stable<W: StableHasherResult>(&self,
}
}
impl
<
'gcx
>
HashStable
<
StableHashingContext
<
'gcx
>>
for
ty
::
RegionVid
{
#[inline]
fn
hash_stable
<
W
:
StableHasherResult
>
(
&
self
,
hcx
:
&
mut
StableHashingContext
<
'gcx
>
,
hasher
:
&
mut
StableHasher
<
W
>
)
{
use
rustc_data_structures
::
indexed_vec
::
Idx
;
self
.index
()
.hash_stable
(
hcx
,
hasher
);
}
}
impl
<
'gcx
>
HashStable
<
StableHashingContext
<
'gcx
>>
for
ty
::
adjustment
::
AutoBorrow
<
'gcx
>
{
fn
hash_stable
<
W
:
StableHasherResult
>
(
&
self
,
...
...
src/librustc/infer/mod.rs
浏览文件 @
ab1c1bc6
...
...
@@ -1062,6 +1062,11 @@ pub fn next_region_var(&self, origin: RegionVariableOrigin)
self
.tcx
.mk_region
(
ty
::
ReVar
(
self
.borrow_region_constraints
()
.new_region_var
(
origin
)))
}
/// Number of region variables created so far.
pub
fn
num_region_vars
(
&
self
)
->
usize
{
self
.borrow_region_constraints
()
.var_origins
()
.len
()
}
/// Just a convenient wrapper of `next_region_var` for using during NLL.
pub
fn
next_nll_region_var
(
&
self
,
origin
:
NLLRegionVariableOrigin
)
->
ty
::
Region
<
'tcx
>
{
...
...
src/librustc/mir/mod.rs
浏览文件 @
ab1c1bc6
...
...
@@ -1789,6 +1789,75 @@ pub struct GeneratorLayout<'tcx> {
pub
fields
:
Vec
<
LocalDecl
<
'tcx
>>
,
}
/// After we borrow check a closure, we are left with various
/// requirements that we have inferred between the free regions that
/// appear in the closure's signature or on its field types. These
/// requirements are then verified and proved by the closure's
/// creating function. This struct encodes those requirements.
///
/// The requirements are listed as being between various
/// `RegionVid`. The 0th region refers to `'static`; subsequent region
/// vids refer to the free regions that appear in the closure (or
/// generator's) type, in order of appearance. (This numbering is
/// actually defined by the `UniversalRegions` struct in the NLL
/// region checker. See for example
/// `UniversalRegions::closure_mapping`.) Note that we treat the free
/// regions in the closure's type "as if" they were erased, so their
/// precise identity is not important, only their position.
///
/// Example: If type check produces a closure with the closure substs:
///
/// ```
/// ClosureSubsts = [
/// i8, // the "closure kind"
/// for<'x> fn(&'a &'x u32) -> &'x u32, // the "closure signature"
/// &'a String, // some upvar
/// ]
/// ```
///
/// here, there is one unique free region (`'a`) but it appears
/// twice. We would "renumber" each occurence to a unique vid, as follows:
///
/// ```
/// ClosureSubsts = [
/// i8, // the "closure kind"
/// for<'x> fn(&'1 &'x u32) -> &'x u32, // the "closure signature"
/// &'2 String, // some upvar
/// ]
/// ```
///
/// Now the code might impose a requirement like `'1: '2`. When an
/// instance of the closure is created, the corresponding free regions
/// can be extracted from its type and constrained to have the given
/// outlives relationship.
#[derive(Clone,
Debug)]
pub
struct
ClosureRegionRequirements
{
/// The number of external regions defined on the closure. In our
/// example above, it would be 3 -- one for `'static`, then `'1`
/// and `'2`. This is just used for a sanity check later on, to
/// make sure that the number of regions we see at the callsite
/// matches.
pub
num_external_vids
:
usize
,
/// Requirements between the various free regions defined in
/// indices.
pub
outlives_requirements
:
Vec
<
ClosureOutlivesRequirement
>
,
}
/// Indicates an outlives constraint between two free-regions declared
/// on the closure.
#[derive(Copy,
Clone,
Debug,
PartialEq,
Eq,
PartialOrd,
Ord,
Hash)]
pub
struct
ClosureOutlivesRequirement
{
// This region ...
pub
free_region
:
ty
::
RegionVid
,
// .. must outlive this one.
pub
outlived_free_region
:
ty
::
RegionVid
,
// If not, report an error here.
pub
blame_span
:
Span
,
}
/*
* TypeFoldable implementations for MIR types
*/
...
...
src/librustc/ty/maps/mod.rs
浏览文件 @
ab1c1bc6
...
...
@@ -190,8 +190,10 @@
[]
fn
coherent_trait
:
coherent_trait_dep_node
((
CrateNum
,
DefId
))
->
(),
[]
fn
borrowck
:
BorrowCheck
(
DefId
)
->
Rc
<
BorrowCheckResult
>
,
// FIXME: shouldn't this return a `Result<(), BorrowckErrors>` instead?
[]
fn
mir_borrowck
:
MirBorrowCheck
(
DefId
)
->
(),
/// Borrow checks the function body. If this is a closure, returns
/// additional requirements that the closure's creator must verify.
[]
fn
mir_borrowck
:
MirBorrowCheck
(
DefId
)
->
Option
<
mir
::
ClosureRegionRequirements
>
,
/// Gets a complete map from all types to their inherent impls.
/// Not meant to be used directly outside of coherence.
...
...
src/librustc/ty/sty.rs
浏览文件 @
ab1c1bc6
...
...
@@ -646,6 +646,17 @@ pub fn input_types<'a>(&'a self) -> impl DoubleEndedIterator<Item=Ty<'tcx>> + 'a
pub
struct
Binder
<
T
>
(
pub
T
);
impl
<
T
>
Binder
<
T
>
{
/// Wraps `value` in a binder, asserting that `value` does not
/// contain any bound regions that would be bound by the
/// binder. This is commonly used to 'inject' a value T into a
/// different binding level.
pub
fn
new_not_binding
<
'tcx
>
(
value
:
T
)
->
Binder
<
T
>
where
T
:
TypeFoldable
<
'tcx
>
{
assert
!
(
!
value
.has_escaping_regions
());
Binder
(
value
)
}
/// Skips the binder and returns the "bound" value. This is a
/// risky thing to do because it's easy to get confused about
/// debruijn indices and the like. It is usually better to
...
...
@@ -700,6 +711,32 @@ pub fn no_late_bound_regions<'tcx>(self) -> Option<T>
Some
(
self
.skip_binder
()
.clone
())
}
}
/// Given two things that have the same binder level,
/// and an operation that wraps on their contents, execute the operation
/// and then wrap its result.
///
/// `f` should consider bound regions at depth 1 to be free, and
/// anything it produces with bound regions at depth 1 will be
/// bound in the resulting return value.
pub
fn
fuse
<
U
,
F
,
R
>
(
self
,
u
:
Binder
<
U
>
,
f
:
F
)
->
Binder
<
R
>
where
F
:
FnOnce
(
T
,
U
)
->
R
{
ty
::
Binder
(
f
(
self
.0
,
u
.0
))
}
/// Split the contents into two things that share the same binder
/// level as the original, returning two distinct binders.
///
/// `f` should consider bound regions at depth 1 to be free, and
/// anything it produces with bound regions at depth 1 will be
/// bound in the resulting return values.
pub
fn
split
<
U
,
V
,
F
>
(
self
,
f
:
F
)
->
(
Binder
<
U
>
,
Binder
<
V
>
)
where
F
:
FnOnce
(
T
)
->
(
U
,
V
)
{
let
(
u
,
v
)
=
f
(
self
.0
);
(
ty
::
Binder
(
u
),
ty
::
Binder
(
v
))
}
}
/// Represents the projection of an associated type. In explicit UFCS
...
...
@@ -799,6 +836,9 @@ pub fn inputs(&self) -> Binder<&'tcx [Ty<'tcx>]> {
pub
fn
input
(
&
self
,
index
:
usize
)
->
ty
::
Binder
<
Ty
<
'tcx
>>
{
self
.map_bound_ref
(|
fn_sig
|
fn_sig
.inputs
()[
index
])
}
pub
fn
inputs_and_output
(
&
self
)
->
ty
::
Binder
<&
'tcx
Slice
<
Ty
<
'tcx
>>>
{
self
.map_bound_ref
(|
fn_sig
|
fn_sig
.inputs_and_output
)
}
pub
fn
output
(
&
self
)
->
ty
::
Binder
<
Ty
<
'tcx
>>
{
self
.map_bound_ref
(|
fn_sig
|
fn_sig
.output
()
.clone
())
}
...
...
src/librustc_driver/driver.rs
浏览文件 @
ab1c1bc6
...
...
@@ -1069,7 +1069,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(control: &CompileController,
time
(
time_passes
,
"MIR borrow checking"
,
||
for
def_id
in
tcx
.body_owners
()
{
tcx
.mir_borrowck
(
def_id
)
});
||
for
def_id
in
tcx
.body_owners
()
{
tcx
.mir_borrowck
(
def_id
)
;
});
time
(
time_passes
,
"MIR effect checking"
,
...
...
src/librustc_mir/borrow_check/mod.rs
浏览文件 @
ab1c1bc6
...
...
@@ -19,6 +19,7 @@
use
rustc
::
mir
::{
AssertMessage
,
BasicBlock
,
BorrowKind
,
Local
,
Location
,
Place
};
use
rustc
::
mir
::{
Mir
,
Mutability
,
Operand
,
Projection
,
ProjectionElem
,
Rvalue
};
use
rustc
::
mir
::{
Field
,
Statement
,
StatementKind
,
Terminator
,
TerminatorKind
};
use
rustc
::
mir
::
ClosureRegionRequirements
;
use
rustc_data_structures
::
fx
::
FxHashSet
;
use
rustc_data_structures
::
indexed_set
::{
self
,
IdxSetBuf
};
...
...
@@ -51,7 +52,10 @@ pub fn provide(providers: &mut Providers) {
};
}
fn
mir_borrowck
<
'a
,
'tcx
>
(
tcx
:
TyCtxt
<
'a
,
'tcx
,
'tcx
>
,
def_id
:
DefId
)
{
fn
mir_borrowck
<
'a
,
'tcx
>
(
tcx
:
TyCtxt
<
'a
,
'tcx
,
'tcx
>
,
def_id
:
DefId
,
)
->
Option
<
ClosureRegionRequirements
>
{
let
input_mir
=
tcx
.mir_validated
(
def_id
);
debug!
(
"run query mir_borrowck: {}"
,
tcx
.item_path_str
(
def_id
));
...
...
@@ -59,21 +63,23 @@ fn mir_borrowck<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) {
!
tcx
.has_attr
(
def_id
,
"rustc_mir_borrowck"
)
&&
!
tcx
.sess.opts.borrowck_mode
.use_mir
()
&&
!
tcx
.sess.opts.debugging_opts.nll
}
{
return
;
return
None
;
}
tcx
.infer_ctxt
()
.enter
(|
infcx
|
{
let
opt_closure_req
=
tcx
.infer_ctxt
()
.enter
(|
infcx
|
{
let
input_mir
:
&
Mir
=
&
input_mir
.borrow
();
do_mir_borrowck
(
&
infcx
,
input_mir
,
def_id
)
;
do_mir_borrowck
(
&
infcx
,
input_mir
,
def_id
)
});
debug!
(
"mir_borrowck done"
);
opt_closure_req
}
fn
do_mir_borrowck
<
'a
,
'gcx
,
'tcx
>
(
infcx
:
&
InferCtxt
<
'a
,
'gcx
,
'tcx
>
,
input_mir
:
&
Mir
<
'gcx
>
,
def_id
:
DefId
,
)
{
)
->
Option
<
ClosureRegionRequirements
>
{
let
tcx
=
infcx
.tcx
;
let
attributes
=
tcx
.get_attrs
(
def_id
);
let
param_env
=
tcx
.param_env
(
def_id
);
...
...
@@ -91,7 +97,7 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
let
mir
=
&
mut
mir
;
// Replace all regions with fresh inference variables.
Some
(
nll
::
replace_regions_in_mir
(
infcx
,
def_id
,
mir
))
Some
(
nll
::
replace_regions_in_mir
(
infcx
,
def_id
,
param_env
,
mir
))
};
let
mir
=
&
mir
;
...
...
@@ -177,8 +183,8 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
));
// If we are in non-lexical mode, compute the non-lexical lifetimes.
let
opt_regioncx
=
if
let
Some
(
free_regions
)
=
free_regions
{
Some
(
nll
::
compute_regions
(
let
(
opt_regioncx
,
opt_closure_req
)
=
if
let
Some
(
free_regions
)
=
free_regions
{
let
(
regioncx
,
opt_closure_req
)
=
nll
::
compute_regions
(
infcx
,
def_id
,
free_regions
,
...
...
@@ -186,10 +192,11 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
param_env
,
&
mut
flow_inits
,
&
mdpe
.move_data
,
))
);
(
Some
(
regioncx
),
opt_closure_req
)
}
else
{
assert
!
(
!
tcx
.sess.opts.debugging_opts.nll
);
None
(
None
,
None
)
};
let
flow_inits
=
flow_inits
;
// remove mut
...
...
@@ -226,6 +233,8 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
);
mbcx
.analyze_results
(
&
mut
state
);
// entry point for DataflowResultsConsumer
opt_closure_req
}
#[allow(dead_code)]
...
...
src/librustc_mir/borrow_check/nll/mod.rs
浏览文件 @
ab1c1bc6
...
...
@@ -9,7 +9,7 @@
// except according to those terms.
use
rustc
::
hir
::
def_id
::
DefId
;
use
rustc
::
mir
::
Mir
;
use
rustc
::
mir
::
{
ClosureRegionRequirements
,
Mir
}
;
use
rustc
::
infer
::
InferCtxt
;
use
rustc
::
ty
::{
self
,
RegionKind
,
RegionVid
};
use
rustc
::
util
::
nodemap
::
FxHashMap
;
...
...
@@ -35,20 +35,21 @@
mod
renumber
;
/// Rewrites the regions in the MIR to use NLL variables, also
/// scraping out the set of
free
regions (e.g., region parameters)
/// scraping out the set of
universal
regions (e.g., region parameters)
/// declared on the function. That set will need to be given to
/// `compute_regions`.
pub
(
in
borrow_check
)
fn
replace_regions_in_mir
<
'cx
,
'gcx
,
'tcx
>
(
infcx
:
&
InferCtxt
<
'cx
,
'gcx
,
'tcx
>
,
def_id
:
DefId
,
param_env
:
ty
::
ParamEnv
<
'tcx
>
,
mir
:
&
mut
Mir
<
'tcx
>
,
)
->
UniversalRegions
<
'tcx
>
{
debug!
(
"replace_regions_in_mir(def_id={:?})"
,
def_id
);
// Compute named region information.
let
universal_regions
=
universal_regions
::
universal_regions
(
infcx
,
def_id
);
// Compute named region information.
This also renumbers the inputs/outputs.
let
universal_regions
=
UniversalRegions
::
new
(
infcx
,
def_id
,
param_env
);
// Replace all regions with fresh inference variables.
// Replace all re
maining re
gions with fresh inference variables.
renumber
::
renumber_mir
(
infcx
,
&
universal_regions
,
mir
);
let
source
=
MirSource
::
item
(
def_id
);
...
...
@@ -68,7 +69,10 @@ pub(in borrow_check) fn compute_regions<'cx, 'gcx, 'tcx>(
param_env
:
ty
::
ParamEnv
<
'gcx
>
,
flow_inits
:
&
mut
FlowInProgress
<
MaybeInitializedLvals
<
'cx
,
'gcx
,
'tcx
>>
,
move_data
:
&
MoveData
<
'tcx
>
,
)
->
RegionInferenceContext
<
'tcx
>
{
)
->
(
RegionInferenceContext
<
'tcx
>
,
Option
<
ClosureRegionRequirements
>
,
)
{
// Run the MIR type-checker.
let
mir_node_id
=
infcx
.tcx.hir
.as_local_node_id
(
def_id
)
.unwrap
();
let
constraint_sets
=
&
type_check
::
type_check
(
infcx
,
mir_node_id
,
param_env
,
mir
);
...
...
@@ -76,13 +80,8 @@ pub(in borrow_check) fn compute_regions<'cx, 'gcx, 'tcx>(
// Create the region inference context, taking ownership of the region inference
// data that was contained in `infcx`.
let
var_origins
=
infcx
.take_region_var_origins
();
let
mut
regioncx
=
RegionInferenceContext
::
new
(
var_origins
,
&
universal_regions
,
mir
);
subtype_constraint_generation
::
generate
(
&
mut
regioncx
,
&
universal_regions
,
mir
,
constraint_sets
,
);
let
mut
regioncx
=
RegionInferenceContext
::
new
(
var_origins
,
universal_regions
,
mir
);
subtype_constraint_generation
::
generate
(
&
mut
regioncx
,
mir
,
constraint_sets
);
// Compute what is live where.
let
liveness
=
&
LivenessResults
{
...
...
@@ -115,13 +114,13 @@ pub(in borrow_check) fn compute_regions<'cx, 'gcx, 'tcx>(
);
// Solve the region constraints.
regioncx
.solve
(
infcx
,
&
mir
);
let
closure_region_requirements
=
regioncx
.solve
(
infcx
,
&
mir
,
def_id
);
// Dump MIR results into a file, if that is enabled. This let us
// write unit-tests.
dump_mir_results
(
infcx
,
liveness
,
MirSource
::
item
(
def_id
),
&
mir
,
&
regioncx
);
regioncx
(
regioncx
,
closure_region_requirements
)
}
struct
LivenessResults
{
...
...
@@ -197,7 +196,7 @@ fn dump_mir_results<'a, 'gcx, 'tcx>(
/// Right now, we piggy back on the `ReVar` to store our NLL inference
/// regions. These are indexed with `RegionVid`. This method will
/// assert that the region is a `ReVar` and extract its interal index.
/// This is reasonable because in our MIR we replace all
free
regions
/// This is reasonable because in our MIR we replace all
universal
regions
/// with inference variables.
pub
trait
ToRegionVid
{
fn
to_region_vid
(
&
self
)
->
RegionVid
;
...
...
src/librustc_mir/borrow_check/nll/region_infer/mod.rs
浏览文件 @
ab1c1bc6
...
...
@@ -9,12 +9,13 @@
// except according to those terms.
use
super
::
universal_regions
::
UniversalRegions
;
use
rustc
::
hir
::
def_id
::
DefId
;
use
rustc
::
infer
::
InferCtxt
;
use
rustc
::
infer
::
RegionVariableOrigin
;
use
rustc
::
infer
::
NLLRegionVariableOrigin
;
use
rustc
::
infer
::
RegionVariableOrigin
;
use
rustc
::
infer
::
SubregionOrigin
;
use
rustc
::
infer
::
region_constraints
::
VarOrigins
;
use
rustc
::
infer
::
outlives
::
free_region_map
::
FreeRegionMap
;
use
rustc
::
mir
::{
Location
,
Mir
};
use
rustc
::
mir
::{
ClosureOutlivesRequirement
,
ClosureRegionRequirements
,
Location
,
Mir
};
use
rustc
::
ty
::{
self
,
RegionVid
};
use
rustc_data_structures
::
indexed_vec
::
IndexVec
;
use
rustc_data_structures
::
fx
::
FxHashSet
;
...
...
@@ -52,12 +53,9 @@ pub struct RegionInferenceContext<'tcx> {
/// the free regions.)
point_indices
:
BTreeMap
<
Location
,
usize
>
,
/// Number of universally quantified regions. This is used to
/// determine the meaning of the bits in `inferred_values` and
/// friends.
num_universal_regions
:
usize
,
free_region_map
:
&
'tcx
FreeRegionMap
<
'tcx
>
,
/// Information about the universally quantified regions in scope
/// on this function and their (known) relations to one another.
universal_regions
:
UniversalRegions
<
'tcx
>
,
}
struct
RegionDefinition
<
'tcx
>
{
...
...
@@ -67,9 +65,15 @@ struct RegionDefinition<'tcx> {
/// late-bound-regions).
origin
:
RegionVariableOrigin
,
/// If this is a free-region, then this is `Some(X)` where `X` is
/// the name of the region.
name
:
Option
<
ty
::
Region
<
'tcx
>>
,
/// True if this is a universally quantified region. This means a
/// lifetime parameter that appears in the function signature (or,
/// in the case of a closure, in the closure environment, which of
/// course is also in the function signature).
is_universal
:
bool
,
/// If this is 'static or an early-bound region, then this is
/// `Some(X)` where `X` is the name of the region.
external_name
:
Option
<
ty
::
Region
<
'tcx
>>
,
}
#[derive(Copy,
Clone,
PartialEq,
Eq,
PartialOrd,
Ord,
Hash)]
...
...
@@ -98,11 +102,11 @@ impl<'tcx> RegionInferenceContext<'tcx> {
/// regions defined in `universal_regions`.
pub
fn
new
(
var_origins
:
VarOrigins
,
universal_regions
:
&
UniversalRegions
<
'tcx
>
,
universal_regions
:
UniversalRegions
<
'tcx
>
,
mir
:
&
Mir
<
'tcx
>
,
)
->
Self
{
let
num_region_variables
=
var_origins
.len
();
let
num_universal_regions
=
universal_regions
.
indices
.
len
();
let
num_universal_regions
=
universal_regions
.len
();
let
mut
num_points
=
0
;
let
mut
point_indices
=
BTreeMap
::
new
();
...
...
@@ -133,11 +137,10 @@ pub fn new(
inferred_values
:
None
,
constraints
:
Vec
::
new
(),
point_indices
,
num_universal_regions
,
free_region_map
:
universal_regions
.free_region_map
,
universal_regions
,
};
result
.init_universal_regions
(
universal_regions
);
result
.init_universal_regions
();
result
}
...
...
@@ -159,25 +162,24 @@ pub fn new(
/// R1 = { CFG, R0, R1 } // 'b
///
/// Here, R0 represents `'a`, and it contains (a) the entire CFG
/// and (b) any
free regions that it outlives, which in this case
///
is just itself. R1 (`'b`) in contrast also outlives `'a` and
/// hence contains R0 and R1.
fn
init_universal_regions
(
&
mut
self
,
universal_regions
:
&
UniversalRegions
<
'tcx
>
)
{
let
UniversalRegions
{
indices
,
free_region_map
:
_
,
}
=
universal_regions
;
/// and (b) any
universally quantified regions that it outlives,
///
which in this case is just itself. R1 (`'b`) in contrast also
///
outlives `'a` and
hence contains R0 and R1.
fn
init_universal_regions
(
&
mut
self
)
{
// Update the names (if any)
for
(
external_name
,
variable
)
in
self
.universal_regions
.named_universal_regions
()
{
self
.definitions
[
variable
]
.external_name
=
Some
(
external_name
);
}
// For each universally quantified region X:
for
(
free_region
,
&
variable
)
in
indices
{
for
variable
in
self
.universal_regions
.universal_regions
()
{
// These should be free-region variables.
assert
!
(
match
self
.definitions
[
variable
]
.origin
{
RegionVariableOrigin
::
NLL
(
NLLRegionVariableOrigin
::
FreeRegion
)
=>
true
,
_
=>
false
,
});
// Initialize the name and a few other details.
self
.definitions
[
variable
]
.name
=
Some
(
free_region
);
self
.definitions
[
variable
]
.is_universal
=
true
;
// Add all nodes in the CFG to liveness constraints
for
(
_
location
,
point_index
)
in
&
self
.point_indices
{
...
...
@@ -196,6 +198,14 @@ pub fn regions(&self) -> impl Iterator<Item = RegionVid> {
self
.definitions
.indices
()
}
/// Given a universal region in scope on the MIR, returns the
/// corresponding index.
///
/// (Panics if `r` is not a registered universal region.)
pub
fn
to_region_vid
(
&
self
,
r
:
ty
::
Region
<
'tcx
>
)
->
RegionVid
{
self
.universal_regions
.to_region_vid
(
r
)
}
/// Returns true if the region `r` contains the point `p`.
///
/// Panics if called before `solve()` executes,
...
...
@@ -237,19 +247,25 @@ pub(super) fn region_value_str(&self, r: RegionVid) -> String {
.as_ref
()
.expect
(
"region values not yet inferred"
);
self
.region_value_str_from_matrix
(
inferred_values
,
r
)
}
fn
region_value_str_from_matrix
(
&
self
,
matrix
:
&
BitMatrix
,
r
:
RegionVid
)
->
String
{
let
mut
result
=
String
::
new
();
result
.push_str
(
"{"
);
let
mut
sep
=
""
;
for
&
point
in
self
.point_indices
.keys
()
{
if
self
.region_contains_point_in_matrix
(
inferred_values
,
r
,
point
)
{
if
self
.region_contains_point_in_matrix
(
matrix
,
r
,
point
)
{
result
.push_str
(
&
format!
(
"{}{:?}"
,
sep
,
point
));
sep
=
", "
;
}
}
for
fr
in
(
0
..
self
.
num_universal_regions
)
.map
(
RegionVid
::
new
)
{
if
self
.region_contains_region_in_matrix
(
inferred_values
,
r
,
fr
)
{
for
fr
in
(
0
..
self
.
universal_regions
.len
()
)
.map
(
RegionVid
::
new
)
{
if
self
.region_contains_region_in_matrix
(
matrix
,
r
,
fr
)
{
result
.push_str
(
&
format!
(
"{}{:?}"
,
sep
,
fr
));
sep
=
", "
;
}
...
...
@@ -289,8 +305,14 @@ pub(super) fn add_outlives(
}
/// Perform region inference.
pub
(
super
)
fn
solve
(
&
mut
self
,
infcx
:
&
InferCtxt
<
'_
,
'_
,
'tcx
>
,
mir
:
&
Mir
<
'tcx
>
)
{
pub
(
super
)
fn
solve
(
&
mut
self
,
infcx
:
&
InferCtxt
<
'_
,
'_
,
'tcx
>
,
mir
:
&
Mir
<
'tcx
>
,
mir_def_id
:
DefId
,
)
->
Option
<
ClosureRegionRequirements
>
{
assert
!
(
self
.inferred_values
.is_none
(),
"values already inferred"
);
let
tcx
=
infcx
.tcx
;
// Find the minimal regions that can solve the constraints. This is infallible.
self
.propagate_constraints
(
mir
);
...
...
@@ -310,57 +332,135 @@ pub(super) fn solve(&mut self, infcx: &InferCtxt<'_, '_, 'tcx>, mir: &Mir<'tcx>)
// The universal regions are always found in a prefix of the
// full list.
let
free_region
_definitions
=
self
.definitions
let
universal
_definitions
=
self
.definitions
.iter_enumerated
()
.take_while
(|(
_
,
fr_definition
)|
fr_definition
.name
.is_some
());
.take_while
(|(
_
,
fr_definition
)|
fr_definition
.is_universal
);
// Go through each of the universal regions `fr` and check that
// they did not grow too large, accumulating any requirements
// for our caller into the `outlives_requirements` vector.
let
mut
outlives_requirements
=
vec!
[];
for
(
fr
,
_
)
in
universal_definitions
{
self
.check_universal_region
(
infcx
,
fr
,
&
mut
outlives_requirements
);
}
for
(
fr
,
fr_definition
)
in
free_region_definitions
{
self
.check_free_region
(
infcx
,
fr
,
fr_definition
);
// If this is not a closure, then there is no caller to which we can
// "pass the buck". So if there are any outlives-requirements that were
// not satisfied, we just have to report a hard error here.
if
!
tcx
.is_closure
(
mir_def_id
)
{
for
outlives_requirement
in
outlives_requirements
{
self
.report_error
(
infcx
,
outlives_requirement
.free_region
,
outlives_requirement
.outlived_free_region
,
outlives_requirement
.blame_span
,
);
}
return
None
;
}
let
num_external_vids
=
self
.universal_regions
.num_global_and_external_regions
();
Some
(
ClosureRegionRequirements
{
num_external_vids
,
outlives_requirements
,
})
}
fn
check_free_region
(
/// Check the final value for the free region `fr` to see if it
/// grew too large. In particular, examine what `end(X)` points
/// wound up in `fr`'s final value; for each `end(X)` where `X !=
/// fr`, we want to check that `fr: X`. If not, that's either an
/// error, or something we have to propagate to our creator.
///
/// Things that are to be propagated are accumulated into the
/// `outlives_requirements` vector.
fn
check_universal_region
(
&
self
,
infcx
:
&
InferCtxt
<
'_
,
'_
,
'tcx
>
,
longer_fr
:
RegionVid
,
longer_definition
:
&
RegionDefinition
<
'tcx
>
,
outlives_requirements
:
&
mut
Vec
<
ClosureOutlivesRequirement
>
,
)
{
let
inferred_values
=
self
.inferred_values
.as_ref
()
.unwrap
();
let
longer_name
=
longer_definition
.name
.unwrap
();
let
longer_value
=
inferred_values
.iter
(
longer_fr
.index
());
// Find every region `shorter` such that `longer: shorter`
// (because `longer` includes `end(shorter)`).
for
shorter_fr
in
longer_value
.take_while
(|
&
i
|
i
<
self
.num_universal_regions
)
{
let
shorter_fr
=
RegionVid
::
new
(
shorter_fr
);
debug!
(
"check_universal_region(fr={:?})"
,
longer_fr
);
// `fr` includes `end(fr)`, that's not especially
// interesting.
if
longer_fr
==
shorter_fr
{
// Find every region `o` such that `fr: o`
// (because `fr` includes `end(o)`).
let
shorter_frs
=
longer_value
.take_while
(|
&
i
|
i
<
self
.universal_regions
.len
())
.map
(
RegionVid
::
new
);
for
shorter_fr
in
shorter_frs
{
// If it is known that `fr: o`, carry on.
if
self
.universal_regions
.outlives
(
longer_fr
,
shorter_fr
)
{
continue
;
}
let
shorter_definition
=
&
self
.definitions
[
shorter_fr
];
let
shorter_name
=
shorter_definition
.name
.unwrap
();
// Check that `o <= fr`. If not, report an error.
if
!
self
.free_region_map
.sub_free_regions
(
shorter_name
,
longer_name
)
{
// FIXME: worst error msg ever
let
blame_span
=
self
.blame_span
(
longer_fr
,
shorter_fr
);
infcx
.tcx.sess
.span_err
(
blame_span
,
&
format!
(
"free region `{}` does not outlive `{}`"
,
longer_name
,
shorter_name
),
debug!
(
"check_universal_region: fr={:?} does not outlive shorter_fr={:?}"
,
longer_fr
,
shorter_fr
,
);
let
blame_span
=
self
.blame_span
(
longer_fr
,
shorter_fr
);
// Shrink `fr` until we find a non-local region (if we do).
// We'll call that `fr-` -- it's ever so slightly smaller than `fr`.
if
let
Some
(
fr_minus
)
=
self
.universal_regions
.non_local_lower_bound
(
longer_fr
)
{
debug!
(
"check_universal_region: fr_minus={:?}"
,
fr_minus
);
// Grow `shorter_fr` until we find a non-local
// regon. (We always will.) We'll call that
// `shorter_fr+` -- it's ever so slightly larger than
// `fr`.
let
shorter_fr_plus
=
self
.universal_regions
.non_local_upper_bound
(
shorter_fr
);
debug!
(
"check_universal_region: shorter_fr_plus={:?}"
,
shorter_fr_plus
);
// Push the constraint `fr-: shorter_fr+`
outlives_requirements
.push
(
ClosureOutlivesRequirement
{
free_region
:
fr_minus
,
outlived_free_region
:
shorter_fr_plus
,
blame_span
:
blame_span
,
});
return
;
}
// If we could not shrink `fr` to something smaller that
// the external users care about, then we can't pass the
// buck; just report an error.
self
.report_error
(
infcx
,
longer_fr
,
shorter_fr
,
blame_span
);
}
}
fn
report_error
(
&
self
,
infcx
:
&
InferCtxt
<
'_
,
'_
,
'tcx
>
,
fr
:
RegionVid
,
outlived_fr
:
RegionVid
,
blame_span
:
Span
,
)
{
// Obviously uncool error reporting.
let
fr_string
=
match
self
.definitions
[
fr
]
.external_name
{
Some
(
r
)
=>
format!
(
"free region `{}`"
,
r
),
None
=>
format!
(
"free region `{:?}`"
,
fr
),
};
let
outlived_fr_string
=
match
self
.definitions
[
outlived_fr
]
.external_name
{
Some
(
r
)
=>
format!
(
"free region `{}`"
,
r
),
None
=>
format!
(
"free region `{:?}`"
,
outlived_fr
),
};
infcx
.tcx.sess
.span_err
(
blame_span
,
&
format!
(
"{} does not outlive {}"
,
fr_string
,
outlived_fr_string
,),
);
}
/// Propagate the region constraints: this will grow the values
/// for each region variable until all the constraints are
/// satisfied. Note that some values may grow **too** large to be
...
...
@@ -421,8 +521,6 @@ fn copy(
stack
.push
(
start_point
);
while
let
Some
(
p
)
=
stack
.pop
()
{
debug!
(
" copy: p={:?}"
,
p
);
if
!
self
.region_contains_point_in_matrix
(
inferred_values
,
from_region
,
p
)
{
debug!
(
" not in from-region"
);
continue
;
...
...
@@ -464,7 +562,7 @@ fn copy(
// and make sure they are included in the `to_region`.
let
universal_region_indices
=
inferred_values
.iter
(
from_region
.index
())
.take_while
(|
&
i
|
i
<
self
.
num_universal_regions
)
.take_while
(|
&
i
|
i
<
self
.
universal_regions
.len
()
)
.collect
::
<
Vec
<
_
>>
();
for
fr
in
&
universal_region_indices
{
changed
|
=
inferred_values
.add
(
to_region
.index
(),
*
fr
);
...
...
@@ -535,7 +633,11 @@ fn new(origin: RegionVariableOrigin) -> Self {
// Create a new region definition. Note that, for free
// regions, these fields get updated later in
// `init_universal_regions`.
Self
{
origin
,
name
:
None
}
Self
{
origin
,
is_universal
:
false
,
external_name
:
None
,
}
}
}
...
...
@@ -551,3 +653,70 @@ fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
)
}
}
pub
trait
ClosureRegionRequirementsExt
{
fn
apply_requirements
<
'tcx
>
(
&
self
,
infcx
:
&
InferCtxt
<
'_
,
'_
,
'tcx
>
,
location
:
Location
,
closure_def_id
:
DefId
,
closure_substs
:
ty
::
ClosureSubsts
<
'tcx
>
,
);
}
impl
ClosureRegionRequirementsExt
for
ClosureRegionRequirements
{
/// Given an instance T of the closure type, this method
/// instantiates the "extra" requirements that we computed for the
/// closure into the inference context. This has the effect of
/// adding new subregion obligations to existing variables.
///
/// As described on `ClosureRegionRequirements`, the extra
/// requirements are expressed in terms of regionvids that index
/// into the free regions that appear on the closure type. So, to
/// do this, we first copy those regions out from the type T into
/// a vector. Then we can just index into that vector to extract
/// out the corresponding region from T and apply the
/// requirements.
fn
apply_requirements
<
'tcx
>
(
&
self
,
infcx
:
&
InferCtxt
<
'_
,
'_
,
'tcx
>
,
location
:
Location
,
closure_def_id
:
DefId
,
closure_substs
:
ty
::
ClosureSubsts
<
'tcx
>
,
)
{
let
tcx
=
infcx
.tcx
;
debug!
(
"apply_requirements(location={:?}, closure_def_id={:?}, closure_substs={:?})"
,
location
,
closure_def_id
,
closure_substs
);
// Get Tu.
let
user_closure_ty
=
tcx
.mk_closure
(
closure_def_id
,
closure_substs
);
debug!
(
"apply_requirements: user_closure_ty={:?}"
,
user_closure_ty
);
// Extract the values of the free regions in `user_closure_ty`
// into a vector. These are the regions that we will be
// relating to one another.
let
closure_mapping
=
UniversalRegions
::
closure_mapping
(
infcx
,
user_closure_ty
,
self
.num_external_vids
);
debug!
(
"apply_requirements: closure_mapping={:?}"
,
closure_mapping
);
// Create the predicates.
for
outlives_requirement
in
&
self
.outlives_requirements
{
let
region
=
closure_mapping
[
outlives_requirement
.free_region
];
let
outlived_region
=
closure_mapping
[
outlives_requirement
.outlived_free_region
];
debug!
(
"apply_requirements: region={:?} outlived_region={:?} outlives_requirements={:?}"
,
region
,
outlived_region
,
outlives_requirement
);
// FIXME, this origin is not entirely suitable.
let
origin
=
SubregionOrigin
::
CallRcvr
(
outlives_requirement
.blame_span
);
infcx
.sub_regions
(
origin
,
outlived_region
,
region
);
}
}
}
src/librustc_mir/borrow_check/nll/renumber.rs
浏览文件 @
ab1c1bc6
...
...
@@ -8,10 +8,11 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use
rustc_data_structures
::
indexed_vec
::
{
Idx
,
IndexVec
}
;
use
rustc_data_structures
::
indexed_vec
::
Idx
;
use
rustc
::
ty
::
subst
::
Substs
;
use
rustc
::
ty
::{
self
,
ClosureSubsts
,
RegionVid
,
Ty
,
TypeFoldable
};
use
rustc
::
ty
::{
self
,
ClosureSubsts
,
Ty
,
TypeFoldable
};
use
rustc
::
mir
::{
BasicBlock
,
Local
,
Location
,
Mir
,
Statement
,
StatementKind
};
use
rustc
::
mir
::
RETURN_PLACE
;
use
rustc
::
mir
::
visit
::{
MutVisitor
,
TyContext
};
use
rustc
::
infer
::{
InferCtxt
,
NLLRegionVariableOrigin
};
...
...
@@ -25,25 +26,24 @@ pub fn renumber_mir<'a, 'gcx, 'tcx>(
universal_regions
:
&
UniversalRegions
<
'tcx
>
,
mir
:
&
mut
Mir
<
'tcx
>
,
)
{
// Create inference variables for each of the free regions
// declared on the function signature.
let
free_region_inference_vars
=
(
0
..
universal_regions
.indices
.len
())
.map
(
RegionVid
::
new
)
.map
(|
vid_expected
|
{
let
r
=
infcx
.next_nll_region_var
(
NLLRegionVariableOrigin
::
FreeRegion
);
assert_eq!
(
vid_expected
,
r
.to_region_vid
());
r
})
.collect
();
debug!
(
"renumber_mir()"
);
debug!
(
"renumber_mir: universal_regions={:#?}"
,
universal_regions
);
debug!
(
"renumber_mir: mir.arg_count={:?}"
,
mir
.arg_count
);
// Update the return type and types of the arguments based on the
// `universal_regions` computation.
debug!
(
"renumber_mir: output_ty={:?}"
,
universal_regions
.output_ty
);
mir
.local_decls
[
RETURN_PLACE
]
.ty
=
universal_regions
.output_ty
;
for
(
&
input_ty
,
local
)
in
universal_regions
.input_tys
.iter
()
.zip
((
1
..
)
.map
(
Local
::
new
))
{
debug!
(
"renumber_mir: input_ty={:?} local={:?}"
,
input_ty
,
local
);
mir
.local_decls
[
local
]
.ty
=
input_ty
;
}
let
mut
visitor
=
NLLVisitor
{
infcx
,
universal_regions
,
free_region_inference_vars
,
arg_count
:
mir
.arg_count
,
};
visitor
.visit_mir
(
mir
);
...
...
@@ -51,8 +51,6 @@ pub fn renumber_mir<'a, 'gcx, 'tcx>(
struct
NLLVisitor
<
'a
,
'gcx
:
'a
+
'tcx
,
'tcx
:
'a
>
{
infcx
:
&
'a
InferCtxt
<
'a
,
'gcx
,
'tcx
>
,
universal_regions
:
&
'a
UniversalRegions
<
'tcx
>
,
free_region_inference_vars
:
IndexVec
<
RegionVid
,
ty
::
Region
<
'tcx
>>
,
arg_count
:
usize
,
}
...
...
@@ -74,20 +72,17 @@ fn renumber_regions<T>(&mut self, ty_context: TyContext, value: &T) -> T
})
}
///
Renumbers the regions appearing in `value`, but those regions
///
are expected to be free regions from the function signature
.
fn
renumber_universal_regions
<
T
>
(
&
mut
self
,
value
:
&
T
)
->
T
///
Checks that all the regions appearing in `value` have already
///
been renumbered. `FreeRegions` code should have done this
.
fn
assert_free_regions_are_renumbered
<
T
>
(
&
self
,
value
:
&
T
)
where
T
:
TypeFoldable
<
'tcx
>
,
{
debug!
(
"
renumber_universal_regions
(value={:?})"
,
value
);
debug!
(
"
assert_free_regions_are_renumbered
(value={:?})"
,
value
);
self
.infcx
.tcx
.fold_regions
(
value
,
&
mut
false
,
|
region
,
_
depth
|
{
let
index
=
self
.universal_regions.indices
[
&
region
];
self
.free_region_inference_vars
[
index
]
})
self
.infcx.tcx
.for_each_free_region
(
value
,
|
region
|
{
region
.to_region_vid
();
// will panic if `region` is not renumbered
});
}
fn
is_argument_or_return_slot
(
&
self
,
local
:
Local
)
->
bool
{
...
...
@@ -110,12 +105,12 @@ fn visit_ty(&mut self, ty: &mut Ty<'tcx>, ty_context: TyContext) {
ty_context
);
let
old_ty
=
*
ty
;
*
ty
=
if
is_arg
{
self
.renumber_universal_regions
(
&
old_ty
)
if
is_arg
{
self
.assert_free_regions_are_renumbered
(
ty
);
}
else
{
self
.renumber_regions
(
ty_context
,
&
old_ty
)
};
*
ty
=
self
.renumber_regions
(
ty_context
,
ty
);
}
debug!
(
"visit_ty: ty={:?}"
,
ty
);
}
...
...
src/librustc_mir/borrow_check/nll/subtype_constraint_generation.rs
浏览文件 @
ab1c1bc6
...
...
@@ -15,7 +15,6 @@
use
transform
::
type_check
::
MirTypeckRegionConstraints
;
use
transform
::
type_check
::
OutlivesSet
;
use
super
::
universal_regions
::
UniversalRegions
;
use
super
::
region_infer
::
RegionInferenceContext
;
/// When the MIR type-checker executes, it validates all the types in
...
...
@@ -25,20 +24,17 @@
/// them into the NLL `RegionInferenceContext`.
pub
(
super
)
fn
generate
<
'tcx
>
(
regioncx
:
&
mut
RegionInferenceContext
<
'tcx
>
,
universal_regions
:
&
UniversalRegions
<
'tcx
>
,
mir
:
&
Mir
<
'tcx
>
,
constraints
:
&
MirTypeckRegionConstraints
<
'tcx
>
,
)
{
SubtypeConstraintGenerator
{
regioncx
,
universal_regions
,
mir
,
}
.generate
(
constraints
);
}
struct
SubtypeConstraintGenerator
<
'cx
,
'tcx
:
'cx
>
{
regioncx
:
&
'cx
mut
RegionInferenceContext
<
'tcx
>
,
universal_regions
:
&
'cx
UniversalRegions
<
'tcx
>
,
mir
:
&
'cx
Mir
<
'tcx
>
,
}
...
...
@@ -106,10 +102,7 @@ fn to_region_vid(&self, r: ty::Region<'tcx>) -> ty::RegionVid {
if
let
ty
::
ReVar
(
vid
)
=
r
{
*
vid
}
else
{
*
self
.universal_regions
.indices
.get
(
&
r
)
.unwrap_or_else
(||
bug!
(
"to_region_vid: bad region {:?}"
,
r
))
self
.regioncx
.to_region_vid
(
r
)
}
}
}
src/librustc_mir/borrow_check/nll/universal_regions.rs
浏览文件 @
ab1c1bc6
此差异已折叠。
点击以展开。
src/librustc_mir/transform/type_check.rs
浏览文件 @
ab1c1bc6
...
...
@@ -11,6 +11,7 @@
//! This pass type-checks the MIR to ensure it is not broken.
#![allow(unreachable_code)]
use
borrow_check
::
nll
::
region_infer
::
ClosureRegionRequirementsExt
;
use
rustc
::
infer
::{
InferCtxt
,
InferOk
,
InferResult
,
LateBoundRegionConversionTime
,
UnitResult
};
use
rustc
::
infer
::
region_constraints
::
RegionConstraintData
;
use
rustc
::
traits
::{
self
,
FulfillmentContext
};
...
...
@@ -1135,14 +1136,45 @@ fn check_aggregate_rvalue(
operands
:
&
[
Operand
<
'tcx
>
],
location
:
Location
,
)
{
let
tcx
=
self
.tcx
();
match
aggregate_kind
{
// tuple rvalue field type is always the type of the op. Nothing to check here.
AggregateKind
::
Tuple
=>
return
,
// For closures, we have some **extra requirements** we
// have to check. In particular, in their upvars and
// signatures, closures often reference various regions
// from the surrounding function -- we call those the
// closure's free regions. When we borrow-check (and hence
// region-check) closures, we may find that the closure
// requires certain relationships between those free
// regions. However, because those free regions refer to
// portions of the CFG of their caller, the closure is not
// in a position to verify those relationships. In that
// case, the requirements get "propagated" to us, and so
// we have to solve them here where we instantiate the
// closure.
//
// Despite the opacity of the previous parapgrah, this is
// actually relatively easy to understand in terms of the
// desugaring. A closure gets desugared to a struct, and
// these extra requirements are basically like where
// clauses on the struct.
AggregateKind
::
Closure
(
def_id
,
substs
)
=>
{
if
let
Some
(
closure_region_requirements
)
=
tcx
.mir_borrowck
(
*
def_id
)
{
closure_region_requirements
.apply_requirements
(
self
.infcx
,
location
,
*
def_id
,
*
substs
,
);
}
}
_
=>
{}
}
let
tcx
=
self
.tcx
();
for
(
i
,
operand
)
in
operands
.iter
()
.enumerate
()
{
let
field_ty
=
match
self
.aggregate_field_ty
(
aggregate_kind
,
i
,
location
)
{
Ok
(
field_ty
)
=>
field_ty
,
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录