Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
int
Rust
提交
253dfc33
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,发现更多精彩内容 >>
提交
253dfc33
编写于
8月 06, 2012
作者:
P
Patrick Walton
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
rustc: Implement pattern matching for structs
上级
5cb3a94b
变更
13
隐藏空白更改
内联
并排
Showing
13 changed file
with
445 addition
and
100 deletion
+445
-100
src/libsyntax/ast.rs
src/libsyntax/ast.rs
+1
-0
src/libsyntax/ast_util.rs
src/libsyntax/ast_util.rs
+2
-1
src/libsyntax/fold.rs
src/libsyntax/fold.rs
+10
-0
src/libsyntax/parse/parser.rs
src/libsyntax/parse/parser.rs
+128
-62
src/libsyntax/print/pprust.rs
src/libsyntax/print/pprust.rs
+18
-0
src/libsyntax/visit.rs
src/libsyntax/visit.rs
+6
-0
src/rustc/middle/borrowck/gather_loans.rs
src/rustc/middle/borrowck/gather_loans.rs
+8
-0
src/rustc/middle/check_alt.rs
src/rustc/middle/check_alt.rs
+37
-4
src/rustc/middle/resolve3.rs
src/rustc/middle/resolve3.rs
+29
-9
src/rustc/middle/trans/alt.rs
src/rustc/middle/trans/alt.rs
+94
-7
src/rustc/middle/trans/base.rs
src/rustc/middle/trans/base.rs
+18
-17
src/rustc/middle/typeck/check/alt.rs
src/rustc/middle/typeck/check/alt.rs
+80
-0
src/test/run-pass/struct-pattern-matching.rs
src/test/run-pass/struct-pattern-matching.rs
+14
-0
未找到文件。
src/libsyntax/ast.rs
浏览文件 @
253dfc33
...
...
@@ -166,6 +166,7 @@ enum pat_ {
pat_enum
(
@
path
,
option
<~
[
@
pat
]
>
),
// "none" means a * pattern where
// we don't bind the fields to names
pat_rec
(
~
[
field_pat
],
bool
),
pat_struct
(
@
path
,
~
[
field_pat
],
bool
),
pat_tup
(
~
[
@
pat
]),
pat_box
(
@
pat
),
pat_uniq
(
@
pat
),
...
...
src/libsyntax/ast_util.rs
浏览文件 @
253dfc33
...
...
@@ -602,7 +602,8 @@ fn walk_pat(pat: @pat, it: fn(@pat)) {
it
(
pat
);
match
pat
.node
{
pat_ident
(
_
,
pth
,
some
(
p
))
=>
walk_pat
(
p
,
it
),
pat_rec
(
fields
,
_
)
=>
for
fields
.each
|
f
|
{
walk_pat
(
f
.pat
,
it
)
}
pat_rec
(
fields
,
_
)
|
pat_struct
(
_
,
fields
,
_
)
=>
for
fields
.each
|
f
|
{
walk_pat
(
f
.pat
,
it
)
}
pat_enum
(
_
,
some
(
s
))
|
pat_tup
(
s
)
=>
for
s
.each
|
p
|
{
walk_pat
(
p
,
it
)
}
...
...
src/libsyntax/fold.rs
浏览文件 @
253dfc33
...
...
@@ -354,6 +354,16 @@ fn noop_fold_pat(p: pat_, fld: ast_fold) -> pat_ {
}
pat_rec
(
fs
,
etc
)
}
pat_struct
(
pth
,
fields
,
etc
)
=>
{
let
pth_
=
fld
.fold_path
(
pth
);
let
mut
fs
=
~
[];
for
fields
.each
|
f
|
{
vec
::
push
(
fs
,
{
ident
:
/* FIXME (#2543) */
copy
f
.ident
,
pat
:
fld
.fold_pat
(
f
.pat
)});
}
pat_struct
(
pth_
,
fs
,
etc
)
}
pat_tup
(
elts
)
=>
pat_tup
(
vec
::
map
(
elts
,
|
x
|
fld
.fold_pat
(
x
))),
pat_box
(
inner
)
=>
pat_box
(
fld
.fold_pat
(
inner
)),
pat_uniq
(
inner
)
=>
pat_uniq
(
fld
.fold_pat
(
inner
)),
...
...
src/libsyntax/parse/parser.rs
浏览文件 @
253dfc33
...
...
@@ -42,14 +42,14 @@
mac_ellipsis
,
mac_invoc
,
mac_invoc_tt
,
mac_var
,
matcher
,
match_nonterminal
,
match_seq
,
match_tok
,
method
,
mode
,
mt
,
mul
,
mutability
,
neg
,
noreturn
,
not
,
pat
,
pat_box
,
pat_enum
,
pat_ident
,
pat_lit
,
pat_range
,
pat_rec
,
pat_
tup
,
pat_uniq
,
pat_
wild
,
path
,
private
,
proto
,
proto_bare
,
proto_block
,
proto_b
ox
,
proto_uniq
,
provided
,
public
,
pure_fn
,
purity
,
re_anon
,
re_named
,
region
,
rem
,
required
,
ret_style
,
return_val
,
self_ty
,
shl
,
shr
,
stmt
,
stmt_decl
,
stmt_expr
,
stmt_semi
,
s
ubtract
,
sty_box
,
sty_by_ref
,
sty_region
,
sty_uniq
,
sty_value
,
token_tree
,
trait_method
,
trait_ref
,
tt_delim
,
tt_seq
,
tt_tok
,
tt_nonterminal
,
ty
,
ty_
,
ty_bot
,
ty_box
,
ty_field
,
ty_fn
,
pat_ident
,
pat_lit
,
pat_range
,
pat_rec
,
pat_
struct
,
pat_tup
,
pat_
uniq
,
pat_wild
,
path
,
private
,
proto
,
proto_bare
,
proto_b
lock
,
proto_box
,
proto_uniq
,
provided
,
public
,
pure_fn
,
purity
,
re_anon
,
re_named
,
region
,
rem
,
required
,
ret_style
,
return_val
,
self_ty
,
shl
,
shr
,
stmt
,
stmt_decl
,
stmt_expr
,
s
tmt_semi
,
subtract
,
sty_box
,
sty_by_ref
,
sty_region
,
sty_uniq
,
sty_value
,
token_tree
,
trait_method
,
trait_ref
,
tt_delim
,
tt_seq
,
tt_
tok
,
tt_
nonterminal
,
ty
,
ty_
,
ty_bot
,
ty_box
,
ty_field
,
ty_fn
,
ty_infer
,
ty_mac
,
ty_method
,
ty_nil
,
ty_param
,
ty_path
,
ty_ptr
,
ty_rec
,
ty_rptr
,
ty_tup
,
ty_u32
,
ty_uniq
,
ty_vec
,
ty_fixed_length
,
unchecked_blk
,
uniq
,
unsafe_blk
,
unsafe_fn
,
...
...
@@ -1640,6 +1640,52 @@ fn parse_pats() -> ~[@pat] {
};
}
fn
parse_pat_fields
(
refutable
:
bool
)
->
(
~
[
ast
::
field_pat
],
bool
)
{
let
mut
fields
=
~
[];
let
mut
etc
=
false
;
let
mut
first
=
true
;
while
self
.token
!=
token
::
RBRACE
{
if
first
{
first
=
false
;
}
else
{
self
.expect
(
token
::
COMMA
);
}
if
self
.token
==
token
::
UNDERSCORE
{
self
.bump
();
if
self
.token
!=
token
::
RBRACE
{
self
.fatal
(
~
"expected `}`, found `"
+
token_to_str
(
self
.reader
,
self
.token
)
+
~
"`"
);
}
etc
=
true
;
break
;
}
let
lo1
=
self
.last_span.lo
;
let
fieldname
=
if
self
.look_ahead
(
1u
)
==
token
::
COLON
{
self
.parse_ident
()
}
else
{
self
.parse_value_ident
()
};
let
hi1
=
self
.last_span.lo
;
let
fieldpath
=
ast_util
::
ident_to_path
(
mk_sp
(
lo1
,
hi1
),
fieldname
);
let
mut
subpat
;
if
self
.token
==
token
::
COLON
{
self
.bump
();
subpat
=
self
.parse_pat
(
refutable
);
}
else
{
subpat
=
@
{
id
:
self
.get_id
(),
node
:
pat_ident
(
bind_by_implicit_ref
,
fieldpath
,
none
),
span
:
self
.last_span
};
}
vec
::
push
(
fields
,
{
ident
:
fieldname
,
pat
:
subpat
});
}
return
(
fields
,
etc
);
}
fn
parse_pat
(
refutable
:
bool
)
->
@
pat
{
maybe_whole!
{
self
,
nt_pat
};
...
...
@@ -1685,48 +1731,7 @@ fn parse_pat(refutable: bool) -> @pat {
}
token
::
LBRACE
=>
{
self
.bump
();
let
mut
fields
=
~
[];
let
mut
etc
=
false
;
let
mut
first
=
true
;
while
self
.token
!=
token
::
RBRACE
{
if
first
{
first
=
false
;
}
else
{
self
.expect
(
token
::
COMMA
);
}
if
self
.token
==
token
::
UNDERSCORE
{
self
.bump
();
if
self
.token
!=
token
::
RBRACE
{
self
.fatal
(
~
"expected `}`, found `"
+
token_to_str
(
self
.reader
,
self
.token
)
+
~
"`"
);
}
etc
=
true
;
break
;
}
let
lo1
=
self
.last_span.lo
;
let
fieldname
=
if
self
.look_ahead
(
1u
)
==
token
::
COLON
{
self
.parse_ident
()
}
else
{
self
.parse_value_ident
()
};
let
hi1
=
self
.last_span.lo
;
let
fieldpath
=
ast_util
::
ident_to_path
(
mk_sp
(
lo1
,
hi1
),
fieldname
);
let
mut
subpat
;
if
self
.token
==
token
::
COLON
{
self
.bump
();
subpat
=
self
.parse_pat
(
refutable
);
}
else
{
subpat
=
@
{
id
:
self
.get_id
(),
node
:
pat_ident
(
bind_by_implicit_ref
,
fieldpath
,
none
),
span
:
mk_sp
(
lo
,
hi
)
};
}
vec
::
push
(
fields
,
{
ident
:
fieldname
,
pat
:
subpat
});
}
let
(
fields
,
etc
)
=
self
.parse_pat_fields
(
refutable
);
hi
=
self
.span.hi
;
self
.bump
();
pat
=
pat_rec
(
fields
,
etc
);
...
...
@@ -1771,21 +1776,82 @@ fn parse_pat(refutable: bool) -> @pat {
}
else
if
!
is_plain_ident
(
self
.token
)
{
pat
=
self
.parse_enum_variant
(
refutable
);
}
else
{
// this is a plain identifier, like `x` or `x(...)`
let
binding_mode
;
if
self
.eat_keyword
(
~
"copy"
)
{
binding_mode
=
bind_by_value
;
}
else
if
refutable
{
// XXX: Should be bind_by_value, but that's not
// backward compatible.
binding_mode
=
bind_by_implicit_ref
;
}
else
{
binding_mode
=
bind_by_value
;
}
let
cannot_be_enum_or_struct
;
match
self
.look_ahead
(
1
)
{
token
::
LPAREN
|
token
::
LBRACKET
|
token
::
LT
=>
{
pat
=
self
.parse_enum_variant
(
refutable
);
}
_
=>
{
let
binding_mode
=
if
refutable
{
// XXX: Should be bind_by_value, but that's not
// backward compatible.
bind_by_implicit_ref
token
::
LPAREN
|
token
::
LBRACKET
|
token
::
LT
|
token
::
LBRACE
=>
cannot_be_enum_or_struct
=
false
,
_
=>
cannot_be_enum_or_struct
=
true
}
if
is_plain_ident
(
self
.token
)
&&
cannot_be_enum_or_struct
{
let
name
=
self
.parse_value_path
();
let
sub
;
if
self
.eat
(
token
::
AT
)
{
sub
=
some
(
self
.parse_pat
(
refutable
));
}
else
{
bind_by_value
sub
=
none
;
};
pat
=
self
.parse_pat_ident
(
refutable
,
binding_mode
);
}
pat
=
pat_ident
(
binding_mode
,
name
,
sub
);
}
else
{
let
enum_path
=
self
.parse_path_with_tps
(
true
);
match
self
.token
{
token
::
LBRACE
=>
{
self
.bump
();
let
(
fields
,
etc
)
=
self
.parse_pat_fields
(
refutable
);
self
.bump
();
pat
=
pat_struct
(
enum_path
,
fields
,
etc
);
}
_
=>
{
let
mut
args
:
~
[
@
pat
]
=
~
[];
let
mut
star_pat
=
false
;
match
self
.token
{
token
::
LPAREN
=>
match
self
.look_ahead
(
1u
)
{
token
::
BINOP
(
token
::
STAR
)
=>
{
// This is a "top constructor only" pat
self
.bump
();
self
.bump
();
star_pat
=
true
;
self
.expect
(
token
::
RPAREN
);
}
_
=>
{
args
=
self
.parse_unspanned_seq
(
token
::
LPAREN
,
token
::
RPAREN
,
seq_sep_trailing_disallowed
(
token
::
COMMA
),
|
p
|
p
.parse_pat
(
refutable
));
}
}
_
=>
()
}
// at this point, we're not sure whether it's a
// enum or a bind
if
star_pat
{
pat
=
pat_enum
(
enum_path
,
none
);
}
else
if
vec
::
is_empty
(
args
)
&&
vec
::
len
(
enum_path
.idents
)
==
1u
{
pat
=
pat_ident
(
binding_mode
,
enum_path
,
none
);
}
else
{
pat
=
pat_enum
(
enum_path
,
some
(
args
));
}
}
}
}
}
hi
=
self
.span.hi
;
...
...
src/libsyntax/print/pprust.rs
浏览文件 @
253dfc33
...
...
@@ -1375,6 +1375,24 @@ fn print_field(s: ps, f: ast::field_pat) {
}
word
(
s
.s
,
~
"}"
);
}
ast
::
pat_struct
(
path
,
fields
,
etc
)
=>
{
print_path
(
s
,
path
,
true
);
word
(
s
.s
,
~
"{"
);
fn
print_field
(
s
:
ps
,
f
:
ast
::
field_pat
)
{
cbox
(
s
,
indent_unit
);
word
(
s
.s
,
*
f
.ident
);
word_space
(
s
,
~
":"
);
print_pat
(
s
,
f
.pat
);
end
(
s
);
}
fn
get_span
(
f
:
ast
::
field_pat
)
->
codemap
::
span
{
return
f
.pat.span
;
}
commasep_cmnt
(
s
,
consistent
,
fields
,
print_field
,
get_span
);
if
etc
{
if
vec
::
len
(
fields
)
!=
0u
{
word_space
(
s
,
~
","
);
}
word
(
s
.s
,
~
"_"
);
}
word
(
s
.s
,
~
"}"
);
}
ast
::
pat_tup
(
elts
)
=>
{
popen
(
s
);
commasep
(
s
,
inconsistent
,
elts
,
print_pat
);
...
...
src/libsyntax/visit.rs
浏览文件 @
253dfc33
...
...
@@ -222,6 +222,12 @@ fn visit_pat<E>(p: @pat, e: E, v: vt<E>) {
pat_rec
(
fields
,
_
)
=>
for
fields
.each
|
f
|
{
v
.visit_pat
(
f
.pat
,
e
,
v
)
}
pat_struct
(
path
,
fields
,
_
)
=>
{
visit_path
(
path
,
e
,
v
);
for
fields
.each
|
f
|
{
v
.visit_pat
(
f
.pat
,
e
,
v
);
}
}
pat_tup
(
elts
)
=>
for
elts
.each
|
elt
|
{
v
.visit_pat
(
elt
,
e
,
v
)
}
...
...
src/rustc/middle/borrowck/gather_loans.rs
浏览文件 @
253dfc33
...
...
@@ -513,6 +513,14 @@ fn gather_pat(cmt: cmt, pat: @ast::pat,
}
}
ast
::
pat_struct
(
_
,
field_pats
,
_
)
=>
{
// {f1: p1, ..., fN: pN}
for
field_pats
.each
|
fp
|
{
let
cmt_field
=
self
.bccx
.cat_field
(
fp
.pat
,
cmt
,
fp
.ident
);
self
.gather_pat
(
cmt_field
,
fp
.pat
,
arm_id
,
alt_id
);
}
}
ast
::
pat_tup
(
subpats
)
=>
{
// (p1, ..., pN)
for
subpats
.each
|
subpat
|
{
...
...
src/rustc/middle/check_alt.rs
浏览文件 @
253dfc33
...
...
@@ -212,7 +212,8 @@ fn pat_ctor_id(tcx: ty::ctxt, p: @pat) -> option<ctor> {
pat_range
(
lo
,
hi
)
=>
{
some
(
range
(
eval_const_expr
(
tcx
,
lo
),
eval_const_expr
(
tcx
,
hi
)))
}
pat_box
(
_
)
|
pat_uniq
(
_
)
|
pat_rec
(
_
,
_
)
|
pat_tup
(
_
)
=>
{
pat_box
(
_
)
|
pat_uniq
(
_
)
|
pat_rec
(
_
,
_
)
|
pat_tup
(
_
)
|
pat_struct
(
*
)
=>
{
some
(
single
)
}
}
...
...
@@ -234,7 +235,8 @@ fn is_wild(tcx: ty::ctxt, p: @pat) -> bool {
fn
missing_ctor
(
tcx
:
ty
::
ctxt
,
m
:
matrix
,
left_ty
:
ty
::
t
)
->
option
<
ctor
>
{
match
ty
::
get
(
left_ty
)
.struct
{
ty
::
ty_box
(
_
)
|
ty
::
ty_uniq
(
_
)
|
ty
::
ty_tup
(
_
)
|
ty
::
ty_rec
(
_
)
=>
{
ty
::
ty_box
(
_
)
|
ty
::
ty_uniq
(
_
)
|
ty
::
ty_tup
(
_
)
|
ty
::
ty_rec
(
_
)
|
ty
::
ty_class
(
*
)
=>
{
for
m
.each
|
r
|
{
if
!
is_wild
(
tcx
,
r
[
0
])
{
return
none
;
}
}
...
...
@@ -286,6 +288,7 @@ fn ctor_arity(tcx: ty::ctxt, ctor: ctor, ty: ty::t) -> uint {
some
(
v
)
=>
v
.args
.len
()
}
}
ty
::
ty_class
(
cid
,
_
)
=>
ty
::
lookup_class_fields
(
tcx
,
cid
)
.len
(),
_
=>
0u
}
}
...
...
@@ -327,7 +330,29 @@ fn specialize(tcx: ty::ctxt, r: ~[@pat], ctor_id: ctor, arity: uint,
};
let
args
=
vec
::
map
(
ty_flds
,
|
ty_f
|
{
match
vec
::
find
(
flds
,
|
f
|
f
.ident
==
ty_f
.ident
)
{
some
(
f
)
=>
f
.pat
,
_
=>
wild
()
some
(
f
)
=>
f
.pat
,
_
=>
wild
()
}
});
some
(
vec
::
append
(
args
,
vec
::
tail
(
r
)))
}
pat_struct
(
_
,
flds
,
_
)
=>
{
// Grab the class data that we care about.
let
class_fields
,
class_id
;
match
ty
::
get
(
left_ty
)
.struct
{
ty
::
ty_class
(
cid
,
substs
)
=>
{
class_id
=
cid
;
class_fields
=
ty
::
lookup_class_fields
(
tcx
,
class_id
);
}
_
=>
{
tcx
.sess
.span_bug
(
r0
.span
,
~
"struct pattern didn't resolve
\
to a struct"
);
}
}
let
args
=
vec
::
map
(
class_fields
,
|
class_field
|
{
match
vec
::
find
(
flds
,
|
f
|
f
.ident
==
class_field
.ident
)
{
some
(
f
)
=>
f
.pat
,
_
=>
wild
()
}
});
some
(
vec
::
append
(
args
,
vec
::
tail
(
r
)))
...
...
@@ -377,7 +402,9 @@ fn check_local(tcx: ty::ctxt, loc: @local, &&s: (), v: visit::vt<()>) {
fn
is_refutable
(
tcx
:
ty
::
ctxt
,
pat
:
@
pat
)
->
bool
{
match
tcx
.def_map
.find
(
pat
.id
)
{
some
(
def_variant
(
enum_id
,
var_id
))
=>
{
if
vec
::
len
(
*
ty
::
enum_variants
(
tcx
,
enum_id
))
!=
1u
{
return
true
;
}
if
vec
::
len
(
*
ty
::
enum_variants
(
tcx
,
enum_id
))
!=
1u
{
return
true
;
}
}
_
=>
()
}
...
...
@@ -394,6 +421,12 @@ fn is_refutable(tcx: ty::ctxt, pat: @pat) -> bool {
}
false
}
pat_struct
(
_
,
fields
,
_
)
=>
{
for
fields
.each
|
it
|
{
if
is_refutable
(
tcx
,
it
.pat
)
{
return
true
;
}
}
false
}
pat_tup
(
elts
)
=>
{
for
elts
.each
|
elt
|
{
if
is_refutable
(
tcx
,
elt
)
{
return
true
;
}
}
false
...
...
src/rustc/middle/resolve3.rs
浏览文件 @
253dfc33
...
...
@@ -15,8 +15,8 @@
import
syntax
::
ast
::{
class_member
,
class_method
,
crate
,
crate_num
,
decl_item
};
import
syntax
::
ast
::{
def
,
def_arg
,
def_binding
,
def_class
,
def_const
,
def_fn
};
import
syntax
::
ast
::{
def_foreign_mod
,
def_id
,
def_local
,
def_mod
};
import
syntax
::
ast
::{
def_prim_ty
,
def_region
,
def_self
,
def_ty
,
def_ty_param
,
def_typaram_binder
};
import
syntax
::
ast
::{
def_prim_ty
,
def_region
,
def_self
,
def_ty
,
def_ty_param
};
import
syntax
::
ast
::{
def_typaram_binder
};
import
syntax
::
ast
::{
def_upvar
,
def_use
,
def_variant
,
expr
,
expr_assign_op
};
import
syntax
::
ast
::{
expr_binary
,
expr_cast
,
expr_field
,
expr_fn
};
import
syntax
::
ast
::{
expr_fn_block
,
expr_index
,
expr_path
};
...
...
@@ -30,13 +30,13 @@
import
syntax
::
ast
::{
item_fn
,
item_mac
,
item_foreign_mod
,
item_impl
};
import
syntax
::
ast
::{
item_mod
,
item_trait
,
item_ty
,
le
,
local
,
local_crate
};
import
syntax
::
ast
::{
lt
,
method
,
mul
,
ne
,
neg
,
node_id
,
pat
,
pat_enum
};
import
syntax
::
ast
::{
pat_ident
,
pat
h
,
prim_ty
,
pat_box
,
pat_uniq
,
pat_lit
};
import
syntax
::
ast
::{
pat_
range
,
pat_rec
,
pat_tup
,
pat_wild
,
provide
d
};
import
syntax
::
ast
::{
required
,
rem
,
self_ty_
,
shl
,
stmt_decl
,
subtract
,
ty
};
import
syntax
::
ast
::{
ty_bool
,
ty_char
,
ty_f
,
ty_f32
,
ty_f64
,
ty_float
,
ty_i
};
import
syntax
::
ast
::{
ty_
i16
,
ty_i32
,
ty_i64
,
ty_i8
,
ty_int
,
ty_param
};
import
syntax
::
ast
::{
ty_pa
th
,
ty_str
,
ty_u
,
ty_u16
,
ty_u32
,
ty_u64
,
ty_u8
};
import
syntax
::
ast
::{
ty_uint
,
variant
,
view_item
,
view_item_export
};
import
syntax
::
ast
::{
pat_ident
,
pat
_struct
,
path
,
prim_ty
,
pat_box
,
pat_uniq
};
import
syntax
::
ast
::{
pat_
lit
,
pat_range
,
pat_rec
,
pat_tup
,
pat_wil
d
};
import
syntax
::
ast
::{
provided
,
required
,
rem
,
self_ty_
,
shl
,
stmt_decl
};
import
syntax
::
ast
::{
subtract
,
ty
,
ty_bool
,
ty_char
,
ty_f
,
ty_f32
,
ty_f64
};
import
syntax
::
ast
::{
ty_
float
,
ty_i
,
ty_i16
,
ty_i32
,
ty_i64
,
ty_i8
,
ty_int
};
import
syntax
::
ast
::{
ty_pa
ram
,
ty_path
,
ty_str
,
ty_u
,
ty_u16
,
ty_u32
,
ty_u64
};
import
syntax
::
ast
::{
ty_u
8
,
ty_u
int
,
variant
,
view_item
,
view_item_export
};
import
syntax
::
ast
::{
view_item_import
,
view_item_use
,
view_path_glob
};
import
syntax
::
ast
::{
view_path_list
,
view_path_simple
};
import
syntax
::
ast_util
::{
def_id_of_def
,
dummy_sp
,
local_def
,
new_def_hash
};
...
...
@@ -4017,6 +4017,26 @@ enum variant",
self
.resolve_expr
(
last_expr
,
visitor
);
}
pat_struct
(
path
,
_
,
_
)
=>
{
match
self
.resolve_path
(
path
,
TypeNS
,
false
,
visitor
)
{
some
(
definition
@
def_ty
(
class_id
))
if
self
.structs
.contains_key
(
class_id
)
=>
{
let
has_constructor
=
self
.structs
.get
(
class_id
);
let
class_def
=
def_class
(
class_id
,
has_constructor
);
self
.record_def
(
pattern
.id
,
class_def
);
}
_
=>
{
self
.session
.span_err
(
path
.span
,
fmt!
(
"`%s` does not name a
\
structure"
,
connect
(
path
.idents
.map
(|
x
|
*
x
),
~
"::"
)));
}
}
}
_
=>
{
// Nothing to do.
}
...
...
src/rustc/middle/trans/alt.rs
浏览文件 @
253dfc33
...
...
@@ -187,7 +187,8 @@ fn enter_default(bcx: block, dm: DefMap, m: match_, col: uint, val: ValueRef)
do
enter_match
(
bcx
,
dm
,
m
,
col
,
val
)
|
p
|
{
match
p
.node
{
ast
::
pat_wild
|
ast
::
pat_rec
(
_
,
_
)
|
ast
::
pat_tup
(
_
)
=>
some
(
~
[]),
ast
::
pat_wild
|
ast
::
pat_rec
(
_
,
_
)
|
ast
::
pat_tup
(
_
)
|
ast
::
pat_struct
(
*
)
=>
some
(
~
[]),
ast
::
pat_ident
(
_
,
_
,
none
)
if
!
pat_is_variant
(
dm
,
p
)
=>
some
(
~
[]),
_
=>
none
}
...
...
@@ -221,12 +222,12 @@ fn enter_opt(bcx: block, m: match_, opt: opt, col: uint,
}
}
fn
enter_rec
(
bcx
:
block
,
dm
:
DefMap
,
m
:
match_
,
col
:
uint
,
fields
:
~
[
ast
::
ident
],
val
:
ValueRef
)
->
match_
{
fn
enter_rec
_or_struct
(
bcx
:
block
,
dm
:
DefMap
,
m
:
match_
,
col
:
uint
,
fields
:
~
[
ast
::
ident
],
val
:
ValueRef
)
->
match_
{
let
dummy
=
@
{
id
:
0
,
node
:
ast
::
pat_wild
,
span
:
dummy_sp
()};
do
enter_match
(
bcx
,
dm
,
m
,
col
,
val
)
|
p
|
{
match
p
.node
{
ast
::
pat_rec
(
fpats
,
_
)
=>
{
ast
::
pat_rec
(
fpats
,
_
)
|
ast
::
pat_struct
(
_
,
fpats
,
_
)
=>
{
let
mut
pats
=
~
[];
for
vec
::
each
(
fields
)
|
fname
|
{
let
mut
pat
=
dummy
;
...
...
@@ -344,6 +345,23 @@ fn collect_record_fields(m: match_, col: uint) -> ~[ast::ident] {
return
fields
;
}
fn
collect_struct_fields
(
m
:
match_
,
col
:
uint
)
->
~
[
ast
::
ident
]
{
let
mut
fields
:
~
[
ast
::
ident
]
=
~
[];
for
vec
::
each
(
m
)
|
br
|
{
match
br
.pats
[
col
]
.node
{
ast
::
pat_struct
(
_
,
fs
,
_
)
=>
{
for
vec
::
each
(
fs
)
|
f
|
{
if
!
vec
::
any
(
fields
,
|
x
|
str
::
eq
(
f
.ident
,
x
))
{
vec
::
push
(
fields
,
f
.ident
);
}
}
}
_
=>
()
}
}
return
fields
;
}
fn
root_pats_as_necessary
(
bcx
:
block
,
m
:
match_
,
col
:
uint
,
val
:
ValueRef
)
{
for
vec
::
each
(
m
)
|
br
|
{
let
pat_id
=
br
.pats
[
col
]
.id
;
...
...
@@ -500,15 +518,56 @@ fn compile_submatch(bcx: block, m: match_, vals: ~[ValueRef],
let
rec_fields
=
collect_record_fields
(
m
,
col
);
// Separate path for extracting and binding record fields
if
rec_fields
.len
()
>
0
u
{
if
rec_fields
.len
()
>
0
{
let
fields
=
ty
::
get_fields
(
node_id_type
(
bcx
,
pat_id
));
let
mut
rec_vals
=
~
[];
for
vec
::
each
(
rec_fields
)
|
field_name
|
{
let
ix
=
option
::
get
(
ty
::
field_idx
(
field_name
,
fields
));
vec
::
push
(
rec_vals
,
GEPi
(
bcx
,
val
,
~
[
0u
,
ix
]));
}
compile_submatch
(
bcx
,
enter_rec
(
bcx
,
dm
,
m
,
col
,
rec_fields
,
val
),
vec
::
append
(
rec_vals
,
vals_left
),
chk
,
exits
);
compile_submatch
(
bcx
,
enter_rec_or_struct
(
bcx
,
dm
,
m
,
col
,
rec_fields
,
val
),
vec
::
append
(
rec_vals
,
vals_left
),
chk
,
exits
);
return
;
}
// Separate path for extracting and binding struct fields.
let
struct_fields
=
collect_struct_fields
(
m
,
col
);
if
struct_fields
.len
()
>
0
{
let
class_id
,
class_fields
;
match
ty
::
get
(
node_id_type
(
bcx
,
pat_id
))
.struct
{
ty
::
ty_class
(
cid
,
_
)
=>
{
class_id
=
cid
;
class_fields
=
ty
::
lookup_class_fields
(
ccx
.tcx
,
class_id
);
}
_
=>
{
ccx
.tcx.sess
.bug
(
~
"struct pattern didn't resolve to a
\
struct"
);
}
}
// Index the class fields.
let
field_map
=
std
::
map
::
box_str_hash
();
for
class_fields
.eachi
|
i
,
class_field
|
{
field_map
.insert
(
class_field
.ident
,
i
);
}
// Fetch each field.
let
mut
struct_vals
=
~
[];
for
struct_fields
.each
|
field_name
|
{
let
index
=
field_map
.get
(
field_name
);
let
fldptr
=
base
::
get_struct_field
(
bcx
,
val
,
class_id
,
index
);
vec
::
push
(
struct_vals
,
fldptr
);
}
compile_submatch
(
bcx
,
enter_rec_or_struct
(
bcx
,
dm
,
m
,
col
,
struct_fields
,
val
),
vec
::
append
(
struct_vals
,
vals_left
),
chk
,
exits
);
return
;
}
...
...
@@ -877,6 +936,34 @@ fn bind_irrefutable_pat(bcx: block, pat: @ast::pat, val: ValueRef,
bcx
=
bind_irrefutable_pat
(
bcx
,
f
.pat
,
fldptr
,
make_copy
);
}
}
ast
::
pat_struct
(
_
,
fields
,
_
)
=>
{
// Grab the class data that we care about.
let
class_fields
,
class_id
;
match
ty
::
get
(
node_id_type
(
bcx
,
pat
.id
))
.struct
{
ty
::
ty_class
(
cid
,
substs
)
=>
{
class_id
=
cid
;
class_fields
=
ty
::
lookup_class_fields
(
ccx
.tcx
,
class_id
);
}
_
=>
{
ccx
.tcx.sess
.span_bug
(
pat
.span
,
~
"struct pattern didn't
\
resolve to a struct"
);
}
}
// Index the class fields.
let
field_map
=
std
::
map
::
box_str_hash
();
for
class_fields
.eachi
|
i
,
class_field
|
{
field_map
.insert
(
class_field
.ident
,
i
);
}
// Fetch each field.
for
fields
.each
|
supplied_field
|
{
let
index
=
field_map
.get
(
supplied_field
.ident
);
let
fldptr
=
base
::
get_struct_field
(
bcx
,
val
,
class_id
,
index
);
bcx
=
bind_irrefutable_pat
(
bcx
,
supplied_field
.pat
,
fldptr
,
make_copy
);
}
}
ast
::
pat_tup
(
elems
)
=>
{
let
mut
i
=
0u
;
for
vec
::
each
(
elems
)
|
elem
|
{
...
...
src/rustc/middle/trans/base.rs
浏览文件 @
253dfc33
...
...
@@ -3391,6 +3391,18 @@ fn trans_rec(bcx: block, fields: ~[ast::field],
return
bcx
;
}
// If the class has a destructor, our GEP is a little more
// complicated.
fn
get_struct_field
(
block_context
:
block
,
dest_address
:
ValueRef
,
class_id
:
ast
::
def_id
,
index
:
uint
)
->
ValueRef
{
if
ty
::
ty_dtor
(
block_context
.tcx
(),
class_id
)
.is_some
()
{
return
GEPi
(
block_context
,
GEPi
(
block_context
,
dest_address
,
~
[
0
,
1
]),
~
[
0
,
index
]);
}
return
GEPi
(
block_context
,
dest_address
,
~
[
0
,
index
]);
}
fn
trans_struct
(
block_context
:
block
,
span
:
span
,
fields
:
~
[
ast
::
field
],
base
:
option
<@
ast
::
expr
>
,
id
:
ast
::
node_id
,
dest
:
dest
)
->
block
{
...
...
@@ -3434,18 +3446,6 @@ fn trans_struct(block_context: block, span: span, fields: ~[ast::field],
}
}
// If the class has a destructor, our GEP is a little more
// complicated.
fn
get_field
(
block_context
:
block
,
dest_address
:
ValueRef
,
class_id
:
ast
::
def_id
,
index
:
uint
)
->
ValueRef
{
if
ty
::
ty_dtor
(
block_context
.tcx
(),
class_id
)
.is_some
()
{
return
GEPi
(
block_context
,
GEPi
(
block_context
,
dest_address
,
~
[
0
,
1
]),
~
[
0
,
index
]);
}
return
GEPi
(
block_context
,
dest_address
,
~
[
0
,
index
]);
}
// Now translate each field.
let
mut
temp_cleanups
=
~
[];
for
fields
.each
|
field
|
{
...
...
@@ -3468,7 +3468,8 @@ fn get_field(block_context: block, dest_address: ValueRef,
}
}
let
dest
=
get_field
(
block_context
,
dest_address
,
class_id
,
index
);
let
dest
=
get_struct_field
(
block_context
,
dest_address
,
class_id
,
index
);
block_context
=
trans_expr_save_in
(
block_context
,
field
.node.expr
,
...
...
@@ -3494,10 +3495,10 @@ fn get_field(block_context: block, dest_address: ValueRef,
if
exists
{
again
;
}
let
lldestfieldvalue
=
get_field
(
block_context
,
dest_address
,
class_id
,
i
);
let
lldestfieldvalue
=
get_
struct_
field
(
block_context
,
dest_address
,
class_id
,
i
);
let
llbasefieldvalue
=
GEPi
(
block_context
,
llbasevalue
,
~
[
0
,
i
]);
...
...
src/rustc/middle/typeck/check/alt.rs
浏览文件 @
253dfc33
...
...
@@ -232,6 +232,86 @@ fn matches(name: ast::ident, f: ty::field) -> bool {
}
fcx
.write_ty
(
pat
.id
,
expected
);
}
ast
::
pat_struct
(
path
,
fields
,
etc
)
=>
{
// Grab the class data that we care about.
let
class_fields
,
class_id
,
substitutions
;
match
structure_of
(
fcx
,
pat
.span
,
expected
)
{
ty
::
ty_class
(
cid
,
substs
)
=>
{
class_id
=
cid
;
substitutions
=
substs
;
class_fields
=
ty
::
lookup_class_fields
(
tcx
,
class_id
);
}
_
=>
{
// XXX: This should not be fatal.
tcx
.sess
.span_fatal
(
pat
.span
,
fmt!
(
"mismatched types: expected `%s`
\
but found struct"
,
fcx
.infcx
.ty_to_str
(
expected
)));
}
}
// Check to ensure that the struct is the one specified.
match
tcx
.def_map
.get
(
pat
.id
)
{
ast
::
def_class
(
supplied_def_id
,
_
)
if
supplied_def_id
==
class_id
=>
{
// OK.
}
ast
::
def_class
(
*
)
=>
{
let
name
=
syntax
::
print
::
pprust
::
path_to_str
(
path
);
tcx
.sess
.span_err
(
pat
.span
,
fmt!
(
"mismatched types: expected `%s` but
\
found `%s`"
,
fcx
.infcx
.ty_to_str
(
expected
),
name
));
}
_
=>
{
tcx
.sess
.span_bug
(
pat
.span
,
~
"resolve didn't write in class"
);
}
}
// Index the class fields.
let
field_map
=
std
::
map
::
box_str_hash
();
for
class_fields
.eachi
|
i
,
class_field
|
{
field_map
.insert
(
class_field
.ident
,
i
);
}
// Typecheck each field.
let
found_fields
=
std
::
map
::
uint_hash
();
for
fields
.each
|
field
|
{
match
field_map
.find
(
field
.ident
)
{
some
(
index
)
=>
{
let
class_field
=
class_fields
[
index
];
let
field_type
=
ty
::
lookup_field_type
(
tcx
,
class_id
,
class_field
.id
,
substitutions
);
check_pat
(
pcx
,
field
.pat
,
field_type
);
found_fields
.insert
(
index
,
());
}
none
=>
{
let
name
=
syntax
::
print
::
pprust
::
path_to_str
(
path
);
tcx
.sess
.span_err
(
pat
.span
,
fmt!
(
"struct `%s` does not have a field
named `%s`"
,
name
,
*
field
.ident
));
}
}
}
// Report an error if not all the fields were specified.
if
!
etc
{
for
class_fields
.eachi
|
i
,
field
|
{
if
found_fields
.contains_key
(
i
)
{
again
;
}
tcx
.sess
.span_err
(
pat
.span
,
fmt!
(
"pattern does not mention field `%s`"
,
*
field
.ident
));
}
}
// Finally, write in the type.
fcx
.write_ty
(
pat
.id
,
expected
);
}
ast
::
pat_tup
(
elts
)
=>
{
let
ex_elts
=
match
structure_of
(
fcx
,
pat
.span
,
expected
)
{
ty
::
ty_tup
(
elts
)
=>
elts
,
...
...
src/test/run-pass/struct-pattern-matching.rs
0 → 100644
浏览文件 @
253dfc33
struct
Foo
{
x
:
int
;
y
:
int
;
}
fn
main
()
{
let
a
=
Foo
{
x
:
1
,
y
:
2
};
match
a
{
Foo
{
x
:
x
,
y
:
y
}
=>
io
::
println
(
fmt!
(
"yes, %d, %d"
,
x
,
y
))
}
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录