Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
int
Rust
提交
35d6efb2
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,发现更多精彩内容 >>
提交
35d6efb2
编写于
2月 01, 2016
作者:
N
Niko Matsakis
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Use the per-tree state to detect and permit DAGs (but not cyclic graphs)
上级
37815fde
变更
1
隐藏空白更改
内联
并排
Showing
1 changed file
with
80 addition
and
41 deletion
+80
-41
src/librustc/middle/traits/fulfill.rs
src/librustc/middle/traits/fulfill.rs
+80
-41
未找到文件。
src/librustc/middle/traits/fulfill.rs
浏览文件 @
35d6efb2
...
...
@@ -36,6 +36,7 @@ pub struct GlobalFulfilledPredicates<'tcx> {
dep_graph
:
DepGraph
,
}
#[derive(Debug)]
pub
struct
LocalFulfilledPredicates
<
'tcx
>
{
set
:
FnvHashSet
<
ty
::
Predicate
<
'tcx
>>
}
...
...
@@ -66,7 +67,8 @@ pub struct FulfillmentContext<'tcx> {
// A list of all obligations that have been registered with this
// fulfillment context.
predicates
:
ObligationForest
<
PendingPredicateObligation
<
'tcx
>
,
()
>
,
predicates
:
ObligationForest
<
PendingPredicateObligation
<
'tcx
>
,
LocalFulfilledPredicates
<
'tcx
>>
,
// A set of constraints that regionck must validate. Each
// constraint has the form `T:'a`, meaning "some type `T` must
...
...
@@ -192,7 +194,7 @@ pub fn register_predicate_obligation<'a>(&mut self,
obligation
:
obligation
,
stalled_on
:
vec!
[]
};
self
.predicates
.push_tree
(
obligation
,
());
self
.predicates
.push_tree
(
obligation
,
LocalFulfilledPredicates
::
new
());
}
pub
fn
region_obligations
(
&
self
,
...
...
@@ -278,7 +280,8 @@ fn select<'a>(&mut self,
let
outcome
=
{
let
region_obligations
=
&
mut
self
.region_obligations
;
self
.predicates
.process_obligations
(
|
obligation
,
_
tree
,
backtrace
|
process_predicate
(
selcx
,
|
obligation
,
tree
,
backtrace
|
process_predicate
(
selcx
,
tree
,
obligation
,
backtrace
,
region_obligations
))
...
...
@@ -315,61 +318,97 @@ fn select<'a>(&mut self,
/// Like `process_predicate1`, but wrap result into a pending predicate.
fn
process_predicate
<
'a
,
'tcx
>
(
selcx
:
&
mut
SelectionContext
<
'a
,
'tcx
>
,
tree_cache
:
&
mut
LocalFulfilledPredicates
<
'tcx
>
,
pending_obligation
:
&
mut
PendingPredicateObligation
<
'tcx
>
,
backtrace
:
Backtrace
<
PendingPredicateObligation
<
'tcx
>>
,
mut
backtrace
:
Backtrace
<
PendingPredicateObligation
<
'tcx
>>
,
region_obligations
:
&
mut
NodeMap
<
Vec
<
RegionObligation
<
'tcx
>>>
)
->
Result
<
Option
<
Vec
<
PendingPredicateObligation
<
'tcx
>>>
,
FulfillmentErrorCode
<
'tcx
>>
{
match
process_predicate1
(
selcx
,
pending_obligation
,
backtrace
,
region_obligations
)
{
match
process_predicate1
(
selcx
,
pending_obligation
,
backtrace
.clone
()
,
region_obligations
)
{
Ok
(
Some
(
v
))
=>
{
// FIXME(#30977) the right thing to do here, I think, is to permit
// DAGs. That is, we should detect whenever this predicate
// has appeared somewhere in the current tree./ If it's a
// parent, that's a cycle, and we should either error out
// or consider it ok. But if it's NOT a parent, we can
// ignore it, since it will be proven (or not) separately.
// However, this is a touch tricky, so I'm doing something
// a bit hackier for now so that the `huge-struct.rs` passes.
// FIXME(#30977) The code below is designed to detect (and
// permit) DAGs, while still ensuring that the reasoning
// is acyclic. However, it does a few things
// suboptimally. For example, it refreshes type variables
// a lot, probably more than needed, but also less than
// you might want.
//
// - more than needed: I want to be very sure we don't
// accidentally treat a cycle as a DAG, so I am
// refreshing type variables as we walk the ancestors;
// but we are going to repeat this a lot, which is
// sort of silly, and it would be nicer to refresh
// them *in place* so that later predicate processing
// can benefit from the same work;
// - less than you might want: we only add items in the cache here,
// but maybe we learn more about type variables and could add them into
// the cache later on.
let
tcx
=
selcx
.tcx
();
let
retain_vec
:
Vec
<
_
>
=
{
let
mut
dedup
=
FnvHashSet
();
v
.iter
()
.map
(|
o
|
{
// Compute a little FnvHashSet for the ancestors. We only
// do this the first time that we care.
let
mut
cache
=
None
;
let
mut
is_ancestor
=
|
predicate
:
&
ty
::
Predicate
<
'tcx
>
|
{
if
cache
.is_none
()
{
let
mut
c
=
FnvHashSet
();
for
ancestor
in
backtrace
.by_ref
()
{
// Ugh. This just feels ridiculously
// inefficient. But we need to compare
// predicates without being concerned about
// the vagaries of type inference, so for now
// just ensure that they are always
// up-to-date. (I suppose we could just use a
// snapshot and check if they are unifiable?)
let
resolved_predicate
=
selcx
.infcx
()
.resolve_type_vars_if_possible
(
&
ancestor
.obligation.predicate
);
c
.insert
(
resolved_predicate
);
}
cache
=
Some
(
c
);
}
cache
.as_ref
()
.unwrap
()
.contains
(
predicate
)
};
let
pending_predicate_obligations
:
Vec
<
_
>
=
v
.into_iter
()
.filter_map
(|
obligation
|
{
// Probably silly, but remove any inference
// variables. This is actually crucial to the
// ancestor check below, but it's not clear that
// it makes sense to ALWAYS do it.
let
obligation
=
selcx
.infcx
()
.resolve_type_vars_if_possible
(
&
obligation
);
// Screen out obligations that we know globally
// are true. This should really be the DAG check
// mentioned above.
if
tcx
.fulfilled_predicates
.borrow
()
.check_duplicate
(
&
o
.predicate
)
{
return
fals
e
;
if
tcx
.fulfilled_predicates
.borrow
()
.check_duplicate
(
&
o
bligation
.predicate
)
{
return
Non
e
;
}
// If we see two siblings that are exactly the
// same, no need to add them twice.
if
!
dedup
.insert
(
&
o
.predicate
)
{
return
false
;
// Check whether this obligation appears somewhere else in the tree.
if
tree_cache
.is_duplicate_or_add
(
&
obligation
.predicate
)
{
// If the obligation appears as a parent,
// allow it, because that is a cycle.
// Otherwise though we can just ignore
// it. Note that we have to be careful around
// inference variables here -- for the
// purposes of the ancestor check, we retain
// the invariant that all type variables are
// fully refreshed.
if
!
(
&
mut
is_ancestor
)(
&
obligation
.predicate
)
{
return
None
;
}
}
true
})
.collect
()
};
let
pending_predicate_obligations
=
v
.into_iter
()
.zip
(
retain_vec
)
.flat_map
(|(
o
,
retain
)|
{
if
retain
{
Some
(
PendingPredicateObligation
{
obligation
:
o
,
stalled_on
:
vec!
[]
})
}
else
{
None
}
Some
(
PendingPredicateObligation
{
obligation
:
obligation
,
stalled_on
:
vec!
[]
})
})
.collect
();
.collect
();
Ok
(
Some
(
pending_predicate_obligations
))
}
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录