Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
int
Rust
提交
46eb7245
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,发现更多精彩内容 >>
提交
46eb7245
编写于
12月 12, 2014
作者:
N
Nick Cameron
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Propagate coercions through match expressions.
上级
22a9f250
变更
4
隐藏空白更改
内联
并排
Showing
4 changed file
with
81 addition
and
38 deletion
+81
-38
src/librustc_typeck/check/_match.rs
src/librustc_typeck/check/_match.rs
+23
-7
src/librustc_typeck/check/mod.rs
src/librustc_typeck/check/mod.rs
+35
-29
src/test/compile-fail/lub-match.rs
src/test/compile-fail/lub-match.rs
+2
-2
src/test/run-pass/coerce-match.rs
src/test/run-pass/coerce-match.rs
+21
-0
未找到文件。
src/librustc_typeck/check/_match.rs
浏览文件 @
46eb7245
...
...
@@ -13,7 +13,8 @@
use
middle
::
pat_util
::{
PatIdMap
,
pat_id_map
,
pat_is_binding
,
pat_is_const
};
use
middle
::
subst
::{
Subst
,
Substs
};
use
middle
::
ty
::{
mod
,
Ty
};
use
check
::{
check_expr
,
check_expr_has_type
,
demand
,
FnCtxt
};
use
check
::{
check_expr
,
check_expr_has_type
,
check_expr_with_expectation
};
use
check
::{
check_expr_coercable_to_type
,
demand
,
FnCtxt
,
Expectation
};
use
check
::{
instantiate_path
,
structurally_resolved_type
,
valid_range_bounds
};
use
require_same_types
;
use
util
::
nodemap
::
FnvHashMap
;
...
...
@@ -233,10 +234,11 @@ pub fn check_dereferencable<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
}
}
pub
fn
check_match
(
fcx
:
&
FnCtxt
,
expr
:
&
ast
::
Expr
,
discrim
:
&
ast
::
Expr
,
arms
:
&
[
ast
::
Arm
])
{
pub
fn
check_match
<
'a
,
'tcx
>
(
fcx
:
&
FnCtxt
<
'a
,
'tcx
>
,
expr
:
&
ast
::
Expr
,
discrim
:
&
ast
::
Expr
,
arms
:
&
[
ast
::
Arm
],
expected
:
Expectation
<
'tcx
>
)
{
let
tcx
=
fcx
.ccx.tcx
;
let
discrim_ty
=
fcx
.infcx
()
.next_ty_var
();
...
...
@@ -263,9 +265,23 @@ pub fn check_match(fcx: &FnCtxt,
// on any empty type and is therefore unreachable; should the flow
// of execution reach it, we will panic, so bottom is an appropriate
// type in that case)
let
expected
=
expected
.adjust_for_branches
(
fcx
);
let
result_ty
=
arms
.iter
()
.fold
(
fcx
.infcx
()
.next_diverging_ty_var
(),
|
result_ty
,
arm
|
{
check_expr
(
fcx
,
&*
arm
.body
);
let
bty
=
fcx
.node_ty
(
arm
.body.id
);
let
bty
=
match
expected
{
// We don't coerce to `()` so that if the match expression is a
// statement it's branches can have any consistent type. That allows
// us to give better error messages (pointing to a usually better
// arm for inconsistent arms or to the whole match when a `()` type
// is required).
Expectation
::
ExpectHasType
(
ety
)
if
ety
!=
ty
::
mk_nil
(
fcx
.tcx
())
=>
{
check_expr_coercable_to_type
(
fcx
,
&*
arm
.body
,
ety
);
ety
}
_
=>
{
check_expr_with_expectation
(
fcx
,
&*
arm
.body
,
expected
);
fcx
.node_ty
(
arm
.body.id
)
}
};
if
let
Some
(
ref
e
)
=
arm
.guard
{
check_expr_has_type
(
fcx
,
&**
e
,
ty
::
mk_bool
());
...
...
src/librustc_typeck/check/mod.rs
浏览文件 @
46eb7245
...
...
@@ -179,6 +179,38 @@ enum Expectation<'tcx> {
impl
<
'tcx
>
Copy
for
Expectation
<
'tcx
>
{}
impl
<
'tcx
>
Expectation
<
'tcx
>
{
// Disregard "castable to" expectations because they
// can lead us astray. Consider for example `if cond
// {22} else {c} as u8` -- if we propagate the
// "castable to u8" constraint to 22, it will pick the
// type 22u8, which is overly constrained (c might not
// be a u8). In effect, the problem is that the
// "castable to" expectation is not the tightest thing
// we can say, so we want to drop it in this case.
// The tightest thing we can say is "must unify with
// else branch". Note that in the case of a "has type"
// constraint, this limitation does not hold.
// If the expected type is just a type variable, then don't use
// an expected type. Otherwise, we might write parts of the type
// when checking the 'then' block which are incompatible with the
// 'else' branch.
fn
adjust_for_branches
<
'a
>
(
&
self
,
fcx
:
&
FnCtxt
<
'a
,
'tcx
>
)
->
Expectation
<
'tcx
>
{
match
self
.only_has_type
()
{
ExpectHasType
(
ety
)
=>
{
let
ety
=
fcx
.infcx
()
.shallow_resolve
(
ety
);
if
!
ty
::
type_is_ty_var
(
ety
)
{
ExpectHasType
(
ety
)
}
else
{
NoExpectation
}
}
_
=>
NoExpectation
}
}
}
#[deriving(Copy,
Clone)]
pub
struct
UnsafetyState
{
pub
def
:
ast
::
NodeId
,
...
...
@@ -3047,7 +3079,7 @@ fn check_method_call(fcx: &FnCtxt,
}
// A generic function for checking the then and else in an if
// or if-
check
// or if-
else.
fn
check_then_else
<
'a
,
'tcx
>
(
fcx
:
&
FnCtxt
<
'a
,
'tcx
>
,
cond_expr
:
&
ast
::
Expr
,
then_blk
:
&
ast
::
Block
,
...
...
@@ -3057,33 +3089,7 @@ fn check_then_else<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
expected
:
Expectation
<
'tcx
>
)
{
check_expr_has_type
(
fcx
,
cond_expr
,
ty
::
mk_bool
());
// Disregard "castable to" expectations because they
// can lead us astray. Consider for example `if cond
// {22} else {c} as u8` -- if we propagate the
// "castable to u8" constraint to 22, it will pick the
// type 22u8, which is overly constrained (c might not
// be a u8). In effect, the problem is that the
// "castable to" expectation is not the tightest thing
// we can say, so we want to drop it in this case.
// The tightest thing we can say is "must unify with
// else branch". Note that in the case of a "has type"
// constraint, this limitation does not hold.
// If the expected type is just a type variable, then don't use
// an expected type. Otherwise, we might write parts of the type
// when checking the 'then' block which are incompatible with the
// 'else' branch.
let
expected
=
match
expected
.only_has_type
()
{
ExpectHasType
(
ety
)
=>
{
let
ety
=
fcx
.infcx
()
.shallow_resolve
(
ety
);
if
!
ty
::
type_is_ty_var
(
ety
)
{
ExpectHasType
(
ety
)
}
else
{
NoExpectation
}
}
_
=>
NoExpectation
};
let
expected
=
expected
.adjust_for_branches
(
fcx
);
check_block_with_expected
(
fcx
,
then_blk
,
expected
);
let
then_ty
=
fcx
.node_ty
(
then_blk
.id
);
...
...
@@ -3989,7 +3995,7 @@ fn check_struct_fields_on_error(fcx: &FnCtxt,
}
}
ast
::
ExprMatch
(
ref
discrim
,
ref
arms
,
_
)
=>
{
_
match
::
check_match
(
fcx
,
expr
,
&**
discrim
,
arms
.as_slice
());
_
match
::
check_match
(
fcx
,
expr
,
&**
discrim
,
arms
.as_slice
()
,
expected
);
}
ast
::
ExprClosure
(
_
,
opt_kind
,
ref
decl
,
ref
body
)
=>
{
closure
::
check_expr_closure
(
fcx
,
expr
,
opt_kind
,
&**
decl
,
&**
body
,
expected
);
...
...
src/test/compile-fail/lub-match.rs
浏览文件 @
46eb7245
...
...
@@ -34,21 +34,21 @@ pub fn opt_str1<'a>(maybestr: &'a Option<String>) -> &'a str {
pub
fn
opt_str2
<
'a
>
(
maybestr
:
&
'a
Option
<
String
>
)
->
&
'static
str
{
match
*
maybestr
{
//~^ ERROR cannot infer an appropriate lifetime due to conflicting requirements
None
=>
"(none)"
,
Some
(
ref
s
)
=>
{
let
s
:
&
'a
str
=
s
.as_slice
();
s
//~^ ERROR cannot infer an appropriate lifetime
}
}
}
pub
fn
opt_str3
<
'a
>
(
maybestr
:
&
'a
Option
<
String
>
)
->
&
'static
str
{
match
*
maybestr
{
//~^ ERROR cannot infer an appropriate lifetime due to conflicting requirements
Some
(
ref
s
)
=>
{
let
s
:
&
'a
str
=
s
.as_slice
();
s
//~^ ERROR cannot infer an appropriate lifetime
}
None
=>
"(none)"
,
}
...
...
src/test/run-pass/coerce-match.rs
0 → 100644
浏览文件 @
46eb7245
// Copyright 2014 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.
// Check that coercions are propagated through match and if expressions.
pub
fn
main
()
{
let
_
:
Box
<
[
int
]
>
=
if
true
{
box
[
1
i
,
2
,
3
]
}
else
{
box
[
1
i
]
};
let
_
:
Box
<
[
int
]
>
=
match
true
{
true
=>
box
[
1
i
,
2
,
3
],
false
=>
box
[
1
i
]
};
// Check we don't get over-keen at propagating coercions in the case of casts.
let
x
=
if
true
{
42
}
else
{
42u8
}
as
u16
;
let
x
=
match
true
{
true
=>
42
,
false
=>
42u8
}
as
u16
;
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录