提交 253dfc33 编写于 作者: P Patrick Walton

rustc: Implement pattern matching for structs

上级 5cb3a94b
......@@ -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),
......
......@@ -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)
}
......
......@@ -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)),
......
......@@ -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_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, stmt_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,
pat_ident, pat_lit, pat_range, pat_rec, pat_struct, pat_tup,
pat_uniq, pat_wild, path, private, proto, proto_bare,
proto_block, 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,
stmt_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;
......
......@@ -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);
......
......@@ -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)
}
......
......@@ -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| {
......
......@@ -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
......
......@@ -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, path, prim_ty, pat_box, pat_uniq, pat_lit};
import syntax::ast::{pat_range, pat_rec, pat_tup, pat_wild, provided};
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_path, 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_wild};
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_param, ty_path, ty_str, ty_u, ty_u16, ty_u32, ty_u64};
import syntax::ast::{ty_u8, ty_uint, 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.
}
......
......@@ -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() > 0u {
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| {
......
......@@ -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]);
......
......@@ -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,
......
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.
先完成此消息的编辑!
想要评论请 注册