diff --git a/src/rustc/middle/borrowck.rs b/src/rustc/middle/borrowck.rs index 1b1ec022d3ff3..ccc2ca9888abd 100644 --- a/src/rustc/middle/borrowck.rs +++ b/src/rustc/middle/borrowck.rs @@ -594,7 +594,7 @@ impl borrowck_ctxt { // mutable structure. fn inherent_mutability(ck: comp_kind) -> mutability { match ck { - comp_tuple | comp_variant(_) => m_imm, - comp_field(_, m) | comp_index(_, m) => m + comp_tuple | comp_anon_field | comp_variant(_) => m_imm, + comp_field(_, m) | comp_index(_, m) => m } } diff --git a/src/rustc/middle/borrowck/gather_loans.rs b/src/rustc/middle/borrowck/gather_loans.rs index e0eb5519d4da3..23f0d9edbfae2 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/borrowck/loan.rs b/src/rustc/middle/borrowck/loan.rs index 71414e6e72453..b302349722073 100644 --- a/src/rustc/middle/borrowck/loan.rs +++ b/src/rustc/middle/borrowck/loan.rs @@ -116,7 +116,8 @@ impl LoanContext { // overwritten and the component along with it. self.loan_stable_comp(cmt, cmt_base, req_mutbl, m) } - cat_comp(cmt_base, comp_tuple) => { + cat_comp(cmt_base, comp_tuple) | + cat_comp(cmt_base, comp_anon_field) => { // As above. self.loan_stable_comp(cmt, cmt_base, req_mutbl, m_imm) } diff --git a/src/rustc/middle/borrowck/preserve.rs b/src/rustc/middle/borrowck/preserve.rs index 556ea7867cfca..c27ceca055fdc 100644 --- a/src/rustc/middle/borrowck/preserve.rs +++ b/src/rustc/middle/borrowck/preserve.rs @@ -119,7 +119,8 @@ priv impl &preserve_ctxt { } cat_comp(cmt_base, comp_field(*)) | cat_comp(cmt_base, comp_index(*)) | - cat_comp(cmt_base, comp_tuple) => { + cat_comp(cmt_base, comp_tuple) | + cat_comp(cmt_base, comp_anon_field) => { // Most embedded components: if the base is stable, the // type never changes. self.preserve(cmt_base) diff --git a/src/rustc/middle/check_alt.rs b/src/rustc/middle/check_alt.rs index 7ed7829cf343b..5b35ed98a837d 100644 --- a/src/rustc/middle/check_alt.rs +++ b/src/rustc/middle/check_alt.rs @@ -355,6 +355,15 @@ fn specialize(tcx: ty::ctxt, r: ~[@pat], ctor_id: ctor, arity: uint, Some(vec::append(args, vec::tail(r))) } def_variant(_, _) => None, + def_class(*) => { + // XXX: Is this right? --pcw + let new_args; + match args { + Some(args) => new_args = args, + None => new_args = vec::from_elem(arity, wild()) + } + Some(vec::append(new_args, vec::tail(r))) + } _ => None } } diff --git a/src/rustc/middle/kind.rs b/src/rustc/middle/kind.rs index 4c66809c16fe6..8eace4f5cf114 100644 --- a/src/rustc/middle/kind.rs +++ b/src/rustc/middle/kind.rs @@ -286,6 +286,7 @@ fn check_expr(e: @expr, cx: ctx, v: visit::vt) { maybe_copy(cx, source, Some(("casted values must be copyable", try_adding))); check_cast_for_escaping_regions(cx, source, e); + check_kind_bounds_of_cast(cx, source, e); } expr_copy(expr) => check_copy_ex(cx, expr, false, Some(("explicit copy requires a copyable argument", ""))), @@ -607,6 +608,26 @@ fn check_cast_for_escaping_regions( } } +/// Ensures that values placed into a ~Trait are copyable and sendable. +fn check_kind_bounds_of_cast(cx: ctx, source: @expr, target: @expr) { + let target_ty = ty::expr_ty(cx.tcx, target); + match ty::get(target_ty).sty { + ty::ty_trait(_, _, ty::vstore_uniq) => { + let source_ty = ty::expr_ty(cx.tcx, source); + let source_kind = ty::type_kind(cx.tcx, source_ty); + if !ty::kind_can_be_copied(source_kind) { + cx.tcx.sess.span_err(target.span, + ~"uniquely-owned trait objects must be copyable"); + } + if !ty::kind_can_be_sent(source_kind) { + cx.tcx.sess.span_err(target.span, + ~"uniquely-owned trait objects must be sendable"); + } + } + _ => {} // Nothing to do. + } +} + // // Local Variables: // mode: rust diff --git a/src/rustc/middle/mem_categorization.rs b/src/rustc/middle/mem_categorization.rs index 8ee9adc4e2f3b..3d018ea8b9482 100644 --- a/src/rustc/middle/mem_categorization.rs +++ b/src/rustc/middle/mem_categorization.rs @@ -162,6 +162,8 @@ impl ptr_kind : cmp::Eq { // structure accessible without a dereference": enum comp_kind { comp_tuple, // elt in a tuple + comp_anon_field, // anonymous field (in e.g. + // struct Foo(int, int); comp_variant(ast::def_id), // internals to a variant of given enum comp_field(ast::ident, // name of field ast::mutability), // declared mutability of field @@ -178,6 +180,12 @@ impl comp_kind : cmp::Eq { _ => false } } + comp_anon_field => { + match (*other) { + comp_anon_field => true, + _ => false + } + } comp_variant(e0a) => { match (*other) { comp_variant(e0b) => e0a == e0b, @@ -773,6 +781,14 @@ impl &mem_categorization_ctxt { ty: self.tcx.ty(elt)} } + fn cat_anon_struct_field(elt: N, cmt: cmt) -> cmt { + @{id: elt.id(), span: elt.span(), + cat: cat_comp(cmt, comp_anon_field), + lp: cmt.lp.map(|l| @lp_comp(*l, comp_anon_field)), + mutbl: cmt.mutbl, // imm iff in an immutable context + ty: self.tcx.ty(elt)} + } + fn cat_method_ref(expr: @ast::expr, expr_ty: ty::t) -> cmt { @{id:expr.id, span:expr.span, cat:cat_special(sk_method), lp:None, @@ -832,16 +848,26 @@ impl &mem_categorization_ctxt { // variant(*) } ast::pat_enum(_, Some(subpats)) => { - // variant(x, y, z) - let enum_did = match self.tcx.def_map.find(pat.id) { - Some(ast::def_variant(enum_did, _)) => enum_did, - e => tcx.sess.span_bug(pat.span, - fmt!("resolved to %?, not variant", e)) - }; - - for subpats.each |subpat| { - let subcmt = self.cat_variant(*subpat, enum_did, cmt); - self.cat_pattern(subcmt, *subpat, op); + match self.tcx.def_map.find(pat.id) { + Some(ast::def_variant(enum_did, _)) => { + // variant(x, y, z) + for subpats.each |subpat| { + let subcmt = self.cat_variant(*subpat, enum_did, cmt); + self.cat_pattern(subcmt, *subpat, op); + } + } + Some(ast::def_class(*)) => { + for subpats.each |subpat| { + let cmt_field = self.cat_anon_struct_field(*subpat, + cmt); + self.cat_pattern(cmt_field, *subpat, op); + } + } + _ => { + self.tcx.sess.span_bug( + pat.span, + ~"enum pattern didn't resolve to enum or struct"); + } } } @@ -932,6 +958,7 @@ impl &mem_categorization_ctxt { comp_field(fld, _) => self.tcx.sess.str_of(fld), comp_index(*) => ~"[]", comp_tuple => ~"()", + comp_anon_field => ~"", comp_variant(_) => ~"" } } @@ -984,6 +1011,7 @@ impl &mem_categorization_ctxt { } cat_comp(_, comp_field(*)) => mut_str + ~" field", cat_comp(_, comp_tuple) => ~"tuple content", + cat_comp(_, comp_anon_field) => ~"anonymous field", cat_comp(_, comp_variant(_)) => ~"enum content", cat_comp(_, comp_index(t, _)) => { match ty::get(t).sty { diff --git a/src/rustc/middle/pat_util.rs b/src/rustc/middle/pat_util.rs index 48ebda9a67e03..9196a0b22caf8 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 97551162de58f..8ebebfa112166 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)); @@ -4286,9 +4289,10 @@ impl Resolver { } pat_ident(_, path, _) | pat_enum(path, _) => { - // These two must be enum variants. + // These two must be enum variants or structs. match self.resolve_path(path, ValueNS, false, visitor) { - Some(def @ def_variant(*)) => { + Some(def @ def_variant(*)) | + Some(def @ def_class(*)) => { self.record_def(pattern.id, def); } Some(_) => { @@ -4348,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 => { @@ -4363,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; } } } @@ -4382,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 b3776e499946a..0908eae34dcd7 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)); + 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_range(l1, l2) => { - add_to_set(ccx.tcx, &found, range(l1, l2)); + } + 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 40792ce45ed4f..727958e3e5f8c 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/common.rs b/src/rustc/middle/trans/common.rs index 7f234349d711f..b02d12e0b7363 100644 --- a/src/rustc/middle/trans/common.rs +++ b/src/rustc/middle/trans/common.rs @@ -971,10 +971,15 @@ fn T_captured_tydescs(cx: @crate_ctxt, n: uint) -> TypeRef { fn T_opaque_trait(cx: @crate_ctxt, vstore: ty::vstore) -> TypeRef { match vstore { - ty::vstore_box => - T_struct(~[T_ptr(cx.tydesc_type), T_opaque_box_ptr(cx)]), - _ => - T_struct(~[T_ptr(cx.tydesc_type), T_ptr(T_i8())]) + ty::vstore_box => { + T_struct(~[T_ptr(cx.tydesc_type), T_opaque_box_ptr(cx)]) + } + ty::vstore_uniq => { + T_struct(~[T_ptr(cx.tydesc_type), + T_unique_ptr(T_unique(cx, T_i8())), + T_ptr(cx.tydesc_type)]) + } + _ => T_struct(~[T_ptr(cx.tydesc_type), T_ptr(T_i8())]) } } diff --git a/src/rustc/middle/trans/datum.rs b/src/rustc/middle/trans/datum.rs index 5e11cdd479436..700ac402a8ad4 100644 --- a/src/rustc/middle/trans/datum.rs +++ b/src/rustc/middle/trans/datum.rs @@ -651,6 +651,41 @@ impl Datum { } }; } + ty::ty_class(did, ref substs) => { + // Check whether this struct is a newtype struct. + let fields = ty::class_items_as_fields(ccx.tcx, did, substs); + if fields.len() != 1 || fields[0].ident != + syntax::parse::token::special_idents::unnamed_field { + return None; + } + + let ty = fields[0].mt.ty; + return match self.mode { + ByRef => { + // Recast lv.val as a pointer to the newtype rather + // than a pointer to the struct type. + // XXX: This isn't correct for structs with + // destructors. + Some(Datum { + val: GEPi(bcx, self.val, [0, 0, 0]), + ty: ty, + mode: ByRef, + source: FromLvalue + }) + } + ByValue => { + // Actually, this case cannot happen right now, + // because structs are never immediate. But in + // principle, newtype'd immediate values should be + // immediate, and in that case the * would be a no-op + // except for changing the type, so I am putting this + // code in place here to do the right thing if this + // change ever goes through. + assert ty::type_is_immediate(ty); + Some(Datum {ty: ty, ..self}) + } + } + } _ => { // not derefable. return None; } diff --git a/src/rustc/middle/trans/expr.rs b/src/rustc/middle/trans/expr.rs index dee553536048a..bfb3679ba6896 100644 --- a/src/rustc/middle/trans/expr.rs +++ b/src/rustc/middle/trans/expr.rs @@ -600,7 +600,16 @@ fn trans_rvalue_dps_unadjusted(bcx: block, expr: @ast::expr, DontAutorefArg); } ast::expr_cast(val, _) => { - return meth::trans_trait_cast(bcx, val, expr.id, dest); + match ty::get(node_id_type(bcx, expr.id)).sty { + ty::ty_trait(_, _, vstore) => { + return meth::trans_trait_cast(bcx, val, expr.id, dest, + vstore); + } + _ => { + bcx.tcx().sess.span_bug(expr.span, + ~"expr_cast of non-trait"); + } + } } ast::expr_assign_op(op, dst, src) => { return trans_assign_op(bcx, expr, op, dst, src); @@ -650,6 +659,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/trans/glue.rs b/src/rustc/middle/trans/glue.rs index af9f2899a54d0..76d5770ac3d27 100644 --- a/src/rustc/middle/trans/glue.rs +++ b/src/rustc/middle/trans/glue.rs @@ -482,7 +482,11 @@ fn make_drop_glue(bcx: block, v0: ValueRef, t: ty::t) { decr_refcnt_maybe_free(bcx, llbox, ty::mk_opaque_box(ccx.tcx)) } ty::ty_trait(_, _, ty::vstore_uniq) => { - ccx.tcx.sess.unimpl(~"drop of unique trait"); + let lluniquevalue = GEPi(bcx, v0, [0, 1]); + let lltydesc = Load(bcx, GEPi(bcx, v0, [0, 2])); + call_tydesc_glue_full(bcx, lluniquevalue, lltydesc, + abi::tydesc_field_free_glue, None); + bcx } ty::ty_opaque_closure_ptr(ck) => { closure::make_opaque_cbox_drop_glue(bcx, ck, v0) @@ -536,11 +540,18 @@ fn make_take_glue(bcx: block, v: ValueRef, t: ty::t) { ty::ty_fn(_) => { closure::make_fn_glue(bcx, v, t, take_ty) } - ty::ty_trait(_, _, _) => { + ty::ty_trait(_, _, ty::vstore_box) => { let llbox = Load(bcx, GEPi(bcx, v, [0u, 1u])); incr_refcnt_of_boxed(bcx, llbox); bcx } + ty::ty_trait(_, _, ty::vstore_uniq) => { + let llval = GEPi(bcx, v, [0, 1]); + let lltydesc = Load(bcx, GEPi(bcx, v, [0, 2])); + call_tydesc_glue_full(bcx, llval, lltydesc, + abi::tydesc_field_take_glue, None); + bcx + } ty::ty_opaque_closure_ptr(ck) => { closure::make_opaque_cbox_take_glue(bcx, ck, v) } diff --git a/src/rustc/middle/trans/meth.rs b/src/rustc/middle/trans/meth.rs index e7c134fe54697..8305a4f7dab48 100644 --- a/src/rustc/middle/trans/meth.rs +++ b/src/rustc/middle/trans/meth.rs @@ -650,7 +650,8 @@ fn make_impl_vtable(ccx: @crate_ctxt, impl_id: ast::def_id, substs: ~[ty::t], fn trans_trait_cast(bcx: block, val: @ast::expr, id: ast::node_id, - dest: expr::Dest) + dest: expr::Dest, + vstore: ty::vstore) -> block { let mut bcx = bcx; @@ -666,25 +667,54 @@ fn trans_trait_cast(bcx: block, let ccx = bcx.ccx(); let v_ty = expr_ty(bcx, val); - let mut llboxdest = GEPi(bcx, lldest, [0u, 1u]); - if bcx.tcx().legacy_boxed_traits.contains_key(id) { - // Allocate an @ box and store the value into it - let {bcx: new_bcx, box: llbox, body: body} = malloc_boxed(bcx, v_ty); - bcx = new_bcx; - add_clean_free(bcx, llbox, heap_shared); - bcx = expr::trans_into(bcx, val, SaveIn(body)); - revoke_clean(bcx, llbox); - - // Store the @ box into the pair - Store(bcx, llbox, PointerCast(bcx, llboxdest, T_ptr(val_ty(llbox)))); - } else { - // Just store the @ box into the pair. - llboxdest = PointerCast(bcx, llboxdest, - T_ptr(type_of::type_of(bcx.ccx(), v_ty))); - bcx = expr::trans_into(bcx, val, SaveIn(llboxdest)); + match vstore { + ty::vstore_slice(*) | ty::vstore_box => { + let mut llboxdest = GEPi(bcx, lldest, [0u, 1u]); + if bcx.tcx().legacy_boxed_traits.contains_key(id) { + // Allocate an @ box and store the value into it + let {bcx: new_bcx, box: llbox, body: body} = + malloc_boxed(bcx, v_ty); + bcx = new_bcx; + add_clean_free(bcx, llbox, heap_shared); + bcx = expr::trans_into(bcx, val, SaveIn(body)); + revoke_clean(bcx, llbox); + + // Store the @ box into the pair + Store(bcx, llbox, PointerCast(bcx, + llboxdest, + T_ptr(val_ty(llbox)))); + } else { + // Just store the @ box into the pair. + llboxdest = PointerCast(bcx, + llboxdest, + T_ptr(type_of::type_of(bcx.ccx(), + v_ty))); + bcx = expr::trans_into(bcx, val, SaveIn(llboxdest)); + } + } + ty::vstore_uniq => { + // Translate the uniquely-owned value into the second element of + // the triple. (The first element is the vtable.) + let mut llvaldest = GEPi(bcx, lldest, [0, 1]); + llvaldest = PointerCast(bcx, + llvaldest, + T_ptr(type_of::type_of(bcx.ccx(), v_ty))); + bcx = expr::trans_into(bcx, val, SaveIn(llvaldest)); + + // Get the type descriptor of the wrapped value and store it into + // the third element of the triple as well. + let tydesc = get_tydesc(bcx.ccx(), v_ty); + glue::lazily_emit_all_tydesc_glue(bcx.ccx(), tydesc); + let lltydescdest = GEPi(bcx, lldest, [0, 2]); + Store(bcx, tydesc.tydesc, lltydescdest); + } + _ => { + bcx.tcx().sess.span_bug(val.span, ~"unexpected vstore in \ + trans_trait_cast"); + } } - // Store the vtable into the pair + // Store the vtable into the pair or triple. let orig = ccx.maps.vtable_map.get(id)[0]; let orig = resolve_vtable_in_fn_ctxt(bcx.fcx, orig); let vtable = get_vtable(bcx.ccx(), orig); diff --git a/src/rustc/middle/ty.rs b/src/rustc/middle/ty.rs index f44f6a3ce628d..7db69f6b0ead4 100644 --- a/src/rustc/middle/ty.rs +++ b/src/rustc/middle/ty.rs @@ -2597,6 +2597,16 @@ fn deref_sty(cx: ctxt, sty: &sty, expl: bool) -> Option { } } + ty_class(did, ref substs) => { + let fields = class_items_as_fields(cx, did, substs); + if fields.len() == 1 && fields[0].ident == + syntax::parse::token::special_idents::unnamed_field { + Some({ty: fields[0].mt.ty, mutbl: ast::m_imm}) + } else { + None + } + } + _ => None } } @@ -2998,7 +3008,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 @@ -3570,6 +3580,29 @@ fn ty_to_def_id(ty: t) -> Option { } } +/// Returns the def ID of the constructor for the given tuple-like struct, or +/// None if the struct is not tuple-like. Fails if the given def ID does not +/// refer to a struct at all. +fn struct_ctor_id(cx: ctxt, struct_did: ast::def_id) -> Option { + if struct_did.crate != ast::local_crate { + // XXX: Cross-crate functionality. + cx.sess.unimpl(~"constructor ID of cross-crate tuple structs"); + } + + match cx.items.find(struct_did.node) { + Some(ast_map::node_item(item, _)) => { + match item.node { + ast::item_class(struct_def, _) => { + struct_def.ctor_id.map(|ctor_id| + ast_util::local_def(*ctor_id)) + } + _ => cx.sess.bug(~"called struct_ctor_id on non-struct") + } + } + _ => cx.sess.bug(~"called struct_ctor_id on non-struct") + } +} + // Enum information type variant_info = @{args: ~[t], ctor_ty: t, name: ast::ident, id: ast::def_id, disr_val: int}; diff --git a/src/rustc/middle/typeck.rs b/src/rustc/middle/typeck.rs index 2e55dd702f09b..d4df07f7eb897 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/astconv.rs b/src/rustc/middle/typeck/astconv.rs index da7a71b3efbf7..d793955e447dc 100644 --- a/src/rustc/middle/typeck/astconv.rs +++ b/src/rustc/middle/typeck/astconv.rs @@ -190,13 +190,14 @@ fn ast_ty_to_ty( match ty::get(result.ty).sty { ty::ty_trait(trait_def_id, substs, _) => { match vst { - ty::vstore_box | ty::vstore_slice(*) => {} + ty::vstore_box | ty::vstore_slice(*) | + ty::vstore_uniq => {} _ => { - tcx.sess.span_unimpl(path.span, - ~"`~trait` is \ - unimplemented; use \ - `@trait` instead for \ - now"); + tcx.sess.span_err(path.span, + ~"@trait, ~trait or &trait \ + are the only supported \ + forms of casting-to-\ + trait"); } } return ty::mk_trait(tcx, trait_def_id, substs, vst); diff --git a/src/rustc/middle/typeck/check.rs b/src/rustc/middle/typeck/check.rs index 339a035b35cfa..c0c9f03009dfe 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); } @@ -1763,6 +1760,12 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, with a single variant which has a \ single argument"); } + ty::ty_class(*) => { + tcx.sess.span_err( + expr.span, + ~"can only dereference structs with one anonymous \ + field"); + } _ => { tcx.sess.span_err( expr.span, diff --git a/src/rustc/middle/typeck/check/alt.rs b/src/rustc/middle/typeck/check/alt.rs index a8308bb1b3c24..069eba62ebd08 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 @@ -123,66 +123,98 @@ fn check_pat_variant(pcx: pat_ctxt, pat: @ast::pat, path: @ast::path, let fcx = pcx.fcx; let tcx = pcx.fcx.ccx.tcx; - // Lookup the enum and variant def ids: - let v_def = lookup_def(pcx.fcx, path.span, pat.id); - let v_def_ids = ast_util::variant_def_ids(v_def); + let arg_types, kind_name; - // Assign the pattern the type of the *enum*, not the variant. - let enum_tpt = ty::lookup_item_type(tcx, v_def_ids.enm); - instantiate_path(pcx.fcx, path, enum_tpt, pat.span, pat.id, - pcx.block_region); - - // Take the enum type params out of `expected`. + // Check to see whether this is an enum or a struct. match structure_of(pcx.fcx, pat.span, expected) { - ty::ty_enum(_, ref expected_substs) => { - // check that the type of the value being matched is a subtype - // of the type of the pattern: - let pat_ty = fcx.node_ty(pat.id); - demand::suptype(fcx, pat.span, pat_ty, expected); - - // Get the expected types of the arguments. - let arg_types = { - let vinfo = - ty::enum_variant_with_id( - tcx, v_def_ids.enm, v_def_ids.var); - vinfo.args.map(|t| { ty::subst(tcx, expected_substs, *t) }) - }; - let arg_len = arg_types.len(), subpats_len = match subpats { - None => arg_len, - Some(ps) => ps.len() - }; - if arg_len > 0u { - // N-ary variant. - if arg_len != subpats_len { - let s = fmt!("this pattern has %u field%s, but the \ - corresponding variant has %u field%s", - subpats_len, - if subpats_len == 1u { ~"" } else { ~"s" }, - arg_len, - if arg_len == 1u { ~"" } else { ~"s" }); - tcx.sess.span_fatal(pat.span, s); - } - - do subpats.iter() |pats| { - for vec::each2(*pats, arg_types) |subpat, arg_ty| { - check_pat(pcx, *subpat, *arg_ty); - } + ty::ty_enum(_, ref expected_substs) => { + // Lookup the enum and variant def ids: + let v_def = lookup_def(pcx.fcx, path.span, pat.id); + let v_def_ids = ast_util::variant_def_ids(v_def); + + // Assign the pattern the type of the *enum*, not the variant. + let enum_tpt = ty::lookup_item_type(tcx, v_def_ids.enm); + instantiate_path(pcx.fcx, path, enum_tpt, pat.span, pat.id, + pcx.block_region); + + // check that the type of the value being matched is a subtype + // of the type of the pattern: + let pat_ty = fcx.node_ty(pat.id); + demand::suptype(fcx, pat.span, pat_ty, expected); + + // Get the expected types of the arguments. + arg_types = { + let vinfo = + ty::enum_variant_with_id( + tcx, v_def_ids.enm, v_def_ids.var); + vinfo.args.map(|t| { ty::subst(tcx, expected_substs, *t) }) }; - } else if subpats_len > 0u { - tcx.sess.span_fatal - (pat.span, fmt!("this pattern has %u field%s, \ - but the corresponding variant has no fields", - subpats_len, - if subpats_len == 1u { ~"" } - else { ~"s" })); + + kind_name = "variant"; } - } - _ => { + ty::ty_class(struct_def_id, ref expected_substs) => { + // Assign the pattern the type of the struct. + let struct_tpt = ty::lookup_item_type(tcx, struct_def_id); + instantiate_path(pcx.fcx, path, struct_tpt, pat.span, pat.id, + pcx.block_region); + + // Check that the type of the value being matched is a subtype of + // the type of the pattern. + let pat_ty = fcx.node_ty(pat.id); + demand::suptype(fcx, pat.span, pat_ty, expected); + + // Get the expected types of the arguments. + let class_fields = ty::class_items_as_fields( + tcx, struct_def_id, expected_substs); + arg_types = class_fields.map(|field| field.mt.ty); + + kind_name = "structure"; + } + _ => { + tcx.sess.span_fatal( + pat.span, + fmt!("mismatched types: expected enum or structure but \ + found `%s`", + fcx.infcx().ty_to_str(expected))); + } + } + + let arg_len = arg_types.len(); + + // Count the number of subpatterns. + let subpats_len; + match subpats { + None => subpats_len = arg_len, + Some(subpats) => subpats_len = subpats.len() + } + + if arg_len > 0u { + // N-ary variant. + if arg_len != subpats_len { + let s = fmt!("this pattern has %u field%s, but the corresponding \ + %s has %u field%s", + subpats_len, + if subpats_len == 1u { ~"" } else { ~"s" }, + kind_name, + arg_len, + if arg_len == 1u { ~"" } else { ~"s" }); + // XXX: This should not be fatal. + tcx.sess.span_fatal(pat.span, s); + } + + do subpats.iter() |pats| { + for vec::each2(*pats, arg_types) |subpat, arg_ty| { + check_pat(pcx, *subpat, *arg_ty); + } + }; + } else if subpats_len > 0u { tcx.sess.span_fatal - (pat.span, - fmt!("mismatched types: expected enum but found `%s`", - fcx.infcx().ty_to_str(expected))); - } + (pat.span, fmt!("this pattern has %u field%s, but the \ + corresponding %s has no fields", + subpats_len, + if subpats_len == 1u { ~"" } + else { ~"s" }, + kind_name)); } } @@ -355,7 +387,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/rustc/middle/typeck/check/vtable.rs b/src/rustc/middle/typeck/check/vtable.rs index 345b8246b4278..dd7ca0cf5ad93 100644 --- a/src/rustc/middle/typeck/check/vtable.rs +++ b/src/rustc/middle/typeck/check/vtable.rs @@ -524,14 +524,18 @@ fn early_resolve_expr(ex: @ast::expr, &&fcx: @fn_ctxt, is_early: bool) { None => { // Try the new-style boxed trait; "@int as @Trait". // Or the new-style region trait; "&int as &Trait". + // Or the new-style uniquely-owned trait; "~int as + // ~Trait". let mut err = false; let ty = structurally_resolved_type(fcx, ex.span, ty); match ty::get(ty).sty { - ty::ty_box(mt) | ty::ty_rptr(_, mt) => { + ty::ty_box(mt) | ty::ty_rptr(_, mt) | + ty::ty_uniq(mt) => { // Ensure that the trait vstore and the pointer // type match. match (ty::get(ty).sty, vstore) { (ty::ty_box(_), ty::vstore_box) | + (ty::ty_uniq(_), ty::vstore_uniq) | (ty::ty_rptr(*), ty::vstore_slice(*)) => { let vtable_opt = lookup_vtable_invariant(fcx, @@ -584,6 +588,14 @@ fn early_resolve_expr(ex: @ast::expr, &&fcx: @fn_ctxt, is_early: bool) { a borrowed \ trait"); } + (ty::ty_uniq(*), _) => { + fcx.ccx.tcx.sess.span_err(ex.span, + ~"must cast \ + a unique \ + pointer to \ + a uniquely-\ + owned trait"); + } _ => { fcx.ccx.tcx.sess.impossible_case( ex.span, diff --git a/src/test/compile-fail/tuple-struct-nonexhaustive.rs b/src/test/compile-fail/tuple-struct-nonexhaustive.rs new file mode 100644 index 0000000000000..a32d598686c8c --- /dev/null +++ b/src/test/compile-fail/tuple-struct-nonexhaustive.rs @@ -0,0 +1,11 @@ +struct Foo(int, int); + +fn main() { + let x = Foo(1, 2); + match x { //~ ERROR non-exhaustive + Foo(1, b) => io::println(fmt!("%d", b)), + Foo(2, b) => io::println(fmt!("%d", b)) + } +} + + diff --git a/src/test/compile-fail/unique-object-noncopyable.rs b/src/test/compile-fail/unique-object-noncopyable.rs new file mode 100644 index 0000000000000..2d4c391841bf4 --- /dev/null +++ b/src/test/compile-fail/unique-object-noncopyable.rs @@ -0,0 +1,21 @@ +trait Foo { + fn f(); +} + +struct Bar { + x: int, + drop {} +} + +impl Bar : Foo { + fn f() { + io::println("hi"); + } +} + +fn main() { + let x = ~Bar { x: 10 }; + let y = (move x) as ~Foo; //~ ERROR uniquely-owned trait objects must be copyable + let _z = copy y; +} + diff --git a/src/test/run-pass/struct-deref.rs b/src/test/run-pass/struct-deref.rs new file mode 100644 index 0000000000000..74726f3c867fd --- /dev/null +++ b/src/test/run-pass/struct-deref.rs @@ -0,0 +1,7 @@ +struct Foo(int); + +fn main() { + let x: Foo = Foo(2); + assert *x == 2; +} + 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 0000000000000..cffd9d828cbb1 --- /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 0000000000000..923e8cbc09d5d --- /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/unique-object.rs b/src/test/run-pass/unique-object.rs new file mode 100644 index 0000000000000..952ecde35d185 --- /dev/null +++ b/src/test/run-pass/unique-object.rs @@ -0,0 +1,22 @@ +trait Foo { + fn f(); +} + +struct Bar { + x: int +} + +impl Bar : Foo { + fn f() { + io::println("hi"); + } +} + +fn main() { + let x = ~Bar { x: 10 }; + let y = x as ~Foo; + let z = copy y; + y.f(); + z.f(); +} + 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 0000000000000..e5eb50a8afd16 --- /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"); } + } +} +