rustc: Support irrefutable patterns in function arguments. r=nmatsakis

This commit is contained in:
Patrick Walton 2012-11-06 18:41:06 -08:00
parent b223c9c465
commit 0fc952372a
31 changed files with 392 additions and 159 deletions

View file

@ -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};
}
}

View file

@ -35,7 +35,7 @@ pub trait SendMap<K:Eq Hash, V: Copy> {
/// Open addressing with linear probing.
pub mod linear {
const initial_capacity: uint = 32u; // 2^5
const INITIAL_CAPACITY: uint = 32u; // 2^5
struct Bucket<K:Eq Hash,V> {
hash: uint,
@ -62,7 +62,7 @@ pub mod linear {
}
pub fn LinearMap<K:Eq Hash,V>() -> LinearMap<K,V> {
linear_map_with_capacity(32)
linear_map_with_capacity(INITIAL_CAPACITY)
}
pub fn linear_map_with_capacity<K:Eq Hash,V>(

View file

@ -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
}
}

View file

@ -570,7 +570,20 @@ 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| {
// For the purposes of purity, only consider function-
// typed bindings in trivial patterns to be function
// arguments. For example, do not allow `f` and `g` in
// (f, g): (&fn(), &fn()) to be called.
match input.pat.node {
ast::pat_ident(_, _, None) => {
fn_args.push(input.pat.id);
}
_ => {} // Ignore this argument.
}
}
self.fn_args = @move fn_args;
}
}

View file

@ -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,23 @@ 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");
}
}
}
fn is_refutable(tcx: ty::ctxt, pat: &pat) -> bool {
match tcx.def_map.find(pat.id) {
Some(def_variant(enum_id, _)) => {

View file

@ -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);
}
}
}

View file

@ -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

View file

@ -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>) -> BasicBlockRef {
match *done { Some(bb) => return bb, _ => () }
finished: @mut Option<BasicBlockRef>) -> 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(_, _) => ()
}

View file

@ -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
}
};

View file

@ -320,9 +320,9 @@ impl cleantype : cmp::Eq {
type cleanup_path = {target: Option<BasicBlockRef>,
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);
}
}
}

View file

@ -664,13 +664,13 @@ fn create_local_var(bcx: block, local: @ast::local)
}
fn create_arg(bcx: block, arg: ast::arg, sp: span)
-> @metadata<argument_md> unsafe {
-> Option<@metadata<argument_md>> unsafe {
let fcx = bcx.fcx, cx = fcx.ccx;
let cache = get_cache(cx);
let tg = ArgVariableTag;
match cached_metadata::<@metadata<argument_md>>(
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) {

View file

@ -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,

View file

@ -2532,18 +2532,19 @@ fn type_param(ty: t) -> Option<uint> {
// 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<mt> {
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<mt> {
deref_sty(cx, &get(t).sty, explicit)
}
fn deref_sty(cx: ctxt, sty: &sty, expl: bool) -> Option<mt> {
fn deref_sty(cx: ctxt, sty: &sty, explicit: bool) -> Option<mt> {
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)
}
}

View file

@ -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.

View file

@ -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),
_ => ()

View file

@ -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;
}

View file

@ -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();

View file

@ -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]

View file

@ -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,

View file

@ -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: @{

View file

@ -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)
}
}

View file

@ -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()}
}

View file

@ -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 {

View file

@ -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()}

View file

@ -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);
}

View file

@ -277,7 +277,10 @@ fn visit_ty_params<E>(tps: ~[ty_param], e: E, v: vt<E>) {
}
fn visit_fn_decl<E>(fd: fn_decl, e: E, v: vt<E>) {
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);
}

View file

@ -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],
{

View file

@ -0,0 +1,6 @@
pure fn call_first((x, _y): (&fn(), &fn())) {
x(); //~ ERROR access to impure function prohibited in pure context
}
fn main() {}

View file

@ -0,0 +1,5 @@
fn main() {
let f = |3: int| io::println("hello"); //~ ERROR refutable pattern
f(4);
}

View file

@ -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
}

View file

@ -0,0 +1,12 @@
struct Foo {
x: int,
y: int
}
fn main() {
let f = |(x, _): (int, int)| io::println((x + 1).to_str());
let g = |Foo { x: x, y: y }: Foo| io::println((x + 1).to_str());
f((2, 3));
g(Foo { x: 1, y: 2 });
}