mirror of
https://github.com/rust-lang/rust.git
synced 2024-10-31 14:31:55 +00:00
rustc: Implement translation of pattern matching for tuple structs and unit-like structs. r=nmatsakis
This commit is contained in:
parent
106f9976ab
commit
4165edff22
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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<ident, node_id>;
|
||||
|
||||
@ -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);
|
||||
}
|
||||
_ => {}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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<Opt>, 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.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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 => {}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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",
|
||||
|
@ -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
|
||||
|
@ -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};
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
10
src/test/run-pass/tuple-struct-destructuring.rs
Normal file
10
src/test/run-pass/tuple-struct-destructuring.rs
Normal file
@ -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;
|
||||
}
|
||||
|
13
src/test/run-pass/tuple-struct-matching.rs
Normal file
13
src/test/run-pass/tuple-struct-matching.rs
Normal file
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
9
src/test/run-pass/unit-like-struct.rs
Normal file
9
src/test/run-pass/unit-like-struct.rs
Normal file
@ -0,0 +1,9 @@
|
||||
struct Foo;
|
||||
|
||||
fn main() {
|
||||
let x: Foo = Foo;
|
||||
match x {
|
||||
Foo => { io::println("hi"); }
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user