From 4165edff227545cb2a7267051347bdae1868895d Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Tue, 30 Oct 2012 15:53:06 -0700 Subject: [PATCH] rustc: Implement translation of pattern matching for tuple structs and unit-like structs. r=nmatsakis --- src/rustc/middle/borrowck/gather_loans.rs | 7 +- src/rustc/middle/pat_util.rs | 20 +- src/rustc/middle/resolve.rs | 51 ++--- src/rustc/middle/trans/alt.rs | 201 +++++++++++++++--- src/rustc/middle/trans/base.rs | 6 +- src/rustc/middle/trans/expr.rs | 5 + src/rustc/middle/ty.rs | 2 +- src/rustc/middle/typeck.rs | 2 +- src/rustc/middle/typeck/check.rs | 7 +- src/rustc/middle/typeck/check/alt.rs | 7 +- .../run-pass/tuple-struct-destructuring.rs | 10 + src/test/run-pass/tuple-struct-matching.rs | 13 ++ src/test/run-pass/unit-like-struct.rs | 9 + 13 files changed, 259 insertions(+), 81 deletions(-) create mode 100644 src/test/run-pass/tuple-struct-destructuring.rs create mode 100644 src/test/run-pass/tuple-struct-matching.rs create mode 100644 src/test/run-pass/unit-like-struct.rs diff --git a/src/rustc/middle/borrowck/gather_loans.rs b/src/rustc/middle/borrowck/gather_loans.rs index e0eb5519d4d..23f0d9edbfa 100644 --- a/src/rustc/middle/borrowck/gather_loans.rs +++ b/src/rustc/middle/borrowck/gather_loans.rs @@ -441,7 +441,8 @@ impl gather_loan_ctxt { alt_id: ast::node_id) { do self.bccx.cat_pattern(discr_cmt, root_pat) |cmt, pat| { match pat.node { - ast::pat_ident(bm, _, _) if !self.pat_is_variant(pat) => { + ast::pat_ident(bm, _, _) + if !self.pat_is_variant_or_struct(pat) => { match bm { ast::bind_by_value | ast::bind_by_move => { // copying does not borrow anything, so no check @@ -492,8 +493,8 @@ impl gather_loan_ctxt { } } - fn pat_is_variant(&self, pat: @ast::pat) -> bool { - pat_util::pat_is_variant(self.bccx.tcx.def_map, pat) + fn pat_is_variant_or_struct(&self, pat: @ast::pat) -> bool { + pat_util::pat_is_variant_or_struct(self.bccx.tcx.def_map, pat) } } diff --git a/src/rustc/middle/pat_util.rs b/src/rustc/middle/pat_util.rs index 48ebda9a67e..9196a0b22ca 100644 --- a/src/rustc/middle/pat_util.rs +++ b/src/rustc/middle/pat_util.rs @@ -7,7 +7,7 @@ use syntax::codemap::span; use std::map::HashMap; export pat_binding_ids, pat_bindings, pat_id_map, PatIdMap; -export pat_is_variant, pat_is_binding_or_wild; +export pat_is_variant_or_struct, pat_is_binding_or_wild; type PatIdMap = std::map::HashMap; @@ -21,20 +21,21 @@ fn pat_id_map(dm: resolve::DefMap, pat: @pat) -> PatIdMap { return map; } -fn pat_is_variant(dm: resolve::DefMap, pat: @pat) -> bool { +fn pat_is_variant_or_struct(dm: resolve::DefMap, pat: @pat) -> bool { match pat.node { - pat_enum(_, _) => true, - pat_ident(_, _, None) | pat_struct(*) => match dm.find(pat.id) { - Some(def_variant(_, _)) => true, + pat_enum(_, _) | pat_ident(_, _, None) | pat_struct(*) => { + match dm.find(pat.id) { + Some(def_variant(*)) | Some(def_class(*)) => true, + _ => false + } + } _ => false - }, - _ => false } } fn pat_is_binding_or_wild(dm: resolve::DefMap, pat: @pat) -> bool { match pat.node { - pat_ident(*) => !pat_is_variant(dm, pat), + pat_ident(*) => !pat_is_variant_or_struct(dm, pat), pat_wild => true, _ => false } @@ -44,7 +45,8 @@ fn pat_bindings(dm: resolve::DefMap, pat: @pat, it: fn(binding_mode, node_id, span, @path)) { do walk_pat(pat) |p| { match p.node { - pat_ident(binding_mode, pth, _) if !pat_is_variant(dm, p) => { + pat_ident(binding_mode, pth, _) + if !pat_is_variant_or_struct(dm, p) => { it(binding_mode, p.id, p.span, pth); } _ => {} diff --git a/src/rustc/middle/resolve.rs b/src/rustc/middle/resolve.rs index a979c0d7b57..8ebebfa1121 100644 --- a/src/rustc/middle/resolve.rs +++ b/src/rustc/middle/resolve.rs @@ -288,10 +288,10 @@ impl AllowCapturingSelfFlag : cmp::Eq { pure fn ne(other: &AllowCapturingSelfFlag) -> bool { !self.eq(other) } } -enum EnumVariantOrConstResolution { - FoundEnumVariant(def), +enum BareIdentifierPatternResolution { + FoundStructOrEnumVariant(def), FoundConst, - EnumVariantOrConstNotFound + BareIdentifierPatternUnresolved } // Specifies how duplicates should be handled when adding a child item if @@ -4187,28 +4187,31 @@ impl Resolver { if !path.global && path.idents.len() == 1u => { // The meaning of pat_ident with no type parameters - // depends on whether an enum variant with that name is in - // scope. The probing lookup has to be careful not to emit - // spurious errors. Only matching patterns (match) can - // match nullary variants. For binding patterns (let), - // matching such a variant is simply disallowed (since - // it's rarely what you want). + // depends on whether an enum variant or unit-like struct + // with that name is in scope. The probing lookup has to + // be careful not to emit spurious errors. Only matching + // patterns (match) can match nullary variants or + // unit-like structs. For binding patterns (let), matching + // such a value is simply disallowed (since it's rarely + // what you want). let ident = path.idents[0]; - match self.resolve_enum_variant_or_const(ident) { - FoundEnumVariant(def) if mode == RefutableMode => { + match self.resolve_bare_identifier_pattern(ident) { + FoundStructOrEnumVariant(def) + if mode == RefutableMode => { debug!("(resolving pattern) resolving `%s` to \ - enum variant", + struct or enum variant", self.session.str_of(ident)); self.record_def(pattern.id, def); } - FoundEnumVariant(_) => { + FoundStructOrEnumVariant(_) => { self.session.span_err(pattern.span, fmt!("declaration of `%s` \ shadows an enum \ - that's in scope", + variant or unit-like \ + struct in scope", self.session .str_of(ident))); } @@ -4218,7 +4221,7 @@ impl Resolver { conflicts with a constant \ in scope"); } - EnumVariantOrConstNotFound => { + BareIdentifierPatternUnresolved => { debug!("(resolving pattern) binding `%s`", self.session.str_of(ident)); @@ -4349,13 +4352,11 @@ impl Resolver { } } - fn resolve_enum_variant_or_const(name: ident) - -> EnumVariantOrConstResolution { - + fn resolve_bare_identifier_pattern(name: ident) + -> BareIdentifierPatternResolution { match self.resolve_item_in_lexical_scope(self.current_module, - name, - ValueNS) { - + name, + ValueNS) { Success(target) => { match target.bindings.value_def { None => { @@ -4364,14 +4365,14 @@ impl Resolver { } Some(def) => { match def.def { - def @ def_variant(*) => { - return FoundEnumVariant(def); + def @ def_variant(*) | def @ def_class(*) => { + return FoundStructOrEnumVariant(def); } def_const(*) => { return FoundConst; } _ => { - return EnumVariantOrConstNotFound; + return BareIdentifierPatternUnresolved; } } } @@ -4383,7 +4384,7 @@ impl Resolver { } Failed => { - return EnumVariantOrConstNotFound; + return BareIdentifierPatternUnresolved; } } } diff --git a/src/rustc/middle/trans/alt.rs b/src/rustc/middle/trans/alt.rs index b3776e49994..0908eae34dc 100644 --- a/src/rustc/middle/trans/alt.rs +++ b/src/rustc/middle/trans/alt.rs @@ -154,16 +154,25 @@ use util::common::indenter; fn macros() { include!("macros.rs"); } // FIXME(#3114): Macro import/export. +// An option identifying a literal: either a unit-like struct or an +// expression. +enum Lit { + UnitLikeStructLit(ast::node_id), // the node ID of the pattern + ExprLit(@ast::expr) +} + // An option identifying a branch (either a literal, a enum variant or a // range) enum Opt { - lit(@ast::expr), + lit(Lit), var(/* disr val */int, /* variant dids */{enm: def_id, var: def_id}), range(@ast::expr, @ast::expr) } fn opt_eq(tcx: ty::ctxt, a: &Opt, b: &Opt) -> bool { match (*a, *b) { - (lit(a), lit(b)) => const_eval::compare_lit_exprs(tcx, a, b) == 0, + (lit(ExprLit(a)), lit(ExprLit(b))) => + const_eval::compare_lit_exprs(tcx, a, b) == 0, + (lit(UnitLikeStructLit(a)), lit(UnitLikeStructLit(b))) => a == b, (range(a1, a2), range(b1, b2)) => { const_eval::compare_lit_exprs(tcx, a1, b1) == 0 && const_eval::compare_lit_exprs(tcx, a2, b2) == 0 @@ -182,10 +191,15 @@ fn trans_opt(bcx: block, o: &Opt) -> opt_result { let ccx = bcx.ccx(); let mut bcx = bcx; match *o { - lit(lit_expr) => { + lit(ExprLit(lit_expr)) => { let datumblock = expr::trans_to_datum(bcx, lit_expr); return single_result(datumblock.to_result()); } + lit(UnitLikeStructLit(pat_id)) => { + let struct_ty = ty::node_id_to_type(bcx.tcx(), pat_id); + let datumblock = datum::scratch_datum(bcx, struct_ty, true); + return single_result(datumblock.to_result(bcx)); + } var(disr_val, _) => { return single_result(rslt(bcx, C_int(ccx, disr_val))); } @@ -197,12 +211,23 @@ fn trans_opt(bcx: block, o: &Opt) -> opt_result { } fn variant_opt(tcx: ty::ctxt, pat_id: ast::node_id) -> Opt { - let vdef = ast_util::variant_def_ids(tcx.def_map.get(pat_id)); - let variants = ty::enum_variants(tcx, vdef.enm); - for vec::each(*variants) |v| { - if vdef.var == v.id { return var(v.disr_val, vdef); } + match tcx.def_map.get(pat_id) { + ast::def_variant(enum_id, var_id) => { + let variants = ty::enum_variants(tcx, enum_id); + for vec::each(*variants) |v| { + if var_id == v.id { + return var(v.disr_val, {enm: enum_id, var: var_id}); + } + } + core::util::unreachable(); + } + ast::def_class(_) => { + return lit(UnitLikeStructLit(pat_id)); + } + _ => { + tcx.sess.bug(~"non-variant or struct in variant_opt()"); + } } - core::util::unreachable(); } enum TransBindingMode { @@ -328,7 +353,7 @@ fn enter_match(bcx: block, dm: DefMap, m: &[@Match/&r], let self = br.pats[col]; match self.node { ast::pat_ident(_, path, None) => { - if !pat_is_variant(dm, self) { + if !pat_is_variant_or_struct(dm, self) { let binding_info = br.data.bindings_map.get(path_to_ident(path)); Store(bcx, val, binding_info.llmatch); @@ -363,7 +388,8 @@ fn enter_default(bcx: block, dm: DefMap, m: &[@Match/&r], match p.node { ast::pat_wild | ast::pat_rec(_, _) | ast::pat_tup(_) | ast::pat_struct(*) => Some(~[]), - ast::pat_ident(_, _, None) if !pat_is_variant(dm, p) => Some(~[]), + ast::pat_ident(_, _, None) + if !pat_is_variant_or_struct(dm, p) => Some(~[]), _ => None } } @@ -417,7 +443,8 @@ fn enter_opt(bcx: block, m: &[@Match/&r], opt: &Opt, col: uint, None } } - ast::pat_ident(_, _, None) if pat_is_variant(tcx.def_map, p) => { + ast::pat_ident(_, _, None) + if pat_is_variant_or_struct(tcx.def_map, p) => { if opt_eq(tcx, &variant_opt(tcx, p.id), opt) { Some(~[]) } else { @@ -425,7 +452,7 @@ fn enter_opt(bcx: block, m: &[@Match/&r], opt: &Opt, col: uint, } } ast::pat_lit(l) => { - if opt_eq(tcx, &lit(l), opt) {Some(~[])} else {None} + if opt_eq(tcx, &lit(ExprLit(l)), opt) {Some(~[])} else {None} } ast::pat_range(l1, l2) => { if opt_eq(tcx, &range(l1, l2), opt) {Some(~[])} else {None} @@ -522,6 +549,29 @@ fn enter_tup(bcx: block, dm: DefMap, m: &[@Match/&r], } } +fn enter_tuple_struct(bcx: block, dm: DefMap, m: &[@Match/&r], col: uint, + val: ValueRef, n_elts: uint) + -> ~[@Match/&r] +{ + debug!("enter_tuple_struct(bcx=%s, m=%s, col=%u, val=%?)", + bcx.to_str(), + matches_to_str(bcx, m), + col, + bcx.val_str(val)); + let _indenter = indenter(); + + 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_enum(_, Some(elts)) => Some(elts), + _ => { + assert_is_binding_or_wild(bcx, p); + Some(vec::from_elem(n_elts, dummy)) + } + } + } +} + fn enter_box(bcx: block, dm: DefMap, m: &[@Match/&r], col: uint, val: ValueRef) -> ~[@Match/&r] @@ -597,6 +647,9 @@ fn enter_region(bcx: block, dm: DefMap, m: &[@Match/&r], } } +// Returns the options in one column of matches. An option is something that +// needs to be conditionally matched at runtime; for example, the discriminant +// on a set of enum variants or a literal. fn get_options(ccx: @crate_ctxt, m: &[@Match], col: uint) -> ~[Opt] { fn add_to_set(tcx: ty::ctxt, set: &DVec, val: Opt) { if set.any(|l| opt_eq(tcx, l, &val)) {return;} @@ -606,18 +659,40 @@ fn get_options(ccx: @crate_ctxt, m: &[@Match], col: uint) -> ~[Opt] { let found = DVec(); for vec::each(m) |br| { let cur = br.pats[col]; - if pat_is_variant(ccx.tcx.def_map, cur) { - add_to_set(ccx.tcx, &found, variant_opt(ccx.tcx, cur.id)); - } else { - match cur.node { - ast::pat_lit(l) => { - add_to_set(ccx.tcx, &found, lit(l)); - } - ast::pat_range(l1, l2) => { - add_to_set(ccx.tcx, &found, range(l1, l2)); - } - _ => () + match cur.node { + ast::pat_lit(l) => { + add_to_set(ccx.tcx, &found, lit(ExprLit(l))); } + ast::pat_ident(*) => { + // This is one of: an enum variant, a unit-like struct, or a + // variable binding. + match ccx.tcx.def_map.find(cur.id) { + Some(ast::def_variant(*)) => { + add_to_set(ccx.tcx, &found, + variant_opt(ccx.tcx, cur.id)); + } + Some(ast::def_class(*)) => { + add_to_set(ccx.tcx, &found, + lit(UnitLikeStructLit(cur.id))); + } + _ => {} + } + } + ast::pat_enum(*) | ast::pat_struct(*) => { + // This could be one of: a tuple-like enum variant, a + // struct-like enum variant, or a struct. + match ccx.tcx.def_map.find(cur.id) { + Some(ast::def_variant(*)) => { + add_to_set(ccx.tcx, &found, + variant_opt(ccx.tcx, cur.id)); + } + _ => {} + } + } + ast::pat_range(l1, l2) => { + add_to_set(ccx.tcx, &found, range(l1, l2)); + } + _ => {} } } return dvec::unwrap(move found); @@ -733,6 +808,21 @@ fn any_tup_pat(m: &[@Match], col: uint) -> bool { any_pat!(m, ast::pat_tup(_)) } +fn any_tuple_struct_pat(bcx: block, m: &[@Match], col: uint) -> bool { + vec::any(m, |br| { + let pat = br.pats[col]; + match pat.node { + ast::pat_enum(_, Some(_)) => { + match bcx.tcx().def_map.find(pat.id) { + Some(ast::def_class(*)) => true, + _ => false + } + } + _ => false + } + }) +} + type mk_fail = fn@() -> BasicBlockRef; fn pick_col(m: &[@Match]) -> uint { @@ -1028,6 +1118,29 @@ fn compile_submatch(bcx: block, return; } + if any_tuple_struct_pat(bcx, m, col) { + let struct_ty = node_id_type(bcx, pat_id); + let struct_element_count; + match ty::get(struct_ty).sty { + ty::ty_class(struct_id, _) => { + struct_element_count = + ty::lookup_class_fields(tcx, struct_id).len(); + } + _ => { + ccx.sess.bug(~"non-struct type in tuple struct pattern"); + } + } + + let llstructvals = vec::from_fn( + struct_element_count, |i| GEPi(bcx, val, struct_field(i))); + compile_submatch(bcx, + enter_tuple_struct(bcx, dm, m, col, val, + struct_element_count), + vec::append(llstructvals, vals_left), + chk); + return; + } + // Unbox in case of a box field if any_box_pat(m, col) { let llbox = Load(bcx, val); @@ -1316,7 +1429,7 @@ fn bind_irrefutable_pat(bcx: block, pat: @ast::pat, val: ValueRef, // Necessary since bind_irrefutable_pat is called outside trans_alt match pat.node { ast::pat_ident(_, _,inner) => { - if pat_is_variant(bcx.tcx().def_map, pat) { + if pat_is_variant_or_struct(bcx.tcx().def_map, pat) { return bcx; } @@ -1335,15 +1448,39 @@ fn bind_irrefutable_pat(bcx: block, pat: @ast::pat, val: ValueRef, for inner.each |inner_pat| { bcx = bind_irrefutable_pat(bcx, *inner_pat, val, true); } - } + } ast::pat_enum(_, sub_pats) => { - let pat_def = ccx.tcx.def_map.get(pat.id); - let vdefs = ast_util::variant_def_ids(pat_def); - let args = extract_variant_args(bcx, pat.id, vdefs, val); - for sub_pats.each |sub_pat| { - for vec::eachi(args.vals) |i, argval| { - bcx = bind_irrefutable_pat(bcx, sub_pat[i], - *argval, make_copy); + match bcx.tcx().def_map.find(pat.id) { + Some(ast::def_variant(*)) => { + let pat_def = ccx.tcx.def_map.get(pat.id); + let vdefs = ast_util::variant_def_ids(pat_def); + let args = extract_variant_args(bcx, pat.id, vdefs, val); + for sub_pats.each |sub_pat| { + for vec::eachi(args.vals) |i, argval| { + bcx = bind_irrefutable_pat(bcx, + sub_pat[i], + *argval, + make_copy); + } + } + } + Some(ast::def_class(*)) => { + match sub_pats { + None => { + // This is a unit-like struct. Nothing to do here. + } + Some(elems) => { + // This is the tuple variant case. + for vec::eachi(elems) |i, elem| { + let fldptr = GEPi(bcx, val, struct_field(i)); + bcx = bind_irrefutable_pat(bcx, *elem, fldptr, + make_copy); + } + } + } + } + _ => { + // Nothing to do here. } } } diff --git a/src/rustc/middle/trans/base.rs b/src/rustc/middle/trans/base.rs index 40792ce45ed..727958e3e5f 100644 --- a/src/rustc/middle/trans/base.rs +++ b/src/rustc/middle/trans/base.rs @@ -1893,12 +1893,14 @@ fn trans_struct_def(ccx: @crate_ctxt, struct_def: @ast::struct_def, // If this is a tuple-like struct, translate the constructor. match struct_def.ctor_id { - None => {} - Some(ctor_id) => { + // We only need to translate a constructor if there are fields; + // otherwise this is a unit-like struct. + Some(ctor_id) if struct_def.fields.len() > 0 => { let llfndecl = get_item_val(ccx, ctor_id); trans_tuple_struct(ccx, struct_def.fields, ctor_id, None, llfndecl); } + Some(_) | None => {} } } diff --git a/src/rustc/middle/trans/expr.rs b/src/rustc/middle/trans/expr.rs index 839a8241963..519aa9c44ec 100644 --- a/src/rustc/middle/trans/expr.rs +++ b/src/rustc/middle/trans/expr.rs @@ -664,6 +664,11 @@ fn trans_def_dps_unadjusted(bcx: block, ref_expr: @ast::expr, return bcx; } } + ast::def_class(*) => { + // Nothing to do here. + // XXX: May not be true in the case of classes with destructors. + return bcx; + } _ => { bcx.tcx().sess.span_bug(ref_expr.span, fmt!( "Non-DPS def %? referened by %s", diff --git a/src/rustc/middle/ty.rs b/src/rustc/middle/ty.rs index 65f77cefd02..8767c4c6253 100644 --- a/src/rustc/middle/ty.rs +++ b/src/rustc/middle/ty.rs @@ -2980,7 +2980,7 @@ fn expr_kind(tcx: ctxt, ast::expr_path(*) => { match resolve_expr(tcx, expr) { ast::def_fn(*) | ast::def_static_method(*) | - ast::def_variant(*) => RvalueDpsExpr, + ast::def_variant(*) | ast::def_class(*) => RvalueDpsExpr, // Note: there is actually a good case to be made that // def_args, particularly those of immediate type, ought to diff --git a/src/rustc/middle/typeck.rs b/src/rustc/middle/typeck.rs index 2e55dd702f0..d4df07f7eb8 100644 --- a/src/rustc/middle/typeck.rs +++ b/src/rustc/middle/typeck.rs @@ -48,7 +48,7 @@ use syntax::visit; use metadata::csearch; use util::common::{block_query, loop_query}; use syntax::codemap::span; -use pat_util::{pat_is_variant, pat_id_map, PatIdMap}; +use pat_util::{pat_id_map, PatIdMap}; use middle::ty; use middle::ty::{arg, field, node_type_table, mk_nil, ty_param_bounds_and_ty}; use middle::ty::{ty_param_substs_and_ty, vstore_uniq}; diff --git a/src/rustc/middle/typeck/check.rs b/src/rustc/middle/typeck/check.rs index 044b95915cd..b29e85643f1 100644 --- a/src/rustc/middle/typeck/check.rs +++ b/src/rustc/middle/typeck/check.rs @@ -376,7 +376,8 @@ fn check_fn(ccx: @crate_ctxt, let visit_pat = fn@(p: @ast::pat, &&e: (), v: visit::vt<()>) { match p.node { ast::pat_ident(_, path, _) - if !pat_util::pat_is_variant(fcx.ccx.tcx.def_map, p) => { + if !pat_util::pat_is_variant_or_struct(fcx.ccx.tcx.def_map, + p) => { assign(p.span, p.id, None); debug!("Pattern binding %s is assigned to %s", tcx.sess.str_of(path.idents[0]), @@ -467,10 +468,6 @@ fn check_struct(ccx: @crate_ctxt, struct_def: @ast::struct_def, for struct_def.methods.each |m| { check_method(ccx, *m, self_ty, local_def(id)); } - // Check that there's at least one field - if struct_def.fields.len() < 1u { - ccx.tcx.sess.span_err(span, ~"a struct must have at least one field"); - } // Check that the class is instantiable check_instantiable(ccx.tcx, span, id); } diff --git a/src/rustc/middle/typeck/check/alt.rs b/src/rustc/middle/typeck/check/alt.rs index 5a62ad0461d..41be34a713c 100644 --- a/src/rustc/middle/typeck/check/alt.rs +++ b/src/rustc/middle/typeck/check/alt.rs @@ -1,6 +1,6 @@ use syntax::print::pprust; use syntax::ast_util::{walk_pat}; -use pat_util::{pat_is_variant}; +use pat_util::{pat_is_variant_or_struct}; fn check_alt(fcx: @fn_ctxt, expr: @ast::expr, @@ -74,7 +74,7 @@ fn check_legality_of_move_bindings(fcx: @fn_ctxt, if !any_by_move { return; } // pointless micro-optimization for pats.each |pat| { do walk_pat(*pat) |p| { - if !pat_is_variant(def_map, p) { + if !pat_is_variant_or_struct(def_map, p) { match p.node { ast::pat_ident(ast::bind_by_move, _, sub) => { // check legality of moving out of the enum @@ -391,7 +391,8 @@ fn check_pat(pcx: pat_ctxt, pat: @ast::pat, expected: ty::t) { } fcx.write_ty(pat.id, b_ty); } - ast::pat_ident(bm, name, sub) if !pat_is_variant(tcx.def_map, pat) => { + ast::pat_ident(bm, name, sub) + if !pat_is_variant_or_struct(tcx.def_map, pat) => { let vid = lookup_local(fcx, pat.span, pat.id); let mut typ = ty::mk_var(tcx, vid); diff --git a/src/test/run-pass/tuple-struct-destructuring.rs b/src/test/run-pass/tuple-struct-destructuring.rs new file mode 100644 index 00000000000..cffd9d828cb --- /dev/null +++ b/src/test/run-pass/tuple-struct-destructuring.rs @@ -0,0 +1,10 @@ +struct Foo(int, int); + +fn main() { + let x = Foo(1, 2); + let Foo(y, z) = x; + io::println(fmt!("%d %d", y, z)); + assert y == 1; + assert z == 2; +} + diff --git a/src/test/run-pass/tuple-struct-matching.rs b/src/test/run-pass/tuple-struct-matching.rs new file mode 100644 index 00000000000..923e8cbc09d --- /dev/null +++ b/src/test/run-pass/tuple-struct-matching.rs @@ -0,0 +1,13 @@ +struct Foo(int, int); + +fn main() { + let x = Foo(1, 2); + match x { + Foo(a, b) => { + assert a == 1; + assert b == 2; + io::println(fmt!("%d %d", a, b)); + } + } +} + diff --git a/src/test/run-pass/unit-like-struct.rs b/src/test/run-pass/unit-like-struct.rs new file mode 100644 index 00000000000..e5eb50a8afd --- /dev/null +++ b/src/test/run-pass/unit-like-struct.rs @@ -0,0 +1,9 @@ +struct Foo; + +fn main() { + let x: Foo = Foo; + match x { + Foo => { io::println("hi"); } + } +} +