diff --git a/src/libcore/extfmt.rs b/src/libcore/extfmt.rs index 2b2180e7efcc0..c7139b169349c 100644 --- a/src/libcore/extfmt.rs +++ b/src/libcore/extfmt.rs @@ -85,7 +85,7 @@ pub mod ct { pub enum Piece { PieceString(~str), PieceConv(Conv), } pub type ErrorFn = fn@(&str) -> ! ; - pub fn parse_fmt_string(s: &str, error: ErrorFn) -> ~[Piece] { + pub fn parse_fmt_string(s: &str, err: ErrorFn) -> ~[Piece] { let mut pieces: ~[Piece] = ~[]; let lim = str::len(s); let mut buf = ~""; @@ -103,7 +103,7 @@ pub mod ct { if curr == ~"%" { i += 1; if i >= lim { - error(~"unterminated conversion at end of string"); + err(~"unterminated conversion at end of string"); } let curr2 = str::slice(s, i, i+1); if curr2 == ~"%" { @@ -111,7 +111,7 @@ pub mod ct { i += 1; } else { buf = flush_buf(move buf, &mut pieces); - let rs = parse_conversion(s, i, lim, error); + let rs = parse_conversion(s, i, lim, err); pieces.push(copy rs.piece); i = rs.next; } @@ -143,13 +143,13 @@ pub mod ct { } } pub fn parse_conversion(s: &str, i: uint, lim: uint, - error: ErrorFn) -> + err: ErrorFn) -> {piece: Piece, next: uint} { let parm = parse_parameter(s, i, lim); let flags = parse_flags(s, parm.next, lim); let width = parse_count(s, flags.next, lim); let prec = parse_precision(s, width.next, lim); - let ty = parse_type(s, prec.next, lim, error); + let ty = parse_type(s, prec.next, lim, err); return {piece: PieceConv({param: parm.param, flags: copy flags.flags, @@ -239,9 +239,9 @@ pub mod ct { } } else { {count: CountImplied, next: i} }; } - pub fn parse_type(s: &str, i: uint, lim: uint, error: ErrorFn) -> + pub fn parse_type(s: &str, i: uint, lim: uint, err: ErrorFn) -> {ty: Ty, next: uint} { - if i >= lim { error(~"missing type in conversion"); } + if i >= lim { err(~"missing type in conversion"); } let tstr = str::slice(s, i, i+1u); // FIXME (#2249): Do we really want two signed types here? // How important is it to be printf compatible? @@ -268,7 +268,7 @@ pub mod ct { TyFloat } else if tstr == ~"?" { TyPoly - } else { error(~"unknown type in conversion: " + tstr) }; + } else { err(~"unknown type in conversion: " + tstr) }; return {ty: t, next: i + 1u}; } } diff --git a/src/libcore/send_map.rs b/src/libcore/send_map.rs index 58b35b82a31fa..11de9ab1a7e12 100644 --- a/src/libcore/send_map.rs +++ b/src/libcore/send_map.rs @@ -35,7 +35,7 @@ pub trait SendMap { /// Open addressing with linear probing. pub mod linear { - const initial_capacity: uint = 32u; // 2^5 + const INITIAL_CAPACITY: uint = 32u; // 2^5 struct Bucket { hash: uint, @@ -62,7 +62,7 @@ pub mod linear { } pub fn LinearMap() -> LinearMap { - linear_map_with_capacity(32) + linear_map_with_capacity(INITIAL_CAPACITY) } pub fn linear_map_with_capacity( diff --git a/src/librustc/lib/llvm.rs b/src/librustc/lib/llvm.rs index f1397006b16b9..e6fa3f2f9538a 100644 --- a/src/librustc/lib/llvm.rs +++ b/src/librustc/lib/llvm.rs @@ -959,15 +959,15 @@ extern mod llvm { /** Opens an object file. */ fn LLVMCreateObjectFile(MemBuf: MemoryBufferRef) -> ObjectFileRef; /** Closes an object file. */ - fn LLVMDisposeObjectFile(ObjectFile: ObjectFileRef); + fn LLVMDisposeObjectFile(ObjFile: ObjectFileRef); /** Enumerates the sections in an object file. */ - fn LLVMGetSections(ObjectFile: ObjectFileRef) -> SectionIteratorRef; + fn LLVMGetSections(ObjFile: ObjectFileRef) -> SectionIteratorRef; /** Destroys a section iterator. */ fn LLVMDisposeSectionIterator(SI: SectionIteratorRef); /** Returns true if the section iterator is at the end of the section list: */ - fn LLVMIsSectionIteratorAtEnd(ObjectFile: ObjectFileRef, + fn LLVMIsSectionIteratorAtEnd(ObjFile: ObjectFileRef, SI: SectionIteratorRef) -> Bool; /** Moves the section iterator to point to the next section. */ fn LLVMMoveToNextSection(SI: SectionIteratorRef); @@ -1228,9 +1228,9 @@ struct object_file_res { drop { llvm::LLVMDisposeObjectFile(self.ObjectFile); } } -fn object_file_res(ObjectFile: ObjectFileRef) -> object_file_res{ +fn object_file_res(ObjFile: ObjectFileRef) -> object_file_res { object_file_res { - ObjectFile: ObjectFile + ObjectFile: ObjFile } } diff --git a/src/librustc/middle/borrowck/check_loans.rs b/src/librustc/middle/borrowck/check_loans.rs index d63f52a4a5838..ad211b06111f1 100644 --- a/src/librustc/middle/borrowck/check_loans.rs +++ b/src/librustc/middle/borrowck/check_loans.rs @@ -570,7 +570,15 @@ fn check_loans_in_fn(fk: visit::fn_kind, decl: ast::fn_decl, body: ast::blk, visit::fk_anon(*) | visit::fk_fn_block(*) | visit::fk_method(*) | visit::fk_item_fn(*) | visit::fk_dtor(*) => { - self.fn_args = @decl.inputs.map(|i| i.id ); + let mut fn_args = ~[]; + for decl.inputs.each |input| { + do pat_util::pat_bindings(self.tcx().def_map, + input.pat) + |_a, pat_id, _b, _c| { + fn_args.push(pat_id); + } + } + self.fn_args = @move fn_args; } } diff --git a/src/librustc/middle/check_alt.rs b/src/librustc/middle/check_alt.rs index 5b35ed98a837d..d0bed6d7f4748 100644 --- a/src/librustc/middle/check_alt.rs +++ b/src/librustc/middle/check_alt.rs @@ -15,6 +15,8 @@ fn check_crate(tcx: ty::ctxt, crate: @crate) { visit::visit_crate(*crate, (), visit::mk_vt(@{ visit_expr: |a,b,c| check_expr(tcx, a, b, c), visit_local: |a,b,c| check_local(tcx, a, b, c), + visit_fn: |kind, decl, body, sp, id, e, v| + check_fn(tcx, kind, decl, body, sp, id, e, v), .. *visit::default_visitor::<()>() })); tcx.sess.abort_if_errors(); @@ -372,8 +374,8 @@ fn specialize(tcx: ty::ctxt, r: ~[@pat], ctor_id: ctor, arity: uint, ty::ty_rec(flds) => flds, _ => fail ~"bad type for pat_rec" }; - let args = vec::map(ty_flds, |ty_f| { - match vec::find(flds, |f| f.ident == ty_f.ident ) { + let args = vec::map(ty_flds, |ty_fld| { + match vec::find(flds, |f| f.ident == ty_fld.ident ) { Some(f) => f.pat, _ => wild() } @@ -386,8 +388,8 @@ fn specialize(tcx: ty::ctxt, r: ~[@pat], ctor_id: ctor, arity: uint, def_variant(_, variant_id) => { if variant(variant_id) == ctor_id { // XXX: Is this right? --pcw - let args = flds.map(|ty_f| { - match vec::find(flds, |f| f.ident == ty_f.ident) { + let args = flds.map(|ty_field| { + match vec::find(flds, |f| f.ident == ty_field.ident) { Some(f) => f.pat, _ => wild() } @@ -465,6 +467,39 @@ fn check_local(tcx: ty::ctxt, loc: @local, &&s: (), v: visit::vt<()>) { } } +fn check_fn(tcx: ty::ctxt, + kind: visit::fn_kind, + decl: fn_decl, + body: blk, + sp: span, + id: node_id, + &&s: (), + v: visit::vt<()>) { + visit::visit_fn(kind, decl, body, sp, id, s, v); + for decl.inputs.each |input| { + if is_refutable(tcx, input.pat) { + tcx.sess.span_err(input.pat.span, + ~"refutable pattern in function argument"); + } + + // Ensure that no complex patterns are used if the argument doesn't + // have + mode. + match input.pat.node { + pat_ident(*) => {} // Always OK. + _ => { + match ty::resolved_mode(tcx, input.mode) { + by_copy => {} // OK. + _ => { + tcx.sess.span_err(input.pat.span, + ~"patterns may only be used in \ + arguments with + mode"); + } + } + } + } + } +} + fn is_refutable(tcx: ty::ctxt, pat: &pat) -> bool { match tcx.def_map.find(pat.id) { Some(def_variant(enum_id, _)) => { diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index baf083b191ba0..ec7c2ffc6f1da 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -414,9 +414,13 @@ fn visit_fn(fk: visit::fn_kind, decl: fn_decl, body: blk, debug!("creating fn_maps: %x", ptr::addr_of(&(*fn_maps)) as uint); for decl.inputs.each |arg| { - debug!("adding argument %d", arg.id); let mode = ty::resolved_mode(self.tcx, arg.mode); - (*fn_maps).add_variable(Arg(arg.id, arg.ident, mode)); + do pat_util::pat_bindings(self.tcx.def_map, arg.pat) + |_bm, arg_id, _x, path| { + debug!("adding argument %d", arg_id); + let ident = ast_util::path_to_ident(path); + (*fn_maps).add_variable(Arg(arg_id, ident, mode)); + } }; // gather up the various local variables, significant expressions, @@ -447,7 +451,7 @@ fn visit_fn(fk: visit::fn_kind, decl: fn_decl, body: blk, }); check_vt.visit_block(body, lsets, check_vt); lsets.check_ret(id, sp, fk, entry_ln); - lsets.warn_about_unused_args(sp, decl, entry_ln); + lsets.warn_about_unused_args(decl, entry_ln); } fn visit_local(local: @local, &&self: @IrMaps, vt: vt<@IrMaps>) { @@ -937,8 +941,11 @@ impl Liveness { // the end. This will prevent us from moving out of // such variables but also prevent us from registering // last uses and so forth. - let var = self.variable(arg.id, blk.span); - self.acc(self.s.exit_ln, var, ACC_READ); + do pat_util::pat_bindings(self.tcx.def_map, arg.pat) + |_bm, arg_id, _sp, _path| { + let var = self.variable(arg_id, blk.span); + self.acc(self.s.exit_ln, var, ACC_READ); + } } by_move | by_copy => { // These are owned modes. If we don't use the @@ -1791,10 +1798,13 @@ impl @Liveness { if name[0] == ('_' as u8) {None} else {Some(name)} } - fn warn_about_unused_args(sp: span, decl: fn_decl, entry_ln: LiveNode) { + fn warn_about_unused_args(decl: fn_decl, entry_ln: LiveNode) { for decl.inputs.each |arg| { - let var = self.variable(arg.id, arg.ty.span); - self.warn_about_unused(sp, entry_ln, var); + do pat_util::pat_bindings(self.tcx.def_map, arg.pat) + |_bm, p_id, sp, _n| { + let var = self.variable(p_id, sp); + self.warn_about_unused(sp, entry_ln, var); + } } } diff --git a/src/librustc/middle/resolve.rs b/src/librustc/middle/resolve.rs index b915086c5511f..66b75d5f1cd74 100644 --- a/src/librustc/middle/resolve.rs +++ b/src/librustc/middle/resolve.rs @@ -28,8 +28,8 @@ use syntax::ast::{foreign_item, foreign_item_const, foreign_item_fn, ge}; use syntax::ast::{gt, ident, impure_fn, inherited, item, item_class}; use syntax::ast::{item_const, item_enum, item_fn, item_foreign_mod}; use syntax::ast::{item_impl, item_mac, item_mod, item_trait, item_ty, le}; -use syntax::ast::{local, local_crate, lt, method, module_ns, mul, ne, neg}; -use syntax::ast::{node_id, pat, pat_enum, pat_ident, path, prim_ty}; +use syntax::ast::{local, local_crate, lt, method, mode, module_ns, mul, ne}; +use syntax::ast::{neg, node_id, pat, pat_enum, pat_ident, path, prim_ty}; use syntax::ast::{pat_box, pat_lit, pat_range, pat_rec, pat_struct}; use syntax::ast::{pat_tup, pat_uniq, pat_wild, private, provided, public}; use syntax::ast::{required, rem, self_ty_, shl, shr, stmt_decl}; @@ -103,12 +103,32 @@ struct Export2 { enum PatternBindingMode { RefutableMode, - IrrefutableMode + LocalIrrefutableMode, + ArgumentIrrefutableMode(mode) } impl PatternBindingMode : cmp::Eq { pure fn eq(other: &PatternBindingMode) -> bool { - (self as uint) == ((*other) as uint) + match self { + RefutableMode => { + match *other { + RefutableMode => true, + _ => false + } + } + LocalIrrefutableMode => { + match *other { + LocalIrrefutableMode => true, + _ => false + } + } + ArgumentIrrefutableMode(mode_a) => { + match *other { + ArgumentIrrefutableMode(mode_b) => mode_a == mode_b, + _ => false + } + } + } } pure fn ne(other: &PatternBindingMode) -> bool { !self.eq(other) } } @@ -3770,15 +3790,17 @@ impl Resolver { } Some(declaration) => { for declaration.inputs.each |argument| { - let name = argument.ident; - let def_like = dl_def(def_arg(argument.id, - argument.mode)); - (*function_value_rib).bindings.insert(name, def_like); + let binding_mode = + ArgumentIrrefutableMode(argument.mode); + self.resolve_pattern(argument.pat, + binding_mode, + Immutable, + None, + visitor); self.resolve_type(argument.ty, visitor); - debug!("(resolving function) recorded argument `%s`", - self.session.str_of(name)); + debug!("(resolving function) recorded argument"); } self.resolve_type(declaration.output, visitor); @@ -4013,7 +4035,7 @@ impl Resolver { } // Resolve the pattern. - self.resolve_pattern(local.node.pat, IrrefutableMode, mutability, + self.resolve_pattern(local.node.pat, LocalIrrefutableMode, mutability, None, visitor); } @@ -4249,10 +4271,14 @@ impl Resolver { def_binding(pattern.id, binding_mode) } - IrrefutableMode => { + LocalIrrefutableMode => { // But for locals, we use `def_local`. def_local(pattern.id, is_mutable) } + ArgumentIrrefutableMode(argument_mode) => { + // And for function arguments, `def_arg`. + def_arg(pattern.id, argument_mode) + } }; // Record the definition so that later passes diff --git a/src/librustc/middle/trans/alt.rs b/src/librustc/middle/trans/alt.rs index 0908eae34dcd7..d3a69a889478b 100644 --- a/src/librustc/middle/trans/alt.rs +++ b/src/librustc/middle/trans/alt.rs @@ -1410,18 +1410,29 @@ fn trans_alt_inner(scope_cx: block, return controlflow::join_blocks(scope_cx, dvec::unwrap(move arm_cxs)); fn mk_fail(bcx: block, sp: span, msg: ~str, - done: @mut Option) -> BasicBlockRef { - match *done { Some(bb) => return bb, _ => () } + finished: @mut Option) -> BasicBlockRef { + match *finished { Some(bb) => return bb, _ => () } let fail_cx = sub_block(bcx, ~"case_fallthrough"); controlflow::trans_fail(fail_cx, Some(sp), msg); - *done = Some(fail_cx.llbb); + *finished = Some(fail_cx.llbb); return fail_cx.llbb; } } +enum IrrefutablePatternBindingMode { + // Stores the association between node ID and LLVM value in `lllocals`. + BindLocal, + // Stores the association between node ID and LLVM value in `llargs`. + BindArgument +} + // Not alt-related, but similar to the pattern-munging code above -fn bind_irrefutable_pat(bcx: block, pat: @ast::pat, val: ValueRef, - make_copy: bool) -> block { +fn bind_irrefutable_pat(bcx: block, + pat: @ast::pat, + val: ValueRef, + make_copy: bool, + binding_mode: IrrefutablePatternBindingMode) + -> block { let _icx = bcx.insn_ctxt("alt::bind_irrefutable_pat"); let ccx = bcx.fcx.ccx; let mut bcx = bcx; @@ -1439,14 +1450,31 @@ fn bind_irrefutable_pat(bcx: block, pat: @ast::pat, val: ValueRef, mode: ByRef, source: FromRvalue}; let scratch = scratch_datum(bcx, binding_ty, false); datum.copy_to_datum(bcx, INIT, scratch); - bcx.fcx.lllocals.insert(pat.id, local_mem(scratch.val)); + match binding_mode { + BindLocal => { + bcx.fcx.lllocals.insert(pat.id, + local_mem(scratch.val)); + } + BindArgument => { + bcx.fcx.llargs.insert(pat.id, + local_mem(scratch.val)); + } + } add_clean(bcx, scratch.val, binding_ty); } else { - bcx.fcx.lllocals.insert(pat.id, local_mem(val)); + match binding_mode { + BindLocal => { + bcx.fcx.lllocals.insert(pat.id, local_mem(val)); + } + BindArgument => { + bcx.fcx.llargs.insert(pat.id, local_mem(val)); + } + } } for inner.each |inner_pat| { - bcx = bind_irrefutable_pat(bcx, *inner_pat, val, true); + bcx = bind_irrefutable_pat( + bcx, *inner_pat, val, true, binding_mode); } } ast::pat_enum(_, sub_pats) => { @@ -1460,7 +1488,8 @@ fn bind_irrefutable_pat(bcx: block, pat: @ast::pat, val: ValueRef, bcx = bind_irrefutable_pat(bcx, sub_pat[i], *argval, - make_copy); + make_copy, + binding_mode); } } } @@ -1473,8 +1502,11 @@ fn bind_irrefutable_pat(bcx: block, pat: @ast::pat, val: ValueRef, // 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); + bcx = bind_irrefutable_pat(bcx, + *elem, + fldptr, + make_copy, + binding_mode); } } } @@ -1491,24 +1523,40 @@ fn bind_irrefutable_pat(bcx: block, pat: @ast::pat, val: ValueRef, for vec::each(fields) |f| { let ix = ty::field_idx_strict(tcx, f.ident, field_tys); let fldptr = GEPi(bcx, val, struct_field(ix)); - bcx = bind_irrefutable_pat(bcx, f.pat, fldptr, make_copy); + bcx = bind_irrefutable_pat(bcx, + f.pat, + fldptr, + make_copy, + binding_mode); } } } ast::pat_tup(elems) => { for vec::eachi(elems) |i, elem| { let fldptr = GEPi(bcx, val, [0u, i]); - bcx = bind_irrefutable_pat(bcx, *elem, fldptr, make_copy); + bcx = bind_irrefutable_pat(bcx, + *elem, + fldptr, + make_copy, + binding_mode); } } ast::pat_box(inner) | ast::pat_uniq(inner) => { let llbox = Load(bcx, val); let unboxed = GEPi(bcx, llbox, [0u, abi::box_field_body]); - bcx = bind_irrefutable_pat(bcx, inner, unboxed, true); + bcx = bind_irrefutable_pat(bcx, + inner, + unboxed, + true, + binding_mode); } ast::pat_region(inner) => { let loaded_val = Load(bcx, val); - bcx = bind_irrefutable_pat(bcx, inner, loaded_val, true); + bcx = bind_irrefutable_pat(bcx, + inner, + loaded_val, + true, + binding_mode); } ast::pat_wild | ast::pat_lit(_) | ast::pat_range(_, _) => () } diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index a2d74dc92dfd6..7a163afafccdd 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -991,7 +991,11 @@ fn init_local(bcx: block, local: @ast::local) -> block { bcx.to_str()); add_clean(bcx, llptr, ty); - return alt::bind_irrefutable_pat(bcx, local.node.pat, llptr, false); + return alt::bind_irrefutable_pat(bcx, + local.node.pat, + llptr, + false, + alt::BindLocal); } fn trans_stmt(cx: block, s: ast::stmt) -> block { @@ -1529,6 +1533,12 @@ fn copy_args_to_allocas(fcx: fn_ctxt, } } + bcx = alt::bind_irrefutable_pat(bcx, + args[arg_n].pat, + llarg, + false, + alt::BindArgument); + fcx.llargs.insert(arg_id, local_mem(llarg)); if fcx.ccx.sess.opts.extra_debuginfo { @@ -1658,7 +1668,9 @@ fn trans_enum_variant(ccx: @crate_ctxt, let fn_args = vec::map(args, |varg| {mode: ast::expl(ast::by_copy), ty: varg.ty, - ident: special_idents::arg, + pat: ast_util::ident_to_pat(ccx.tcx.sess.next_node_id(), + ast_util::dummy_sp(), + special_idents::arg), id: varg.id}); let fcx = new_fn_ctxt_w_id(ccx, ~[], llfndecl, variant.node.id, None, param_substs, None); @@ -1714,7 +1726,9 @@ fn trans_tuple_struct(ccx: @crate_ctxt, { mode: ast::expl(ast::by_copy), ty: field.node.ty, - ident: special_idents::arg, + pat: ast_util::ident_to_pat(ccx.tcx.sess.next_node_id(), + ast_util::dummy_sp(), + special_idents::arg), id: field.node.id } }; diff --git a/src/librustc/middle/trans/common.rs b/src/librustc/middle/trans/common.rs index 36d6bb9258b1d..8badf672e8174 100644 --- a/src/librustc/middle/trans/common.rs +++ b/src/librustc/middle/trans/common.rs @@ -320,9 +320,9 @@ impl cleantype : cmp::Eq { type cleanup_path = {target: Option, dest: BasicBlockRef}; -fn scope_clean_changed(info: scope_info) { - if info.cleanup_paths.len() > 0u { info.cleanup_paths = ~[]; } - info.landing_pad = None; +fn scope_clean_changed(scope_info: scope_info) { + if scope_info.cleanup_paths.len() > 0u { scope_info.cleanup_paths = ~[]; } + scope_info.landing_pad = None; } fn cleanup_type(cx: ty::ctxt, ty: ty::t) -> cleantype { @@ -361,11 +361,11 @@ fn add_clean(bcx: block, val: ValueRef, t: ty::t) { ty_to_str(bcx.ccx().tcx, t)); let {root, rooted} = root_for_cleanup(bcx, val, t); let cleanup_type = cleanup_type(bcx.tcx(), t); - do in_scope_cx(bcx) |info| { - info.cleanups.push( + do in_scope_cx(bcx) |scope_info| { + scope_info.cleanups.push( clean(|a| glue::drop_ty_root(a, root, rooted, t), cleanup_type)); - scope_clean_changed(info); + scope_clean_changed(scope_info); } } @@ -375,11 +375,11 @@ fn add_clean_temp_immediate(cx: block, val: ValueRef, ty: ty::t) { cx.to_str(), val_str(cx.ccx().tn, val), ty_to_str(cx.ccx().tcx, ty)); let cleanup_type = cleanup_type(cx.tcx(), ty); - do in_scope_cx(cx) |info| { - info.cleanups.push( + do in_scope_cx(cx) |scope_info| { + scope_info.cleanups.push( clean_temp(val, |a| glue::drop_ty_immediate(a, val, ty), cleanup_type)); - scope_clean_changed(info); + scope_clean_changed(scope_info); } } fn add_clean_temp_mem(bcx: block, val: ValueRef, t: ty::t) { @@ -389,11 +389,11 @@ fn add_clean_temp_mem(bcx: block, val: ValueRef, t: ty::t) { ty_to_str(bcx.ccx().tcx, t)); let {root, rooted} = root_for_cleanup(bcx, val, t); let cleanup_type = cleanup_type(bcx.tcx(), t); - do in_scope_cx(bcx) |info| { - info.cleanups.push( + do in_scope_cx(bcx) |scope_info| { + scope_info.cleanups.push( clean_temp(val, |a| glue::drop_ty_root(a, root, rooted, t), cleanup_type)); - scope_clean_changed(info); + scope_clean_changed(scope_info); } } fn add_clean_free(cx: block, ptr: ValueRef, heap: heap) { @@ -401,10 +401,10 @@ fn add_clean_free(cx: block, ptr: ValueRef, heap: heap) { heap_shared => |a| glue::trans_free(a, ptr), heap_exchange => |a| glue::trans_unique_free(a, ptr) }; - do in_scope_cx(cx) |info| { - info.cleanups.push(clean_temp(ptr, free_fn, + do in_scope_cx(cx) |scope_info| { + scope_info.cleanups.push(clean_temp(ptr, free_fn, normal_exit_and_unwind)); - scope_clean_changed(info); + scope_clean_changed(scope_info); } } @@ -413,20 +413,20 @@ fn add_clean_free(cx: block, ptr: ValueRef, heap: heap) { // this will be more involved. For now, we simply zero out the local, and the // drop glue checks whether it is zero. fn revoke_clean(cx: block, val: ValueRef) { - do in_scope_cx(cx) |info| { + do in_scope_cx(cx) |scope_info| { let cleanup_pos = vec::position( - info.cleanups, + scope_info.cleanups, |cu| match *cu { clean_temp(v, _, _) if v == val => true, _ => false }); for cleanup_pos.each |i| { - info.cleanups = - vec::append(vec::slice(info.cleanups, 0u, *i), - vec::view(info.cleanups, + scope_info.cleanups = + vec::append(vec::slice(scope_info.cleanups, 0u, *i), + vec::view(scope_info.cleanups, *i + 1u, - info.cleanups.len())); - scope_clean_changed(info); + scope_info.cleanups.len())); + scope_clean_changed(scope_info); } } } diff --git a/src/librustc/middle/trans/debuginfo.rs b/src/librustc/middle/trans/debuginfo.rs index 2db0dd59cf918..fd18aaaf58ec6 100644 --- a/src/librustc/middle/trans/debuginfo.rs +++ b/src/librustc/middle/trans/debuginfo.rs @@ -664,13 +664,13 @@ fn create_local_var(bcx: block, local: @ast::local) } fn create_arg(bcx: block, arg: ast::arg, sp: span) - -> @metadata unsafe { + -> Option<@metadata> unsafe { let fcx = bcx.fcx, cx = fcx.ccx; let cache = get_cache(cx); let tg = ArgVariableTag; match cached_metadata::<@metadata>( cache, ArgVariableTag, |md| md.data.id == arg.id) { - option::Some(md) => return md, + option::Some(md) => return Some(md), option::None => () } @@ -680,18 +680,32 @@ fn create_arg(bcx: block, arg: ast::arg, sp: span) let tymd = create_ty(cx, ty, arg.ty); let filemd = create_file(cx, loc.file.name); let context = create_function(bcx.fcx); - let mdnode = create_var(tg, context.node, cx.sess.str_of(arg.ident), - filemd.node, loc.line as int, tymd.node); - let mdval = @{node: mdnode, data: {id: arg.id}}; - update_cache(cache, tg, argument_metadata(mdval)); - let llptr = match fcx.llargs.get(arg.id) { - local_mem(v) | local_imm(v) => v, - }; - let declargs = ~[llmdnode(~[llptr]), mdnode]; - trans::build::Call(bcx, cx.intrinsics.get(~"llvm.dbg.declare"), - declargs); - return mdval; + match arg.pat.node { + ast::pat_ident(_, path, _) => { + // XXX: This is wrong; it should work for multiple bindings. + let mdnode = create_var(tg, + context.node, + cx.sess.str_of(path.idents.last()), + filemd.node, + loc.line as int, + tymd.node); + + let mdval = @{node: mdnode, data: {id: arg.id}}; + update_cache(cache, tg, argument_metadata(mdval)); + + let llptr = match fcx.llargs.get(arg.id) { + local_mem(v) | local_imm(v) => v, + }; + let declargs = ~[llmdnode(~[llptr]), mdnode]; + trans::build::Call(bcx, cx.intrinsics.get(~"llvm.dbg.declare"), + declargs); + return Some(mdval); + } + _ => { + return None; + } + } } fn update_source_pos(cx: block, s: span) { diff --git a/src/librustc/middle/trans/deriving.rs b/src/librustc/middle/trans/deriving.rs index bc398bf753df3..e2749db74aa61 100644 --- a/src/librustc/middle/trans/deriving.rs +++ b/src/librustc/middle/trans/deriving.rs @@ -261,9 +261,9 @@ fn call_substructure_method(bcx: block, vtable_result); let llfn = fn_data.llfn; - let cb: &fn(block) -> Callee = |block| { + let cb: &fn(block) -> Callee = |bloc| { Callee { - bcx: block, + bcx: bloc, data: Method(MethodData { llfn: llfn, llself: llselfval, diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 5e1bccb6c9d5a..52f05eb44de01 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -2532,18 +2532,19 @@ fn type_param(ty: t) -> Option { // Returns the type and mutability of *t. // -// The parameter `expl` indicates if this is an *explicit* dereference. Some -// types---notably unsafe ptrs---can only be dereferenced explicitly. -fn deref(cx: ctxt, t: t, expl: bool) -> Option { - deref_sty(cx, &get(t).sty, expl) +// The parameter `explicit` indicates if this is an *explicit* dereference. +// Some types---notably unsafe ptrs---can only be dereferenced explicitly. +fn deref(cx: ctxt, t: t, explicit: bool) -> Option { + deref_sty(cx, &get(t).sty, explicit) } -fn deref_sty(cx: ctxt, sty: &sty, expl: bool) -> Option { + +fn deref_sty(cx: ctxt, sty: &sty, explicit: bool) -> Option { match *sty { ty_rptr(_, mt) | ty_box(mt) | ty_uniq(mt) => { Some(mt) } - ty_ptr(mt) if expl => { + ty_ptr(mt) if explicit => { Some(mt) } @@ -3443,7 +3444,7 @@ fn provided_trait_methods(cx: ctxt, id: ast::def_id) -> ~[ast::ident] { id)) } } else { - csearch::get_provided_trait_methods(cx, id).map(|info| info.ty.ident) + csearch::get_provided_trait_methods(cx, id).map(|ifo| ifo.ty.ident) } } diff --git a/src/librustc/middle/typeck/check.rs b/src/librustc/middle/typeck/check.rs index 3de9955455411..d9ab7306ac3aa 100644 --- a/src/librustc/middle/typeck/check.rs +++ b/src/librustc/middle/typeck/check.rs @@ -267,7 +267,7 @@ fn check_fn(ccx: @crate_ctxt, } else { None }; @fn_ctxt { - self_impl_def_id: self_info.map(|info| info.def_id), + self_impl_def_id: self_info.map(|self_info| self_info.def_id), ret_ty: ret_ty, indirect_ret_ty: indirect_ret_ty, purity: purity, @@ -280,16 +280,16 @@ fn check_fn(ccx: @crate_ctxt, // Update the self_info to contain an accurate self type (taking // into account explicit self). - let self_info = do self_info.chain_ref |info| { + let self_info = do self_info.chain_ref |self_info| { // If the self type is sty_static, we don't have a self ty. - if info.explicit_self.node == ast::sty_static { + if self_info.explicit_self.node == ast::sty_static { None } else { let self_region = fcx.in_scope_regions.find(ty::br_self); let ty = method::transform_self_type_for_method( fcx.tcx(), self_region, - info.self_ty, info.explicit_self.node); - Some({self_ty: ty,.. *info}) + self_info.self_ty, self_info.explicit_self.node); + Some({self_ty: ty,.. *self_info}) } }; @@ -306,8 +306,8 @@ fn check_fn(ccx: @crate_ctxt, None => () } - for self_info.each |info| { - fcx.write_ty(info.self_id, info.self_ty); + for self_info.each |self_info| { + fcx.write_ty(self_info.self_id, self_info.self_ty); } for vec::each2(decl.inputs, arg_tys) |input, arg| { fcx.write_ty(input.id, *arg); @@ -344,19 +344,31 @@ fn check_fn(ccx: @crate_ctxt, }; // Add the self parameter - for self_info.each |info| { - assign(info.explicit_self.span, - info.self_id, Some(info.self_ty)); + for self_info.each |self_info| { + assign(self_info.explicit_self.span, + self_info.self_id, + Some(self_info.self_ty)); debug!("self is assigned to %s", - fcx.inh.locals.get(info.self_id).to_str()); + fcx.inh.locals.get(self_info.self_id).to_str()); } // Add formal parameters. for vec::each2(arg_tys, decl.inputs) |arg_ty, input| { - assign(input.ty.span, input.id, Some(*arg_ty)); - debug!("Argument %s is assigned to %s", - tcx.sess.str_of(input.ident), - fcx.inh.locals.get(input.id).to_str()); + // Create type variables for each argument. + do pat_util::pat_bindings(tcx.def_map, input.pat) + |_bm, pat_id, _sp, _path| { + assign(input.ty.span, pat_id, None); + } + + // Check the pattern. + let region = fcx.block_region(); + let pcx = { + fcx: fcx, + map: pat_id_map(tcx.def_map, input.pat), + alt_region: region, + block_region: region, + }; + alt::check_pat(pcx, input.pat, *arg_ty); } // Add explicitly-declared locals. diff --git a/src/librustc/middle/typeck/check/alt.rs b/src/librustc/middle/typeck/check/alt.rs index 41be34a713cfe..d7bee357b66bd 100644 --- a/src/librustc/middle/typeck/check/alt.rs +++ b/src/librustc/middle/typeck/check/alt.rs @@ -428,6 +428,9 @@ fn check_pat(pcx: pat_ctxt, pat: @ast::pat, expected: ty::t) { demand::eqtype(fcx, pat.span, ct, typ); } fcx.write_ty(pat.id, typ); + + debug!("(checking alt) writing type for pat id %d", pat.id); + match sub { Some(p) => check_pat(pcx, p, expected), _ => () diff --git a/src/librustc/middle/typeck/check/writeback.rs b/src/librustc/middle/typeck/check/writeback.rs index 33a26c8daf497..8000d2f733163 100644 --- a/src/librustc/middle/typeck/check/writeback.rs +++ b/src/librustc/middle/typeck/check/writeback.rs @@ -234,7 +234,10 @@ fn resolve_type_vars_in_fn(fcx: @fn_ctxt, self_info.self_id); } for decl.inputs.each |arg| { - resolve_type_vars_for_node(wbcx, arg.ty.span, arg.id); + do pat_util::pat_bindings(fcx.tcx().def_map, arg.pat) + |_bm, pat_id, span, _path| { + resolve_type_vars_for_node(wbcx, span, pat_id); + } } return wbcx.success; } diff --git a/src/librustc/middle/typeck/coherence.rs b/src/librustc/middle/typeck/coherence.rs index c1bffef3f31e3..5ad3b27e619ed 100644 --- a/src/librustc/middle/typeck/coherence.rs +++ b/src/librustc/middle/typeck/coherence.rs @@ -856,8 +856,8 @@ impl CoherenceChecker { debug!("(adding default methods for trait) processing trait"); - for csearch::get_provided_trait_methods(tcx, - trait_def_id).each |info| { + for csearch::get_provided_trait_methods(tcx, trait_def_id).each + |trait_method_info| { debug!("(adding default methods for trait) found default method"); // Create a new def ID for this provided method. @@ -868,11 +868,11 @@ impl CoherenceChecker { @ProvidedMethodInfo { method_info: @{ did: new_did, - n_tps: info.ty.tps.len(), - ident: info.ty.ident, - self_type: info.ty.self_ty + n_tps: trait_method_info.ty.tps.len(), + ident: trait_method_info.ty.ident, + self_type: trait_method_info.ty.self_ty }, - trait_method_def_id: info.def_id + trait_method_def_id: trait_method_info.def_id }; let method_infos = @DVec(); diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 8fcb9300b52e9..7452e41fac337 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -662,8 +662,8 @@ type expr = {id: node_id, callee_id: node_id, node: expr_, span: span}; #[auto_serialize] #[auto_deserialize] -enum log_level { error, debug, other } -// 0 = error, 1 = debug, 2 = other +enum log_level { error, debug, log_other } +// 0 = error, 1 = debug, 2 = log_other #[auto_serialize] #[auto_deserialize] @@ -1137,7 +1137,7 @@ impl Ty : to_bytes::IterBytes { #[auto_serialize] #[auto_deserialize] -type arg = {mode: mode, ty: @Ty, ident: ident, id: node_id}; +type arg = {mode: mode, ty: @Ty, pat: @pat, id: node_id}; #[auto_serialize] #[auto_deserialize] diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs index ea49cce50477e..d3b879da7dd95 100644 --- a/src/libsyntax/ast_util.rs +++ b/src/libsyntax/ast_util.rs @@ -274,6 +274,12 @@ fn ident_to_path(s: span, +i: ident) -> @path { rp: None, types: ~[]} } +fn ident_to_pat(id: node_id, s: span, +i: ident) -> @pat { + @{id: id, + node: pat_ident(bind_by_value, ident_to_path(s, i), None), + span: s} +} + pure fn is_unguarded(a: &arm) -> bool { match a.guard { None => true, diff --git a/src/libsyntax/ext/auto_serialize.rs b/src/libsyntax/ext/auto_serialize.rs index 707787e78b9a1..39e94291d8bb7 100644 --- a/src/libsyntax/ext/auto_serialize.rs +++ b/src/libsyntax/ext/auto_serialize.rs @@ -515,7 +515,12 @@ fn mk_ser_method( let ser_inputs = ~[{ mode: ast::infer(cx.next_id()), ty: ty_s, - ident: cx.ident_of(~"__s"), + pat: @{id: cx.next_id(), + node: ast::pat_ident( + ast::bind_by_value, + ast_util::ident_to_path(span, cx.ident_of(~"__s")), + None), + span: span}, id: cx.next_id(), }]; @@ -570,7 +575,12 @@ fn mk_deser_method( let deser_inputs = ~[{ mode: ast::infer(cx.next_id()), ty: ty_d, - ident: cx.ident_of(~"__d"), + pat: @{id: cx.next_id(), + node: ast::pat_ident( + ast::bind_by_value, + ast_util::ident_to_path(span, cx.ident_of(~"__d")), + None), + span: span}, id: cx.next_id(), }]; @@ -1087,7 +1097,13 @@ fn mk_enum_deser_body( node: ast::ty_infer, span: span }, - ident: cx.ident_of(~"i"), + pat: @{id: cx.next_id(), + node: ast::pat_ident( + ast::bind_by_value, + ast_util::ident_to_path(span, + cx.ident_of(~"i")), + None), + span: span}, id: cx.next_id(), }], output: @{ diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 5b4cc23ce09fd..ddf58ce0fef1c 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -234,24 +234,27 @@ fn mk_ctxt(parse_sess: parse::parse_sess, move ((move imp) as ext_ctxt) } -fn expr_to_str(cx: ext_ctxt, expr: @ast::expr, error: ~str) -> ~str { +fn expr_to_str(cx: ext_ctxt, expr: @ast::expr, err_msg: ~str) -> ~str { match expr.node { ast::expr_lit(l) => match l.node { ast::lit_str(s) => return *s, - _ => cx.span_fatal(l.span, error) + _ => cx.span_fatal(l.span, err_msg) }, - _ => cx.span_fatal(expr.span, error) + _ => cx.span_fatal(expr.span, err_msg) } } -fn expr_to_ident(cx: ext_ctxt, expr: @ast::expr, error: ~str) -> ast::ident { +fn expr_to_ident(cx: ext_ctxt, + expr: @ast::expr, + err_msg: ~str) -> ast::ident { match expr.node { ast::expr_path(p) => { if vec::len(p.types) > 0u || vec::len(p.idents) != 1u { - cx.span_fatal(expr.span, error); - } else { return p.idents[0]; } + cx.span_fatal(expr.span, err_msg); + } + return p.idents[0]; } - _ => cx.span_fatal(expr.span, error) + _ => cx.span_fatal(expr.span, err_msg) } } diff --git a/src/libsyntax/ext/pipes/ast_builder.rs b/src/libsyntax/ext/pipes/ast_builder.rs index 632b3b93af99a..f03adb90f0bcf 100644 --- a/src/libsyntax/ext/pipes/ast_builder.rs +++ b/src/libsyntax/ext/pipes/ast_builder.rs @@ -4,7 +4,7 @@ // something smarter. use ast::{ident, node_id}; -use ast_util::respan; +use ast_util::{ident_to_path, respan}; use codemap::span; use ext::base::mk_ctxt; @@ -178,7 +178,12 @@ impl ext_ctxt: ext_ctxt_ast_builder { fn arg(name: ident, ty: @ast::Ty) -> ast::arg { {mode: ast::infer(self.next_id()), ty: ty, - ident: name, + pat: @{id: self.next_id(), + node: ast::pat_ident( + ast::bind_by_value, + ast_util::ident_to_path(self.empty_span(), name), + None), + span: self.empty_span()}, id: self.next_id()} } diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 3879e70cb2888..8609124126c09 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -105,9 +105,9 @@ fn fold_attribute_(at: attribute, fld: ast_fold) -> //used in noop_fold_foreign_item and noop_fold_fn_decl fn fold_arg_(a: arg, fld: ast_fold) -> arg { return {mode: a.mode, - ty: fld.fold_ty(a.ty), - ident: fld.fold_ident(a.ident), - id: fld.new_id(a.id)}; + ty: fld.fold_ty(a.ty), + pat: fld.fold_pat(a.pat), + id: fld.new_id(a.id)}; } //used in noop_fold_expr, and possibly elsewhere in the future fn fold_mac_(m: mac, fld: ast_fold) -> mac { diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index db3f6abbf7b79..2b42dcc0ed06a 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -696,19 +696,21 @@ impl Parser { // identifier names. fn parse_arg_general(require_name: bool) -> arg { let mut m; - let i = if require_name || self.is_named_argument() { + let pat = if require_name || self.is_named_argument() { m = self.parse_arg_mode(); - let name = self.parse_value_ident(); + let pat = self.parse_pat(false); self.expect(token::COLON); - name + pat } else { m = infer(self.get_id()); - special_idents::invalid + ast_util::ident_to_pat(self.get_id(), + copy self.last_span, + special_idents::invalid) }; let t = self.parse_ty(false); - {mode: m, ty: t, ident: i, id: self.get_id()} + {mode: m, ty: t, pat: pat, id: self.get_id()} } fn parse_arg() -> arg_or_capture_item { @@ -722,7 +724,7 @@ impl Parser { fn parse_fn_block_arg() -> arg_or_capture_item { do self.parse_capture_item_or |p| { let m = p.parse_arg_mode(); - let i = p.parse_value_ident(); + let pat = p.parse_pat(false); let t = if p.eat(token::COLON) { p.parse_ty(false) } else { @@ -730,7 +732,7 @@ impl Parser { node: ty_infer, span: mk_sp(p.span.lo, p.span.hi)} }; - either::Left({mode: m, ty: t, ident: i, id: p.get_id()}) + either::Left({mode: m, ty: t, pat: pat, id: p.get_id()}) } } @@ -1042,7 +1044,7 @@ impl Parser { let lvl = self.parse_expr(); self.expect(token::COMMA); let e = self.parse_expr(); - ex = expr_log(ast::other, lvl, e); + ex = expr_log(ast::log_other, lvl, e); hi = self.span.hi; self.expect(token::RPAREN); } else if self.eat_keyword(~"assert") { @@ -2708,6 +2710,11 @@ impl Parser { } } + fn ident_to_path(i: ident) -> @path { + @{span: self.last_span, global: false, idents: ~[i], + rp: None, types: ~[]} + } + fn parse_trait_ref() -> @trait_ref { @{path: self.parse_path_with_tps(false), ref_id: self.get_id(), impl_id: self.get_id()} diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index ed64d02cea36e..0418f6776de6b 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -1386,7 +1386,7 @@ fn print_expr(s: ps, &&expr: @ast::expr) { match lvl { ast::debug => { word_nbsp(s, ~"log"); print_expr(s, expr); } ast::error => { word_nbsp(s, ~"log_err"); print_expr(s, expr); } - ast::other => { + ast::log_other => { word_nbsp(s, ~"log"); popen(s); print_expr(s, lexp); @@ -1820,12 +1820,19 @@ fn print_arg(s: ps, input: ast::arg) { ibox(s, indent_unit); print_arg_mode(s, input.mode); match input.ty.node { - ast::ty_infer => print_ident(s, input.ident), + ast::ty_infer => print_pat(s, input.pat), _ => { - if input.ident != parse::token::special_idents::invalid { - print_ident(s, input.ident); - word(s.s, ~":"); - space(s.s); + match input.pat.node { + ast::pat_ident(_, path, _) if + path.idents.len() == 1 && + path.idents[0] == parse::token::special_idents::invalid => { + // Do nothing. + } + _ => { + print_pat(s, input.pat); + word(s.s, ~":"); + space(s.s); + } } print_type(s, input.ty); } diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 97cc52bd35a16..42b869b6c3417 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -277,7 +277,10 @@ fn visit_ty_params(tps: ~[ty_param], e: E, v: vt) { } fn visit_fn_decl(fd: fn_decl, e: E, v: vt) { - for fd.inputs.each |a| { v.visit_ty(a.ty, e, v); } + for fd.inputs.each |a| { + v.visit_pat(a.pat, e, v); + v.visit_ty(a.ty, e, v); + } v.visit_ty(fd.output, e, v); } diff --git a/src/test/compile-fail/arg-pattern-with-wrong-mode.rs b/src/test/compile-fail/arg-pattern-with-wrong-mode.rs new file mode 100644 index 0000000000000..67b9f6ef89ecb --- /dev/null +++ b/src/test/compile-fail/arg-pattern-with-wrong-mode.rs @@ -0,0 +1,4 @@ +fn f(&&(x, y): (int, int)) {} //~ ERROR patterns may only be used in arguments with + mode + +fn main(){} + diff --git a/src/test/compile-fail/macro-2.rs b/src/test/compile-fail/macro-2.rs index bb54685f752ff..41be88168f21b 100644 --- a/src/test/compile-fail/macro-2.rs +++ b/src/test/compile-fail/macro-2.rs @@ -1,4 +1,4 @@ -//error-pattern:is an expr, expected an identifier +//error-pattern:is an expr, expected a path fn main() { #macro[[#mylambda[x, body], { diff --git a/src/test/compile-fail/refutable-pattern-in-fn-arg.rs b/src/test/compile-fail/refutable-pattern-in-fn-arg.rs new file mode 100644 index 0000000000000..5299d6a87c376 --- /dev/null +++ b/src/test/compile-fail/refutable-pattern-in-fn-arg.rs @@ -0,0 +1,5 @@ +fn main() { + let f = |3: int| io::println("hello"); //~ ERROR refutable pattern + f(4); +} + diff --git a/src/test/compile-fail/regions-glb-free-free.rs b/src/test/compile-fail/regions-glb-free-free.rs index e4913f7056e85..223665381da1e 100644 --- a/src/test/compile-fail/regions-glb-free-free.rs +++ b/src/test/compile-fail/regions-glb-free-free.rs @@ -19,7 +19,7 @@ mod argparse { fn set_desc(self, s: &str) -> Flag { Flag { //~ ERROR cannot infer an appropriate lifetime name: self.name, - desc: s, //~ ERROR cannot infer an appropriate lifetime + desc: s, max_count: self.max_count, value: self.value } diff --git a/src/test/run-pass/pattern-in-closure.rs b/src/test/run-pass/pattern-in-closure.rs new file mode 100644 index 0000000000000..fe3739e69346f --- /dev/null +++ b/src/test/run-pass/pattern-in-closure.rs @@ -0,0 +1,15 @@ +struct Foo { + x: int, + y: int +} + +fn main() { + let f = |(x, _): (int, int)| assert x == 2; + let g = |Foo { x: x, y: y }: Foo| { + assert x == 1; + assert y == 2; + }; + f((2, 3)); + g(Foo { x: 1, y: 2 }); +} +