Skip to content

Commit 0fc9523

Browse files
committed
rustc: Support irrefutable patterns in function arguments. r=nmatsakis
1 parent b223c9c commit 0fc9523

31 files changed

+392
-159
lines changed

src/libcore/extfmt.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ pub mod ct {
8585
pub enum Piece { PieceString(~str), PieceConv(Conv), }
8686
pub type ErrorFn = fn@(&str) -> ! ;
8787

88-
pub fn parse_fmt_string(s: &str, error: ErrorFn) -> ~[Piece] {
88+
pub fn parse_fmt_string(s: &str, err: ErrorFn) -> ~[Piece] {
8989
let mut pieces: ~[Piece] = ~[];
9090
let lim = str::len(s);
9191
let mut buf = ~"";
@@ -103,15 +103,15 @@ pub mod ct {
103103
if curr == ~"%" {
104104
i += 1;
105105
if i >= lim {
106-
error(~"unterminated conversion at end of string");
106+
err(~"unterminated conversion at end of string");
107107
}
108108
let curr2 = str::slice(s, i, i+1);
109109
if curr2 == ~"%" {
110110
buf += curr2;
111111
i += 1;
112112
} else {
113113
buf = flush_buf(move buf, &mut pieces);
114-
let rs = parse_conversion(s, i, lim, error);
114+
let rs = parse_conversion(s, i, lim, err);
115115
pieces.push(copy rs.piece);
116116
i = rs.next;
117117
}
@@ -143,13 +143,13 @@ pub mod ct {
143143
}
144144
}
145145
pub fn parse_conversion(s: &str, i: uint, lim: uint,
146-
error: ErrorFn) ->
146+
err: ErrorFn) ->
147147
{piece: Piece, next: uint} {
148148
let parm = parse_parameter(s, i, lim);
149149
let flags = parse_flags(s, parm.next, lim);
150150
let width = parse_count(s, flags.next, lim);
151151
let prec = parse_precision(s, width.next, lim);
152-
let ty = parse_type(s, prec.next, lim, error);
152+
let ty = parse_type(s, prec.next, lim, err);
153153
return {piece:
154154
PieceConv({param: parm.param,
155155
flags: copy flags.flags,
@@ -239,9 +239,9 @@ pub mod ct {
239239
}
240240
} else { {count: CountImplied, next: i} };
241241
}
242-
pub fn parse_type(s: &str, i: uint, lim: uint, error: ErrorFn) ->
242+
pub fn parse_type(s: &str, i: uint, lim: uint, err: ErrorFn) ->
243243
{ty: Ty, next: uint} {
244-
if i >= lim { error(~"missing type in conversion"); }
244+
if i >= lim { err(~"missing type in conversion"); }
245245
let tstr = str::slice(s, i, i+1u);
246246
// FIXME (#2249): Do we really want two signed types here?
247247
// How important is it to be printf compatible?
@@ -268,7 +268,7 @@ pub mod ct {
268268
TyFloat
269269
} else if tstr == ~"?" {
270270
TyPoly
271-
} else { error(~"unknown type in conversion: " + tstr) };
271+
} else { err(~"unknown type in conversion: " + tstr) };
272272
return {ty: t, next: i + 1u};
273273
}
274274
}

src/libcore/send_map.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ pub trait SendMap<K:Eq Hash, V: Copy> {
3535

3636
/// Open addressing with linear probing.
3737
pub mod linear {
38-
const initial_capacity: uint = 32u; // 2^5
38+
const INITIAL_CAPACITY: uint = 32u; // 2^5
3939

4040
struct Bucket<K:Eq Hash,V> {
4141
hash: uint,
@@ -62,7 +62,7 @@ pub mod linear {
6262
}
6363

6464
pub fn LinearMap<K:Eq Hash,V>() -> LinearMap<K,V> {
65-
linear_map_with_capacity(32)
65+
linear_map_with_capacity(INITIAL_CAPACITY)
6666
}
6767

6868
pub fn linear_map_with_capacity<K:Eq Hash,V>(

src/librustc/lib/llvm.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -959,15 +959,15 @@ extern mod llvm {
959959
/** Opens an object file. */
960960
fn LLVMCreateObjectFile(MemBuf: MemoryBufferRef) -> ObjectFileRef;
961961
/** Closes an object file. */
962-
fn LLVMDisposeObjectFile(ObjectFile: ObjectFileRef);
962+
fn LLVMDisposeObjectFile(ObjFile: ObjectFileRef);
963963

964964
/** Enumerates the sections in an object file. */
965-
fn LLVMGetSections(ObjectFile: ObjectFileRef) -> SectionIteratorRef;
965+
fn LLVMGetSections(ObjFile: ObjectFileRef) -> SectionIteratorRef;
966966
/** Destroys a section iterator. */
967967
fn LLVMDisposeSectionIterator(SI: SectionIteratorRef);
968968
/** Returns true if the section iterator is at the end of the section
969969
list: */
970-
fn LLVMIsSectionIteratorAtEnd(ObjectFile: ObjectFileRef,
970+
fn LLVMIsSectionIteratorAtEnd(ObjFile: ObjectFileRef,
971971
SI: SectionIteratorRef) -> Bool;
972972
/** Moves the section iterator to point to the next section. */
973973
fn LLVMMoveToNextSection(SI: SectionIteratorRef);
@@ -1228,9 +1228,9 @@ struct object_file_res {
12281228
drop { llvm::LLVMDisposeObjectFile(self.ObjectFile); }
12291229
}
12301230

1231-
fn object_file_res(ObjectFile: ObjectFileRef) -> object_file_res{
1231+
fn object_file_res(ObjFile: ObjectFileRef) -> object_file_res {
12321232
object_file_res {
1233-
ObjectFile: ObjectFile
1233+
ObjectFile: ObjFile
12341234
}
12351235
}
12361236

src/librustc/middle/borrowck/check_loans.rs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -570,7 +570,20 @@ fn check_loans_in_fn(fk: visit::fn_kind, decl: ast::fn_decl, body: ast::blk,
570570
visit::fk_anon(*) | visit::fk_fn_block(*) |
571571
visit::fk_method(*) | visit::fk_item_fn(*) |
572572
visit::fk_dtor(*) => {
573-
self.fn_args = @decl.inputs.map(|i| i.id );
573+
let mut fn_args = ~[];
574+
for decl.inputs.each |input| {
575+
// For the purposes of purity, only consider function-
576+
// typed bindings in trivial patterns to be function
577+
// arguments. For example, do not allow `f` and `g` in
578+
// (f, g): (&fn(), &fn()) to be called.
579+
match input.pat.node {
580+
ast::pat_ident(_, _, None) => {
581+
fn_args.push(input.pat.id);
582+
}
583+
_ => {} // Ignore this argument.
584+
}
585+
}
586+
self.fn_args = @move fn_args;
574587
}
575588
}
576589

src/librustc/middle/check_alt.rs

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ fn check_crate(tcx: ty::ctxt, crate: @crate) {
1515
visit::visit_crate(*crate, (), visit::mk_vt(@{
1616
visit_expr: |a,b,c| check_expr(tcx, a, b, c),
1717
visit_local: |a,b,c| check_local(tcx, a, b, c),
18+
visit_fn: |kind, decl, body, sp, id, e, v|
19+
check_fn(tcx, kind, decl, body, sp, id, e, v),
1820
.. *visit::default_visitor::<()>()
1921
}));
2022
tcx.sess.abort_if_errors();
@@ -372,8 +374,8 @@ fn specialize(tcx: ty::ctxt, r: ~[@pat], ctor_id: ctor, arity: uint,
372374
ty::ty_rec(flds) => flds,
373375
_ => fail ~"bad type for pat_rec"
374376
};
375-
let args = vec::map(ty_flds, |ty_f| {
376-
match vec::find(flds, |f| f.ident == ty_f.ident ) {
377+
let args = vec::map(ty_flds, |ty_fld| {
378+
match vec::find(flds, |f| f.ident == ty_fld.ident ) {
377379
Some(f) => f.pat,
378380
_ => wild()
379381
}
@@ -386,8 +388,8 @@ fn specialize(tcx: ty::ctxt, r: ~[@pat], ctor_id: ctor, arity: uint,
386388
def_variant(_, variant_id) => {
387389
if variant(variant_id) == ctor_id {
388390
// XXX: Is this right? --pcw
389-
let args = flds.map(|ty_f| {
390-
match vec::find(flds, |f| f.ident == ty_f.ident) {
391+
let args = flds.map(|ty_field| {
392+
match vec::find(flds, |f| f.ident == ty_field.ident) {
391393
Some(f) => f.pat,
392394
_ => wild()
393395
}
@@ -465,6 +467,23 @@ fn check_local(tcx: ty::ctxt, loc: @local, &&s: (), v: visit::vt<()>) {
465467
}
466468
}
467469

470+
fn check_fn(tcx: ty::ctxt,
471+
kind: visit::fn_kind,
472+
decl: fn_decl,
473+
body: blk,
474+
sp: span,
475+
id: node_id,
476+
&&s: (),
477+
v: visit::vt<()>) {
478+
visit::visit_fn(kind, decl, body, sp, id, s, v);
479+
for decl.inputs.each |input| {
480+
if is_refutable(tcx, input.pat) {
481+
tcx.sess.span_err(input.pat.span,
482+
~"refutable pattern in function argument");
483+
}
484+
}
485+
}
486+
468487
fn is_refutable(tcx: ty::ctxt, pat: &pat) -> bool {
469488
match tcx.def_map.find(pat.id) {
470489
Some(def_variant(enum_id, _)) => {

src/librustc/middle/liveness.rs

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -414,9 +414,13 @@ fn visit_fn(fk: visit::fn_kind, decl: fn_decl, body: blk,
414414
debug!("creating fn_maps: %x", ptr::addr_of(&(*fn_maps)) as uint);
415415

416416
for decl.inputs.each |arg| {
417-
debug!("adding argument %d", arg.id);
418417
let mode = ty::resolved_mode(self.tcx, arg.mode);
419-
(*fn_maps).add_variable(Arg(arg.id, arg.ident, mode));
418+
do pat_util::pat_bindings(self.tcx.def_map, arg.pat)
419+
|_bm, arg_id, _x, path| {
420+
debug!("adding argument %d", arg_id);
421+
let ident = ast_util::path_to_ident(path);
422+
(*fn_maps).add_variable(Arg(arg_id, ident, mode));
423+
}
420424
};
421425

422426
// gather up the various local variables, significant expressions,
@@ -447,7 +451,7 @@ fn visit_fn(fk: visit::fn_kind, decl: fn_decl, body: blk,
447451
});
448452
check_vt.visit_block(body, lsets, check_vt);
449453
lsets.check_ret(id, sp, fk, entry_ln);
450-
lsets.warn_about_unused_args(sp, decl, entry_ln);
454+
lsets.warn_about_unused_args(decl, entry_ln);
451455
}
452456

453457
fn visit_local(local: @local, &&self: @IrMaps, vt: vt<@IrMaps>) {
@@ -937,8 +941,11 @@ impl Liveness {
937941
// the end. This will prevent us from moving out of
938942
// such variables but also prevent us from registering
939943
// last uses and so forth.
940-
let var = self.variable(arg.id, blk.span);
941-
self.acc(self.s.exit_ln, var, ACC_READ);
944+
do pat_util::pat_bindings(self.tcx.def_map, arg.pat)
945+
|_bm, arg_id, _sp, _path| {
946+
let var = self.variable(arg_id, blk.span);
947+
self.acc(self.s.exit_ln, var, ACC_READ);
948+
}
942949
}
943950
by_move | by_copy => {
944951
// These are owned modes. If we don't use the
@@ -1791,10 +1798,13 @@ impl @Liveness {
17911798
if name[0] == ('_' as u8) {None} else {Some(name)}
17921799
}
17931800

1794-
fn warn_about_unused_args(sp: span, decl: fn_decl, entry_ln: LiveNode) {
1801+
fn warn_about_unused_args(decl: fn_decl, entry_ln: LiveNode) {
17951802
for decl.inputs.each |arg| {
1796-
let var = self.variable(arg.id, arg.ty.span);
1797-
self.warn_about_unused(sp, entry_ln, var);
1803+
do pat_util::pat_bindings(self.tcx.def_map, arg.pat)
1804+
|_bm, p_id, sp, _n| {
1805+
let var = self.variable(p_id, sp);
1806+
self.warn_about_unused(sp, entry_ln, var);
1807+
}
17981808
}
17991809
}
18001810

src/librustc/middle/resolve.rs

Lines changed: 38 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@ use syntax::ast::{foreign_item, foreign_item_const, foreign_item_fn, ge};
2828
use syntax::ast::{gt, ident, impure_fn, inherited, item, item_class};
2929
use syntax::ast::{item_const, item_enum, item_fn, item_foreign_mod};
3030
use syntax::ast::{item_impl, item_mac, item_mod, item_trait, item_ty, le};
31-
use syntax::ast::{local, local_crate, lt, method, module_ns, mul, ne, neg};
32-
use syntax::ast::{node_id, pat, pat_enum, pat_ident, path, prim_ty};
31+
use syntax::ast::{local, local_crate, lt, method, mode, module_ns, mul, ne};
32+
use syntax::ast::{neg, node_id, pat, pat_enum, pat_ident, path, prim_ty};
3333
use syntax::ast::{pat_box, pat_lit, pat_range, pat_rec, pat_struct};
3434
use syntax::ast::{pat_tup, pat_uniq, pat_wild, private, provided, public};
3535
use syntax::ast::{required, rem, self_ty_, shl, shr, stmt_decl};
@@ -103,12 +103,32 @@ struct Export2 {
103103

104104
enum PatternBindingMode {
105105
RefutableMode,
106-
IrrefutableMode
106+
LocalIrrefutableMode,
107+
ArgumentIrrefutableMode(mode)
107108
}
108109

109110
impl PatternBindingMode : cmp::Eq {
110111
pure fn eq(other: &PatternBindingMode) -> bool {
111-
(self as uint) == ((*other) as uint)
112+
match self {
113+
RefutableMode => {
114+
match *other {
115+
RefutableMode => true,
116+
_ => false
117+
}
118+
}
119+
LocalIrrefutableMode => {
120+
match *other {
121+
LocalIrrefutableMode => true,
122+
_ => false
123+
}
124+
}
125+
ArgumentIrrefutableMode(mode_a) => {
126+
match *other {
127+
ArgumentIrrefutableMode(mode_b) => mode_a == mode_b,
128+
_ => false
129+
}
130+
}
131+
}
112132
}
113133
pure fn ne(other: &PatternBindingMode) -> bool { !self.eq(other) }
114134
}
@@ -3770,15 +3790,17 @@ impl Resolver {
37703790
}
37713791
Some(declaration) => {
37723792
for declaration.inputs.each |argument| {
3773-
let name = argument.ident;
3774-
let def_like = dl_def(def_arg(argument.id,
3775-
argument.mode));
3776-
(*function_value_rib).bindings.insert(name, def_like);
3793+
let binding_mode =
3794+
ArgumentIrrefutableMode(argument.mode);
3795+
self.resolve_pattern(argument.pat,
3796+
binding_mode,
3797+
Immutable,
3798+
None,
3799+
visitor);
37773800

37783801
self.resolve_type(argument.ty, visitor);
37793802

3780-
debug!("(resolving function) recorded argument `%s`",
3781-
self.session.str_of(name));
3803+
debug!("(resolving function) recorded argument");
37823804
}
37833805

37843806
self.resolve_type(declaration.output, visitor);
@@ -4013,7 +4035,7 @@ impl Resolver {
40134035
}
40144036

40154037
// Resolve the pattern.
4016-
self.resolve_pattern(local.node.pat, IrrefutableMode, mutability,
4038+
self.resolve_pattern(local.node.pat, LocalIrrefutableMode, mutability,
40174039
None, visitor);
40184040
}
40194041

@@ -4249,10 +4271,14 @@ impl Resolver {
42494271

42504272
def_binding(pattern.id, binding_mode)
42514273
}
4252-
IrrefutableMode => {
4274+
LocalIrrefutableMode => {
42534275
// But for locals, we use `def_local`.
42544276
def_local(pattern.id, is_mutable)
42554277
}
4278+
ArgumentIrrefutableMode(argument_mode) => {
4279+
// And for function arguments, `def_arg`.
4280+
def_arg(pattern.id, argument_mode)
4281+
}
42564282
};
42574283

42584284
// Record the definition so that later passes

0 commit comments

Comments
 (0)