Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
int
Rust
提交
60cc00f5
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,发现更多精彩内容 >>
提交
60cc00f5
编写于
11月 22, 2020
作者:
N
Niko Matsakis
提交者:
Mark Rousskov
8月 20, 2021
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
move `fallback_if_possible` and friends to fallback.rs
Along the way, simplify and document the logic more clearly.
上级
faf84263
变更
5
隐藏空白更改
内联
并排
Showing
5 changed file
with
127 addition
and
125 deletion
+127
-125
compiler/rustc_infer/src/infer/mod.rs
compiler/rustc_infer/src/infer/mod.rs
+18
-23
compiler/rustc_middle/src/ty/error.rs
compiler/rustc_middle/src/ty/error.rs
+0
-6
compiler/rustc_typeck/src/check/fallback.rs
compiler/rustc_typeck/src/check/fallback.rs
+108
-3
compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
+1
-83
compiler/rustc_typeck/src/check/mod.rs
compiler/rustc_typeck/src/check/mod.rs
+0
-10
未找到文件。
compiler/rustc_infer/src/infer/mod.rs
浏览文件 @
60cc00f5
...
...
@@ -23,7 +23,7 @@
use
rustc_middle
::
infer
::
unify_key
::{
ConstVariableOrigin
,
ConstVariableOriginKind
,
ToType
};
use
rustc_middle
::
mir
::
interpret
::
EvalToConstValueResult
;
use
rustc_middle
::
traits
::
select
;
use
rustc_middle
::
ty
::
error
::{
ExpectedFound
,
TypeError
,
UnconstrainedNumeric
};
use
rustc_middle
::
ty
::
error
::{
ExpectedFound
,
TypeError
};
use
rustc_middle
::
ty
::
fold
::{
TypeFoldable
,
TypeFolder
};
use
rustc_middle
::
ty
::
relate
::
RelateResult
;
use
rustc_middle
::
ty
::
subst
::{
GenericArg
,
GenericArgKind
,
InternalSubsts
,
SubstsRef
};
...
...
@@ -679,6 +679,10 @@ pub fn freshen<T: TypeFoldable<'tcx>>(&self, t: T) -> T {
t
.fold_with
(
&
mut
self
.freshener
())
}
/// Returns whether `ty` is a diverging type variable or not.
/// (If `ty` is not a type variable at all, returns not diverging.)
///
/// No attempt is made to resolve `ty`.
pub
fn
type_var_diverges
(
&
'a
self
,
ty
:
Ty
<
'_
>
)
->
Diverging
{
match
*
ty
.kind
()
{
ty
::
Infer
(
ty
::
TyVar
(
vid
))
=>
self
.inner
.borrow_mut
()
.type_variables
()
.var_diverges
(
vid
),
...
...
@@ -686,6 +690,19 @@ pub fn type_var_diverges(&'a self, ty: Ty<'_>) -> Diverging {
}
}
/// Returns the origin of the type variable identified by `vid`, or `None`
/// if this is not a type variable.
///
/// No attempt is made to resolve `ty`.
pub
fn
type_var_origin
(
&
'a
self
,
ty
:
Ty
<
'tcx
>
)
->
Option
<
TypeVariableOrigin
>
{
match
*
ty
.kind
()
{
ty
::
Infer
(
ty
::
TyVar
(
vid
))
=>
{
Some
(
*
self
.inner
.borrow_mut
()
.type_variables
()
.var_origin
(
vid
))
}
_
=>
None
,
}
}
pub
fn
freshener
<
'b
>
(
&
'b
self
)
->
TypeFreshener
<
'b
,
'tcx
>
{
freshen
::
TypeFreshener
::
new
(
self
,
false
)
}
...
...
@@ -695,28 +712,6 @@ pub fn freshener_keep_static<'b>(&'b self) -> TypeFreshener<'b, 'tcx> {
freshen
::
TypeFreshener
::
new
(
self
,
true
)
}
pub
fn
type_is_unconstrained_numeric
(
&
'a
self
,
ty
:
Ty
<
'_
>
)
->
UnconstrainedNumeric
{
use
rustc_middle
::
ty
::
error
::
UnconstrainedNumeric
::
Neither
;
use
rustc_middle
::
ty
::
error
::
UnconstrainedNumeric
::{
UnconstrainedFloat
,
UnconstrainedInt
};
match
*
ty
.kind
()
{
ty
::
Infer
(
ty
::
IntVar
(
vid
))
=>
{
if
self
.inner
.borrow_mut
()
.int_unification_table
()
.probe_value
(
vid
)
.is_some
()
{
Neither
}
else
{
UnconstrainedInt
}
}
ty
::
Infer
(
ty
::
FloatVar
(
vid
))
=>
{
if
self
.inner
.borrow_mut
()
.float_unification_table
()
.probe_value
(
vid
)
.is_some
()
{
Neither
}
else
{
UnconstrainedFloat
}
}
_
=>
Neither
,
}
}
pub
fn
unsolved_variables
(
&
self
)
->
Vec
<
Ty
<
'tcx
>>
{
let
mut
inner
=
self
.inner
.borrow_mut
();
let
mut
vars
:
Vec
<
Ty
<
'_
>>
=
inner
...
...
compiler/rustc_middle/src/ty/error.rs
浏览文件 @
60cc00f5
...
...
@@ -71,12 +71,6 @@ pub enum TypeError<'tcx> {
TargetFeatureCast
(
DefId
),
}
pub
enum
UnconstrainedNumeric
{
UnconstrainedFloat
,
UnconstrainedInt
,
Neither
,
}
/// Explains the source of a type err in a short, human readable way. This is meant to be placed
/// in parentheses after some larger message. You should also invoke `note_and_explain_type_err()`
/// afterwards to present additional details, particularly when it comes to lifetime-related
...
...
compiler/rustc_typeck/src/check/fallback.rs
浏览文件 @
60cc00f5
use
crate
::
check
::
FallbackMode
;
use
crate
::
check
::
FnCtxt
;
use
rustc_infer
::
infer
::
type_variable
::
Diverging
;
use
rustc_middle
::
ty
::{
self
,
Ty
};
impl
<
'tcx
>
FnCtxt
<
'_
,
'tcx
>
{
pub
(
super
)
fn
type_inference_fallback
(
&
self
)
{
...
...
@@ -12,8 +13,9 @@ pub(super) fn type_inference_fallback(&self) {
// The first time, we do *not* replace opaque types.
for
ty
in
&
self
.unsolved_variables
()
{
debug!
(
"unsolved_variable = {:?}"
,
ty
);
fallback_has_occurred
|
=
self
.fallback_if_possible
(
ty
,
FallbackMode
::
NoOpaque
);
fallback_has_occurred
|
=
self
.fallback_if_possible
(
ty
);
}
// We now see if we can make progress. This might
// cause us to unify inference variables for opaque types,
// since we may have unified some other type variables
...
...
@@ -43,10 +45,113 @@ pub(super) fn type_inference_fallback(&self) {
// unconstrained opaque type variables, in addition to performing
// other kinds of fallback.
for
ty
in
&
self
.unsolved_variables
()
{
fallback_has_occurred
|
=
self
.fallback_
if_possible
(
ty
,
FallbackMode
::
All
);
fallback_has_occurred
|
=
self
.fallback_
opaque_type_vars
(
ty
);
}
// See if we can make any more progress.
self
.select_obligations_where_possible
(
fallback_has_occurred
,
|
_
|
{});
}
// Tries to apply a fallback to `ty` if it is an unsolved variable.
//
// - Unconstrained ints are replaced with `i32`.
//
// - Unconstrained floats are replaced with with `f64`.
//
// - Non-numerics get replaced with `!` when `#![feature(never_type_fallback)]`
// is enabled. Otherwise, they are replaced with `()`.
//
// Fallback becomes very dubious if we have encountered type-checking errors.
// In that case, fallback to Error.
// The return value indicates whether fallback has occurred.
fn
fallback_if_possible
(
&
self
,
ty
:
Ty
<
'tcx
>
)
->
bool
{
// Careful: we do NOT shallow-resolve `ty`. We know that `ty`
// is an unsolved variable, and we determine its fallback based
// solely on how it was created, not what other type variables
// it may have been unified with since then.
//
// The reason this matters is that other attempts at fallback may
// (in principle) conflict with this fallback, and we wish to generate
// a type error in that case. (However, this actually isn't true right now,
// because we're only using the builtin fallback rules. This would be
// true if we were using user-supplied fallbacks. But it's still useful
// to write the code to detect bugs.)
//
// (Note though that if we have a general type variable `?T` that is then unified
// with an integer type variable `?I` that ultimately never gets
// resolved to a special integral type, `?T` is not considered unsolved,
// but `?I` is. The same is true for float variables.)
let
fallback
=
match
ty
.kind
()
{
_
if
self
.is_tainted_by_errors
()
=>
self
.tcx
.ty_error
(),
ty
::
Infer
(
ty
::
IntVar
(
_
))
=>
self
.tcx.types.i32
,
ty
::
Infer
(
ty
::
FloatVar
(
_
))
=>
self
.tcx.types.f64
,
_
=>
match
self
.type_var_diverges
(
ty
)
{
Diverging
::
Diverges
=>
self
.tcx
.mk_diverging_default
(),
Diverging
::
NotDiverging
=>
return
false
,
},
};
debug!
(
"fallback_if_possible(ty={:?}): defaulting to `{:?}`"
,
ty
,
fallback
);
let
span
=
self
.infcx
.type_var_origin
(
ty
)
.map
(|
origin
|
origin
.span
)
.unwrap_or
(
rustc_span
::
DUMMY_SP
);
self
.demand_eqtype
(
span
,
ty
,
fallback
);
true
}
/// Second round of fallback: Unconstrained type variables
/// created from the instantiation of an opaque
/// type fall back to the opaque type itself. This is a
/// somewhat incomplete attempt to manage "identity passthrough"
/// for `impl Trait` types.
///
/// For example, in this code:
///
///```
/// type MyType = impl Copy;
/// fn defining_use() -> MyType { true }
/// fn other_use() -> MyType { defining_use() }
/// ```
///
/// `defining_use` will constrain the instantiated inference
/// variable to `bool`, while `other_use` will constrain
/// the instantiated inference variable to `MyType`.
///
/// When we process opaque types during writeback, we
/// will handle cases like `other_use`, and not count
/// them as defining usages
///
/// However, we also need to handle cases like this:
///
/// ```rust
/// pub type Foo = impl Copy;
/// fn produce() -> Option<Foo> {
/// None
/// }
/// ```
///
/// In the above snippet, the inference variable created by
/// instantiating `Option<Foo>` will be completely unconstrained.
/// We treat this as a non-defining use by making the inference
/// variable fall back to the opaque type itself.
fn
fallback_opaque_type_vars
(
&
self
,
ty
:
Ty
<
'tcx
>
)
->
bool
{
let
span
=
self
.infcx
.type_var_origin
(
ty
)
.map
(|
origin
|
origin
.span
)
.unwrap_or
(
rustc_span
::
DUMMY_SP
);
let
oty
=
self
.inner
.borrow
()
.opaque_types_vars
.get
(
ty
)
.map
(|
v
|
*
v
);
if
let
Some
(
opaque_ty
)
=
oty
{
debug!
(
"fallback_opaque_type_vars(ty={:?}): falling back to opaque type {:?}"
,
ty
,
opaque_ty
);
self
.demand_eqtype
(
span
,
ty
,
opaque_ty
);
true
}
else
{
return
false
;
}
}
}
compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
浏览文件 @
60cc00f5
...
...
@@ -4,7 +4,7 @@
};
use
crate
::
check
::
callee
::{
self
,
DeferredCallResolution
};
use
crate
::
check
::
method
::{
self
,
MethodCallee
,
SelfSource
};
use
crate
::
check
::{
BreakableCtxt
,
Diverges
,
Expectation
,
F
allbackMode
,
F
nCtxt
,
LocalTy
};
use
crate
::
check
::{
BreakableCtxt
,
Diverges
,
Expectation
,
FnCtxt
,
LocalTy
};
use
rustc_ast
::
TraitObjectSyntax
;
use
rustc_data_structures
::
captures
::
Captures
;
...
...
@@ -17,7 +17,6 @@
use
rustc_hir
::{
ExprKind
,
GenericArg
,
Node
,
QPath
,
TyKind
};
use
rustc_infer
::
infer
::
canonical
::{
Canonical
,
OriginalQueryValues
,
QueryResponse
};
use
rustc_infer
::
infer
::
error_reporting
::
TypeAnnotationNeeded
::
E0282
;
use
rustc_infer
::
infer
::
type_variable
::
Diverging
;
use
rustc_infer
::
infer
::{
InferOk
,
InferResult
};
use
rustc_middle
::
ty
::
adjustment
::{
Adjust
,
Adjustment
,
AutoBorrow
,
AutoBorrowMutability
};
use
rustc_middle
::
ty
::
fold
::
TypeFoldable
;
...
...
@@ -636,87 +635,6 @@ pub(in super::super) fn resolve_generator_interiors(&self, def_id: DefId) {
}
}
// Tries to apply a fallback to `ty` if it is an unsolved variable.
//
// - Unconstrained ints are replaced with `i32`.
//
// - Unconstrained floats are replaced with with `f64`.
//
// - Non-numerics get replaced with `!` when `#![feature(never_type_fallback)]`
// is enabled. Otherwise, they are replaced with `()`.
//
// Fallback becomes very dubious if we have encountered type-checking errors.
// In that case, fallback to Error.
// The return value indicates whether fallback has occurred.
pub
(
in
super
::
super
)
fn
fallback_if_possible
(
&
self
,
ty
:
Ty
<
'tcx
>
,
mode
:
FallbackMode
)
->
bool
{
use
rustc_middle
::
ty
::
error
::
UnconstrainedNumeric
::
Neither
;
use
rustc_middle
::
ty
::
error
::
UnconstrainedNumeric
::{
UnconstrainedFloat
,
UnconstrainedInt
};
assert
!
(
ty
.is_ty_infer
());
let
fallback
=
match
self
.type_is_unconstrained_numeric
(
ty
)
{
_
if
self
.is_tainted_by_errors
()
=>
self
.tcx
()
.ty_error
(),
UnconstrainedInt
=>
self
.tcx.types.i32
,
UnconstrainedFloat
=>
self
.tcx.types.f64
,
Neither
=>
match
self
.type_var_diverges
(
ty
)
{
Diverging
::
Diverges
=>
self
.tcx
.mk_diverging_default
(),
Diverging
::
NotDiverging
=>
{
// This type variable was created from the instantiation of an opaque
// type. The fact that we're attempting to perform fallback for it
// means that the function neither constrained it to a concrete
// type, nor to the opaque type itself.
//
// For example, in this code:
//
//```
// type MyType = impl Copy;
// fn defining_use() -> MyType { true }
// fn other_use() -> MyType { defining_use() }
// ```
//
// `defining_use` will constrain the instantiated inference
// variable to `bool`, while `other_use` will constrain
// the instantiated inference variable to `MyType`.
//
// When we process opaque types during writeback, we
// will handle cases like `other_use`, and not count
// them as defining usages
//
// However, we also need to handle cases like this:
//
// ```rust
// pub type Foo = impl Copy;
// fn produce() -> Option<Foo> {
// None
// }
// ```
//
// In the above snippet, the inference variable created by
// instantiating `Option<Foo>` will be completely unconstrained.
// We treat this as a non-defining use by making the inference
// variable fall back to the opaque type itself.
if
let
FallbackMode
::
All
=
mode
{
if
let
Some
(
opaque_ty
)
=
self
.infcx.inner
.borrow
()
.opaque_types_vars
.get
(
ty
)
{
debug!
(
"fallback_if_possible: falling back opaque type var {:?} to {:?}"
,
ty
,
opaque_ty
);
*
opaque_ty
}
else
{
return
false
;
}
}
else
{
return
false
;
}
}
},
};
debug!
(
"fallback_if_possible: defaulting `{:?}` to `{:?}`"
,
ty
,
fallback
);
self
.demand_eqtype
(
rustc_span
::
DUMMY_SP
,
ty
,
fallback
);
true
}
pub
(
in
super
::
super
)
fn
select_all_obligations_or_error
(
&
self
)
{
debug!
(
"select_all_obligations_or_error"
);
if
let
Err
(
errors
)
=
self
...
...
compiler/rustc_typeck/src/check/mod.rs
浏览文件 @
60cc00f5
...
...
@@ -872,16 +872,6 @@ enum TupleArgumentsFlag {
TupleArguments
,
}
/// Controls how we perform fallback for unconstrained
/// type variables.
enum
FallbackMode
{
/// Do not fallback type variables to opaque types.
NoOpaque
,
/// Perform all possible kinds of fallback, including
/// turning type variables to opaque types.
All
,
}
/// A wrapper for `InferCtxt`'s `in_progress_typeck_results` field.
#[derive(Copy,
Clone)]
struct
MaybeInProgressTables
<
'a
,
'tcx
>
{
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录