Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
int
Rust
提交
434d59a2
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,发现更多精彩内容 >>
提交
434d59a2
编写于
5月 07, 2018
作者:
N
Niko Matsakis
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
ignore the point where the outlives requirement was added
上级
964e0691
变更
6
隐藏空白更改
内联
并排
Showing
6 changed file
with
122 addition
and
409 deletion
+122
-409
src/librustc_data_structures/bitvec.rs
src/librustc_data_structures/bitvec.rs
+1
-1
src/librustc_mir/borrow_check/nll/region_infer/dfs.rs
src/librustc_mir/borrow_check/nll/region_infer/dfs.rs
+0
-265
src/librustc_mir/borrow_check/nll/region_infer/mod.rs
src/librustc_mir/borrow_check/nll/region_infer/mod.rs
+53
-81
src/librustc_mir/borrow_check/nll/region_infer/values.rs
src/librustc_mir/borrow_check/nll/region_infer/values.rs
+16
-54
src/test/ui/nll/get_default.rs
src/test/ui/nll/get_default.rs
+4
-2
src/test/ui/nll/get_default.stderr
src/test/ui/nll/get_default.stderr
+48
-6
未找到文件。
src/librustc_data_structures/bitvec.rs
浏览文件 @
434d59a2
...
...
@@ -326,7 +326,7 @@ pub fn merge(&mut self, read: R, write: R) -> bool {
}
/// True if `sub` is a subset of `sup`
pub
fn
subset
(
&
self
,
sub
:
R
,
sup
:
R
)
->
bool
{
pub
fn
is_
subset
(
&
self
,
sub
:
R
,
sup
:
R
)
->
bool
{
sub
==
sup
||
{
let
bit_set_sub
=
&
self
.vector
[
sub
];
let
bit_set_sup
=
&
self
.vector
[
sup
];
...
...
src/librustc_mir/borrow_check/nll/region_infer/dfs.rs
已删除
100644 → 0
浏览文件 @
964e0691
// 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.
//! Module defining the `dfs` method on `RegionInferenceContext`, along with
//! its associated helper traits.
use
borrow_check
::
nll
::
universal_regions
::
UniversalRegions
;
use
borrow_check
::
nll
::
region_infer
::
RegionInferenceContext
;
use
borrow_check
::
nll
::
region_infer
::
values
::{
RegionElementIndex
,
RegionValueElements
,
RegionValues
};
use
syntax
::
codemap
::
Span
;
use
rustc
::
mir
::{
Location
,
Mir
};
use
rustc
::
ty
::
RegionVid
;
use
rustc_data_structures
::
bitvec
::
BitVector
;
use
rustc_data_structures
::
indexed_vec
::
Idx
;
pub
(
super
)
struct
DfsStorage
{
stack
:
Vec
<
Location
>
,
visited
:
BitVector
,
}
impl
<
'tcx
>
RegionInferenceContext
<
'tcx
>
{
/// Creates dfs storage for use by dfs; this should be shared
/// across as many calls to dfs as possible to amortize allocation
/// costs.
pub
(
super
)
fn
new_dfs_storage
(
&
self
)
->
DfsStorage
{
let
num_elements
=
self
.elements
.num_elements
();
DfsStorage
{
stack
:
vec!
[],
visited
:
BitVector
::
new
(
num_elements
),
}
}
/// Function used to satisfy or test a `R1: R2 @ P`
/// constraint. The core idea is that it performs a DFS starting
/// from `P`. The precise actions *during* that DFS depend on the
/// `op` supplied, so see (e.g.) `CopyFromSourceToTarget` for more
/// details.
///
/// Returns:
///
/// - `Ok(true)` if the walk was completed and something changed
/// along the way;
/// - `Ok(false)` if the walk was completed with no changes;
/// - `Err(early)` if the walk was existed early by `op`. `earlyelem` is the
/// value that `op` returned.
#[inline(never)]
// ensure dfs is identifiable in profiles
pub
(
super
)
fn
dfs
<
C
>
(
&
self
,
mir
:
&
Mir
<
'tcx
>
,
dfs
:
&
mut
DfsStorage
,
mut
op
:
C
,
)
->
Result
<
bool
,
C
::
Early
>
where
C
:
DfsOp
,
{
let
mut
changed
=
false
;
dfs
.visited
.clear
();
dfs
.stack
.push
(
op
.start_point
());
while
let
Some
(
p
)
=
dfs
.stack
.pop
()
{
let
point_index
=
self
.elements
.index
(
p
);
if
!
op
.source_region_contains
(
point_index
)
{
debug!
(
" not in from-region"
);
continue
;
}
if
!
dfs
.visited
.insert
(
point_index
.index
())
{
debug!
(
" already visited"
);
continue
;
}
let
new
=
op
.add_to_target_region
(
point_index
)
?
;
changed
|
=
new
;
let
block_data
=
&
mir
[
p
.block
];
let
start_stack_len
=
dfs
.stack
.len
();
if
p
.statement_index
<
block_data
.statements
.len
()
{
dfs
.stack
.push
(
Location
{
statement_index
:
p
.statement_index
+
1
,
..
p
});
}
else
{
dfs
.stack
.extend
(
block_data
.terminator
()
.successors
()
.map
(|
&
basic_block
|
Location
{
statement_index
:
0
,
block
:
basic_block
,
}),
);
}
if
dfs
.stack
.len
()
==
start_stack_len
{
// 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`.
changed
|
=
op
.add_universal_regions_outlived_by_source_to_target
()
?
;
}
}
Ok
(
changed
)
}
}
/// Customizes the operation of the `dfs` function. This function is
/// used during inference to satisfy a `R1: R2 @ P` constraint.
pub
(
super
)
trait
DfsOp
{
/// If this op stops the walk early, what type does it propagate?
type
Early
;
/// Returns the point from which to start the DFS.
fn
start_point
(
&
self
)
->
Location
;
/// Returns true if the source region contains the given point.
fn
source_region_contains
(
&
mut
self
,
point_index
:
RegionElementIndex
)
->
bool
;
/// Adds the given point to the target region, returning true if
/// something has changed. Returns `Err` if we should abort the
/// walk early.
fn
add_to_target_region
(
&
mut
self
,
point_index
:
RegionElementIndex
,
)
->
Result
<
bool
,
Self
::
Early
>
;
/// Adds all universal regions in the source region to the target region, returning
/// true if something has changed.
fn
add_universal_regions_outlived_by_source_to_target
(
&
mut
self
)
->
Result
<
bool
,
Self
::
Early
>
;
}
/// Used during inference to enforce a `R1: R2 @ P` constraint. For
/// each point Q we reach along the DFS, we check if Q is in R2 (the
/// "source region"). If not, we stop the walk. Otherwise, we add Q to
/// R1 (the "target region") and continue to Q's successors. If we
/// reach the end of the graph, then we add any universal regions from
/// R2 into R1.
pub
(
super
)
struct
CopyFromSourceToTarget
<
'v
>
{
pub
source_region
:
RegionVid
,
pub
target_region
:
RegionVid
,
pub
inferred_values
:
&
'v
mut
RegionValues
,
pub
constraint_point
:
Location
,
pub
constraint_span
:
Span
,
}
impl
<
'v
>
DfsOp
for
CopyFromSourceToTarget
<
'v
>
{
/// We never stop the walk early.
type
Early
=
!
;
fn
start_point
(
&
self
)
->
Location
{
self
.constraint_point
}
fn
source_region_contains
(
&
mut
self
,
point_index
:
RegionElementIndex
)
->
bool
{
self
.inferred_values
.contains
(
self
.source_region
,
point_index
)
}
fn
add_to_target_region
(
&
mut
self
,
point_index
:
RegionElementIndex
)
->
Result
<
bool
,
!>
{
Ok
(
self
.inferred_values
.add_due_to_outlives
(
self
.source_region
,
self
.target_region
,
point_index
,
self
.constraint_point
,
self
.constraint_span
,
))
}
fn
add_universal_regions_outlived_by_source_to_target
(
&
mut
self
)
->
Result
<
bool
,
!>
{
Ok
(
self
.inferred_values
.add_universal_regions_outlived_by
(
self
.source_region
,
self
.target_region
,
self
.constraint_point
,
self
.constraint_span
,
))
}
}
/// Used after inference to *test* a `R1: R2 @ P` constraint. For
/// each point Q we reach along the DFS, we check if Q in R2 is also
/// contained in R1. If not, we abort the walk early with an `Err`
/// condition. Similarly, if we reach the end of the graph and find
/// that R1 contains some universal region that R2 does not contain,
/// we abort the walk early.
pub
(
super
)
struct
TestTargetOutlivesSource
<
'v
,
'tcx
:
'v
>
{
pub
source_region
:
RegionVid
,
pub
target_region
:
RegionVid
,
pub
elements
:
&
'v
RegionValueElements
,
pub
universal_regions
:
&
'v
UniversalRegions
<
'tcx
>
,
pub
inferred_values
:
&
'v
RegionValues
,
pub
constraint_point
:
Location
,
}
impl
<
'v
,
'tcx
>
DfsOp
for
TestTargetOutlivesSource
<
'v
,
'tcx
>
{
/// The element that was not found within R2.
type
Early
=
RegionElementIndex
;
fn
start_point
(
&
self
)
->
Location
{
self
.constraint_point
}
fn
source_region_contains
(
&
mut
self
,
point_index
:
RegionElementIndex
)
->
bool
{
self
.inferred_values
.contains
(
self
.source_region
,
point_index
)
}
fn
add_to_target_region
(
&
mut
self
,
point_index
:
RegionElementIndex
,
)
->
Result
<
bool
,
RegionElementIndex
>
{
if
!
self
.inferred_values
.contains
(
self
.target_region
,
point_index
)
{
return
Err
(
point_index
);
}
Ok
(
false
)
}
fn
add_universal_regions_outlived_by_source_to_target
(
&
mut
self
,
)
->
Result
<
bool
,
RegionElementIndex
>
{
// For all `ur_in_source` in `source_region`.
for
ur_in_source
in
self
.inferred_values
.universal_regions_outlived_by
(
self
.source_region
)
{
// Check that `target_region` outlives `ur_in_source`.
// If `ur_in_source` is a member of `target_region`, OK.
//
// (This is implied by the loop below, actually, just an
// irresistible micro-opt. Mm. Premature optimization. So
// tasty.)
if
self
.inferred_values
.contains
(
self
.target_region
,
ur_in_source
)
{
continue
;
}
// If there is some other element X such that `target_region: X` and
// `X: ur_in_source`, OK.
if
self
.inferred_values
.universal_regions_outlived_by
(
self
.target_region
)
.any
(|
ur_in_target
|
self
.universal_regions
.outlives
(
ur_in_target
,
ur_in_source
))
{
continue
;
}
// Otherwise, not known to be true.
return
Err
(
self
.elements
.index
(
ur_in_source
));
}
Ok
(
false
)
}
}
src/librustc_mir/borrow_check/nll/region_infer/mod.rs
浏览文件 @
434d59a2
...
...
@@ -11,15 +11,17 @@
use
super
::
universal_regions
::
UniversalRegions
;
use
borrow_check
::
nll
::
region_infer
::
values
::
ToElementIndex
;
use
rustc
::
hir
::
def_id
::
DefId
;
use
rustc
::
infer
::
error_reporting
::
nice_region_error
::
NiceRegionError
;
use
rustc
::
infer
::
region_constraints
::{
GenericKind
,
VarInfos
};
use
rustc
::
infer
::
InferCtxt
;
use
rustc
::
infer
::
NLLRegionVariableOrigin
;
use
rustc
::
infer
::
RegionObligation
;
use
rustc
::
infer
::
RegionVariableOrigin
;
use
rustc
::
infer
::
SubregionOrigin
;
use
rustc
::
infer
::
error_reporting
::
nice_region_error
::
NiceRegionError
;
use
rustc
::
infer
::
region_constraints
::{
GenericKind
,
VarInfos
};
use
rustc
::
mir
::{
ClosureOutlivesRequirement
,
ClosureOutlivesSubject
,
ClosureRegionRequirements
,
Local
,
Location
,
Mir
};
use
rustc
::
mir
::{
ClosureOutlivesRequirement
,
ClosureOutlivesSubject
,
ClosureRegionRequirements
,
Local
,
Location
,
Mir
,
};
use
rustc
::
traits
::
ObligationCause
;
use
rustc
::
ty
::{
self
,
RegionVid
,
Ty
,
TypeFoldable
};
use
rustc
::
util
::
common
::{
self
,
ErrorReported
};
...
...
@@ -31,8 +33,6 @@
use
syntax_pos
::
Span
;
mod
annotation
;
mod
dfs
;
use
self
::
dfs
::{
CopyFromSourceToTarget
,
TestTargetOutlivesSource
};
mod
dump_mir
;
mod
graphviz
;
mod
values
;
...
...
@@ -422,9 +422,7 @@ fn solve_inner<'gcx>(
)
->
Option
<
ClosureRegionRequirements
<
'gcx
>>
{
assert
!
(
self
.inferred_values
.is_none
(),
"values already inferred"
);
let
dfs_storage
=
&
mut
self
.new_dfs_storage
();
self
.propagate_constraints
(
mir
,
dfs_storage
);
self
.propagate_constraints
(
mir
);
// If this is a closure, we can propagate unsatisfied
// `outlives_requirements` to our creator, so create a vector
...
...
@@ -437,13 +435,7 @@ fn solve_inner<'gcx>(
None
};
self
.check_type_tests
(
infcx
,
mir
,
dfs_storage
,
mir_def_id
,
outlives_requirements
.as_mut
(),
);
self
.check_type_tests
(
infcx
,
mir
,
mir_def_id
,
outlives_requirements
.as_mut
());
self
.check_universal_regions
(
infcx
,
mir_def_id
,
outlives_requirements
.as_mut
());
...
...
@@ -464,18 +456,14 @@ fn solve_inner<'gcx>(
/// for each region variable until all the constraints are
/// satisfied. Note that some values may grow **too** large to be
/// feasible, but we check this later.
fn
propagate_constraints
(
&
mut
self
,
mir
:
&
Mir
<
'tcx
>
,
dfs_storage
:
&
mut
dfs
::
DfsStorage
)
{
fn
propagate_constraints
(
&
mut
self
,
mir
:
&
Mir
<
'tcx
>
)
{
self
.dependency_map
=
Some
(
self
.build_dependency_map
());
let
inferred_values
=
self
.compute_region_values
(
mir
,
dfs_storage
);
let
inferred_values
=
self
.compute_region_values
(
mir
);
self
.inferred_values
=
Some
(
inferred_values
);
}
#[inline(never)]
// ensure dfs is identifiable in profiles
fn
compute_region_values
(
&
self
,
mir
:
&
Mir
<
'tcx
>
,
dfs_storage
:
&
mut
dfs
::
DfsStorage
,
)
->
RegionValues
{
fn
compute_region_values
(
&
self
,
_
mir
:
&
Mir
<
'tcx
>
)
->
RegionValues
{
debug!
(
"compute_region_values()"
);
debug!
(
"compute_region_values: constraints={:#?}"
,
{
let
mut
constraints
:
Vec
<
_
>
=
self
.constraints
.iter
()
.collect
();
...
...
@@ -502,21 +490,7 @@ fn compute_region_values(
let
constraint
=
&
self
.constraints
[
constraint_idx
];
debug!
(
"propagate_constraints: constraint={:?}"
,
constraint
);
// Grow the value as needed to accommodate the
// outlives constraint.
let
Ok
(
made_changes
)
=
self
.dfs
(
mir
,
dfs_storage
,
CopyFromSourceToTarget
{
source_region
:
constraint
.sub
,
target_region
:
constraint
.sup
,
inferred_values
:
&
mut
inferred_values
,
constraint_point
:
constraint
.point
,
constraint_span
:
constraint
.span
,
},
);
if
made_changes
{
if
inferred_values
.add_region
(
constraint
.sup
,
constraint
.sub
)
{
debug!
(
"propagate_constraints: sub={:?}"
,
constraint
.sub
);
debug!
(
"propagate_constraints: sup={:?}"
,
constraint
.sup
);
...
...
@@ -561,7 +535,6 @@ fn check_type_tests<'gcx>(
&
self
,
infcx
:
&
InferCtxt
<
'_
,
'gcx
,
'tcx
>
,
mir
:
&
Mir
<
'tcx
>
,
dfs_storage
:
&
mut
dfs
::
DfsStorage
,
mir_def_id
:
DefId
,
mut
propagated_outlives_requirements
:
Option
<&
mut
Vec
<
ClosureOutlivesRequirement
<
'gcx
>>>
,
)
{
...
...
@@ -570,13 +543,7 @@ fn check_type_tests<'gcx>(
for
type_test
in
&
self
.type_tests
{
debug!
(
"check_type_test: {:?}"
,
type_test
);
if
self
.eval_region_test
(
mir
,
dfs_storage
,
type_test
.point
,
type_test
.lower_bound
,
&
type_test
.test
,
)
{
if
self
.eval_region_test
(
mir
,
type_test
.point
,
type_test
.lower_bound
,
&
type_test
.test
)
{
continue
;
}
...
...
@@ -833,7 +800,6 @@ fn universal_upper_bound(&self, r: RegionVid) -> RegionVid {
fn
eval_region_test
(
&
self
,
mir
:
&
Mir
<
'tcx
>
,
dfs_storage
:
&
mut
dfs
::
DfsStorage
,
point
:
Location
,
lower_bound
:
RegionVid
,
test
:
&
RegionTest
,
...
...
@@ -846,27 +812,26 @@ fn eval_region_test(
match
test
{
RegionTest
::
IsOutlivedByAllRegionsIn
(
regions
)
=>
regions
.iter
()
.all
(|
&
r
|
self
.eval_outlives
(
mir
,
dfs_storage
,
r
,
lower_bound
,
point
)),
.all
(|
&
r
|
self
.eval_outlives
(
mir
,
r
,
lower_bound
,
point
)),
RegionTest
::
IsOutlivedByAnyRegionIn
(
regions
)
=>
regions
.iter
()
.any
(|
&
r
|
self
.eval_outlives
(
mir
,
dfs_storage
,
r
,
lower_bound
,
point
)),
.any
(|
&
r
|
self
.eval_outlives
(
mir
,
r
,
lower_bound
,
point
)),
RegionTest
::
Any
(
tests
)
=>
tests
.iter
()
.any
(|
test
|
self
.eval_region_test
(
mir
,
dfs_storage
,
point
,
lower_bound
,
test
)),
.any
(|
test
|
self
.eval_region_test
(
mir
,
point
,
lower_bound
,
test
)),
RegionTest
::
All
(
tests
)
=>
tests
.iter
()
.all
(|
test
|
self
.eval_region_test
(
mir
,
dfs_storage
,
point
,
lower_bound
,
test
)),
.all
(|
test
|
self
.eval_region_test
(
mir
,
point
,
lower_bound
,
test
)),
}
}
// Evaluate whether `sup_region: sub_region @ point`.
fn
eval_outlives
(
&
self
,
mir
:
&
Mir
<
'tcx
>
,
dfs_storage
:
&
mut
dfs
::
DfsStorage
,
_
mir
:
&
Mir
<
'tcx
>
,
sup_region
:
RegionVid
,
sub_region
:
RegionVid
,
point
:
Location
,
...
...
@@ -876,36 +841,43 @@ fn eval_outlives(
sup_region
,
sub_region
,
point
);
// Roughly speaking, do a DFS of all region elements reachable
// from `point` contained in `sub_region`. If any of those are
// *not* present in `sup_region`, the DFS will abort early and
// yield an `Err` result.
match
self
.dfs
(
mir
,
dfs_storage
,
TestTargetOutlivesSource
{
source_region
:
sub_region
,
target_region
:
sup_region
,
constraint_point
:
point
,
elements
:
&
self
.elements
,
universal_regions
:
&
self
.universal_regions
,
inferred_values
:
self
.inferred_values
.as_ref
()
.unwrap
(),
},
)
{
Ok
(
_
)
=>
{
debug!
(
"eval_outlives: true"
);
true
}
let
inferred_values
=
self
.inferred_values
.as_ref
()
.expect
(
"values for regions not yet inferred"
);
Err
(
elem
)
=>
{
debug!
(
"eval_outlives: false because `{:?}` is not present in `{:?}`"
,
self
.elements
.to_element
(
elem
),
sup_region
);
false
}
debug!
(
"eval_outlives: sup_region's value = {:?}"
,
inferred_values
.region_value_str
(
sup_region
),
);
debug!
(
"eval_outlives: sub_region's value = {:?}"
,
inferred_values
.region_value_str
(
sub_region
),
);
// Both the `sub_region` and `sup_region` consist of the union
// of some number of universal regions (along with the union
// of various points in the CFG; ignore those points for
// now). Therefore, the sup-region outlives the sub-region if,
// for each universal region R1 in the sub-region, there
// exists some region R2 in the sup-region that outlives R1.
let
universal_outlives
=
inferred_values
.universal_regions_outlived_by
(
sub_region
)
.all
(|
r1
|
{
inferred_values
.universal_regions_outlived_by
(
sup_region
)
.any
(|
r2
|
self
.universal_regions
.outlives
(
r2
,
r1
))
});
if
!
universal_outlives
{
return
false
;
}
// Now we have to compare all the points in the sub region and make
// sure they exist in the sup region.
if
self
.universal_regions
.is_universal_region
(
sup_region
)
{
// Micro-opt: universal regions contain all points.
return
true
;
}
inferred_values
.contains_points
(
sup_region
,
sub_region
)
}
/// Once regions have been propagated, this method is used to see
...
...
src/librustc_mir/borrow_check/nll/region_infer/values.rs
浏览文件 @
434d59a2
...
...
@@ -17,7 +17,6 @@
use
rustc
::
ty
::
RegionVid
;
use
std
::
fmt
::
Debug
;
use
std
::
rc
::
Rc
;
use
syntax
::
codemap
::
Span
;
use
super
::
Cause
;
...
...
@@ -74,11 +73,6 @@ pub(super) fn all_point_indices<'a>(&'a self) -> impl Iterator<Item = RegionElem
(
0
..
self
.num_points
)
.map
(
move
|
i
|
RegionElementIndex
::
new
(
i
+
self
.num_universal_regions
))
}
/// Iterates over the `RegionElementIndex` for all points in the CFG.
pub
(
super
)
fn
all_universal_region_indices
(
&
self
)
->
impl
Iterator
<
Item
=
RegionElementIndex
>
{
(
0
..
self
.num_universal_regions
)
.map
(
move
|
i
|
RegionElementIndex
::
new
(
i
))
}
/// Converts a particular `RegionElementIndex` to the `RegionElement` it represents.
pub
(
super
)
fn
to_element
(
&
self
,
i
:
RegionElementIndex
)
->
RegionElement
{
debug!
(
"to_element(i={:?})"
,
i
);
...
...
@@ -244,6 +238,12 @@ pub(super) fn add_element<E: ToElementIndex>(&mut self, r: RegionVid, elem: E, c
self
.add_internal
(
r
,
i
,
|
_
|
cause
.clone
())
}
/// Add all elements in `r_from` to `r_to` (because e.g. `r_to:
/// r_from`).
pub
(
super
)
fn
add_region
(
&
mut
self
,
r_to
:
RegionVid
,
r_from
:
RegionVid
)
->
bool
{
self
.matrix
.merge
(
r_from
,
r_to
)
}
/// Internal method to add an element to a region.
///
/// Takes a "lazy" cause -- this function will return the cause, but it will only
...
...
@@ -278,60 +278,22 @@ fn add_internal<F>(&mut self, r: RegionVid, i: RegionElementIndex, make_cause: F
}
}
/// Adds `elem` to `to_region` because of a relation:
///
/// to_region: from_region @ constraint_location
///
/// that was added by the cod at `constraint_span`.
pub
(
super
)
fn
add_due_to_outlives
<
T
:
ToElementIndex
>
(
&
mut
self
,
from_region
:
RegionVid
,
to_region
:
RegionVid
,
elem
:
T
,
_
constraint_location
:
Location
,
_
constraint_span
:
Span
,
)
->
bool
{
let
elem
=
self
.elements
.index
(
elem
);
self
.add_internal
(
to_region
,
elem
,
|
causes
|
causes
[
&
(
from_region
,
elem
)])
}
/// Adds all the universal regions outlived by `from_region` to
/// `to_region`.
pub
(
super
)
fn
add_universal_regions_outlived_by
(
&
mut
self
,
from_region
:
RegionVid
,
to_region
:
RegionVid
,
constraint_location
:
Location
,
constraint_span
:
Span
,
)
->
bool
{
// We could optimize this by improving `SparseBitMatrix::merge` so
// it does not always merge an entire row. That would
// complicate causal tracking though.
debug!
(
"add_universal_regions_outlived_by(from_region={:?}, to_region={:?})"
,
from_region
,
to_region
);
let
mut
changed
=
false
;
for
elem
in
self
.elements
.all_universal_region_indices
()
{
if
self
.contains
(
from_region
,
elem
)
{
changed
|
=
self
.add_due_to_outlives
(
from_region
,
to_region
,
elem
,
constraint_location
,
constraint_span
,
);
}
}
changed
}
/// True if the region `r` contains the given element.
pub
(
super
)
fn
contains
<
E
:
ToElementIndex
>
(
&
self
,
r
:
RegionVid
,
elem
:
E
)
->
bool
{
let
i
=
self
.elements
.index
(
elem
);
self
.matrix
.contains
(
r
,
i
)
}
/// True if `sup_region` contains all the CFG points that
/// `sub_region` contains. Ignores universal regions.
pub
(
super
)
fn
contains_points
(
&
self
,
sup_region
:
RegionVid
,
sub_region
:
RegionVid
)
->
bool
{
// This could be done faster by comparing the bitsets. But I
// am lazy.
self
.element_indices_contained_in
(
sub_region
)
.skip_while
(|
&
i
|
self
.elements
.to_universal_region
(
i
)
.is_some
())
.all
(|
e
|
self
.contains
(
sup_region
,
e
))
}
/// Iterate over the value of the region `r`, yielding up element
/// indices. You may prefer `universal_regions_outlived_by` or
/// `elements_contained_in`.
...
...
src/test/ui/nll/get_default.rs
浏览文件 @
434d59a2
...
...
@@ -30,8 +30,9 @@ fn ok(map: &mut Map) -> &String {
return
v
;
}
None
=>
{
map
.set
(
String
::
new
());
//
Just AST errors here
map
.set
(
String
::
new
());
//
Ideally, this would not error.
//~^ ERROR borrowed as immutable (Ast)
//~| ERROR borrowed as immutable (Mir)
}
}
}
...
...
@@ -47,8 +48,9 @@ fn err(map: &mut Map) -> &String {
return
v
;
}
None
=>
{
map
.set
(
String
::
new
());
//
Just AST errors
here
map
.set
(
String
::
new
());
//
Ideally, just AST would error
here
//~^ ERROR borrowed as immutable (Ast)
//~| ERROR borrowed as immutable (Mir)
}
}
}
...
...
src/test/ui/nll/get_default.stderr
浏览文件 @
434d59a2
...
...
@@ -4,14 +4,14 @@ error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as imm
LL | match map.get() {
| --- immutable borrow occurs here
...
LL | map.set(String::new()); //
Just AST errors here
LL | map.set(String::new()); //
Ideally, this would not error.
| ^^^ mutable borrow occurs here
...
LL | }
| - immutable borrow ends here
error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as immutable (Ast)
--> $DIR/get_default.rs:4
4
:17
--> $DIR/get_default.rs:4
5
:17
|
LL | match map.get() {
| --- immutable borrow occurs here
...
...
@@ -23,19 +23,61 @@ LL | }
| - immutable borrow ends here
error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as immutable (Ast)
--> $DIR/get_default.rs:5
0
:17
--> $DIR/get_default.rs:5
1
:17
|
LL | match map.get() {
| --- immutable borrow occurs here
...
LL | map.set(String::new()); //
Just AST errors
here
LL | map.set(String::new()); //
Ideally, just AST would error
here
| ^^^ mutable borrow occurs here
...
LL | }
| - immutable borrow ends here
error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as immutable (Mir)
--> $DIR/get_default.rs:44:17
--> $DIR/get_default.rs:33:17
|
LL | match map.get() {
| --- immutable borrow occurs here
...
LL | map.set(String::new()); // Ideally, this would not error.
| ^^^ mutable borrow occurs here
|
note: borrowed value must be valid for the anonymous lifetime #1 defined on the function body at 26:1...
--> $DIR/get_default.rs:26:1
|
LL | / fn ok(map: &mut Map) -> &String {
LL | | loop {
LL | | match map.get() {
LL | | Some(v) => {
... |
LL | | }
LL | | }
| |_^
error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as immutable (Mir)
--> $DIR/get_default.rs:51:17
|
LL | match map.get() {
| --- immutable borrow occurs here
...
LL | map.set(String::new()); // Ideally, just AST would error here
| ^^^ mutable borrow occurs here
|
note: borrowed value must be valid for the anonymous lifetime #1 defined on the function body at 41:1...
--> $DIR/get_default.rs:41:1
|
LL | / fn err(map: &mut Map) -> &String {
LL | | loop {
LL | | match map.get() {
LL | | Some(v) => {
... |
LL | | }
LL | | }
| |_^
error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as immutable (Mir)
--> $DIR/get_default.rs:45:17
|
LL | match map.get() {
| --- immutable borrow occurs here
...
...
@@ -46,6 +88,6 @@ LL | map.set(String::new()); // Both AST and MIR error here
LL | return v;
| - borrow later used here
error: aborting due to
4
previous errors
error: aborting due to
6
previous errors
For more information about this error, try `rustc --explain E0502`.
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录