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/metadata/tyencode.rs b/src/librustc/metadata/tyencode.rs index 4129066ff2863..922fff18e9e59 100644 --- a/src/librustc/metadata/tyencode.rs +++ b/src/librustc/metadata/tyencode.rs @@ -286,6 +286,11 @@ fn enc_sty(w: io::Writer, cx: @ctxt, st: ty::sty) { w.write_char('I'); w.write_uint(id.to_uint()); } + ty::ty_infer(ty::FloatVar(id)) => { + w.write_char('X'); + w.write_char('F'); + w.write_uint(id.to_uint()); + } ty::ty_param({idx: id, def_id: did}) => { w.write_char('p'); w.write_str(cx.ds(did)); 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/const_eval.rs b/src/librustc/middle/const_eval.rs index 3e30bf50e023d..cbe5430b5be40 100644 --- a/src/librustc/middle/const_eval.rs +++ b/src/librustc/middle/const_eval.rs @@ -389,6 +389,8 @@ fn lit_to_const(lit: @lit) -> const_val { lit_uint(n, _) => const_uint(n), lit_int_unsuffixed(n) => const_int(n), lit_float(n, _) => const_float(float::from_str(*n).get() as f64), + lit_float_unsuffixed(n) => + const_float(float::from_str(*n).get() as f64), lit_nil => const_int(0i64), lit_bool(b) => const_bool(b) } 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/consts.rs b/src/librustc/middle/trans/consts.rs index 23ec0b6a9c184..6796d139bc76f 100644 --- a/src/librustc/middle/trans/consts.rs +++ b/src/librustc/middle/trans/consts.rs @@ -22,6 +22,19 @@ fn const_lit(cx: @crate_ctxt, e: @ast::expr, lit: ast::lit) } } ast::lit_float(fs, t) => C_floating(*fs, T_float_ty(cx, t)), + ast::lit_float_unsuffixed(fs) => { + let lit_float_ty = ty::node_id_to_type(cx.tcx, e.id); + match ty::get(lit_float_ty).sty { + ty::ty_float(t) => { + C_floating(*fs, T_float_ty(cx, t)) + } + _ => { + cx.sess.span_bug(lit.span, + ~"floating point literal doesn't have the right \ + type"); + } + } + } ast::lit_bool(b) => C_bool(b), ast::lit_nil => C_nil(), ast::lit_str(s) => C_estr_slice(cx, *s) 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..e7cf5fa8ad8ab 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -21,7 +21,7 @@ use util::ppaux::{ty_to_str, proto_ty_to_str, tys_to_str}; export ProvidedMethodSource; export InstantiatedTraitRef; -export TyVid, IntVid, FnVid, RegionVid, vid; +export TyVid, IntVid, FloatVid, FnVid, RegionVid, vid; export br_hashmap; export is_instantiable; export node_id_to_type; @@ -86,6 +86,7 @@ export ty_fn, FnTy, FnTyBase, FnMeta, FnSig, mk_fn; export ty_fn_proto, ty_fn_purity, ty_fn_ret, ty_fn_ret_style, tys_in_fn_ty; export ty_int, mk_int, mk_mach_int, mk_char; export mk_i8, mk_u8, mk_i16, mk_u16, mk_i32, mk_u32, mk_i64, mk_u64; +export mk_f32, mk_f64; export ty_estr, mk_estr, type_is_str; export ty_evec, mk_evec, type_is_vec; export ty_unboxed_vec, mk_unboxed_vec, mk_mut_unboxed_vec; @@ -102,8 +103,8 @@ export ty_tup, mk_tup; export ty_type, mk_type; export ty_uint, mk_uint, mk_mach_uint; export ty_uniq, mk_uniq, mk_imm_uniq, type_is_unique_box; -export ty_infer, mk_infer, type_is_ty_var, mk_var, mk_int_var; -export InferTy, TyVar, IntVar; +export ty_infer, mk_infer, type_is_ty_var, mk_var, mk_int_var, mk_float_var; +export InferTy, TyVar, IntVar, FloatVar; export ty_self, mk_self, type_has_self; export ty_class; export Region, bound_region, encl_region; @@ -172,7 +173,8 @@ export ty_sort_str; export normalize_ty; export to_str; export bound_const; -export terr_no_integral_type, terr_ty_param_size, terr_self_substs; +export terr_no_integral_type, terr_no_floating_point_type; +export terr_ty_param_size, terr_self_substs; export terr_in_field, terr_record_fields, terr_vstores_differ, terr_arg_count; export terr_sorts, terr_vec, terr_str, terr_record_size, terr_tuple_size; export terr_regions_does_not_outlive, terr_mutability, terr_purity_mismatch; @@ -666,6 +668,7 @@ enum type_err { terr_sorts(expected_found), terr_self_substs, terr_no_integral_type, + terr_no_floating_point_type, } enum param_bound { @@ -678,6 +681,7 @@ enum param_bound { enum TyVid = uint; enum IntVid = uint; +enum FloatVid = uint; enum FnVid = uint; #[auto_serialize] #[auto_deserialize] @@ -685,14 +689,16 @@ enum RegionVid = uint; enum InferTy { TyVar(TyVid), - IntVar(IntVid) + IntVar(IntVid), + FloatVar(FloatVid) } impl InferTy : to_bytes::IterBytes { pure fn iter_bytes(+lsb0: bool, f: to_bytes::Cb) { match self { TyVar(ref tv) => to_bytes::iter_bytes_2(&0u8, tv, lsb0, f), - IntVar(ref iv) => to_bytes::iter_bytes_2(&1u8, iv, lsb0, f) + IntVar(ref iv) => to_bytes::iter_bytes_2(&1u8, iv, lsb0, f), + FloatVar(ref fv) => to_bytes::iter_bytes_2(&2u8, fv, lsb0, f) } } } @@ -758,6 +764,11 @@ impl IntVid: vid { pure fn to_str() -> ~str { fmt!("", self.to_uint()) } } +impl FloatVid: vid { + pure fn to_uint() -> uint { *self } + pure fn to_str() -> ~str { fmt!("", self.to_uint()) } +} + impl FnVid: vid { pure fn to_uint() -> uint { *self } pure fn to_str() -> ~str { fmt!("", self.to_uint()) } @@ -773,6 +784,7 @@ impl InferTy { match self { TyVar(v) => v.to_uint() << 1, IntVar(v) => (v.to_uint() << 1) + 1, + FloatVar(v) => (v.to_uint() << 1) + 2 } } @@ -780,6 +792,7 @@ impl InferTy { match self { TyVar(v) => v.to_str(), IntVar(v) => v.to_str(), + FloatVar(v) => v.to_str() } } } @@ -812,6 +825,12 @@ impl IntVid : to_bytes::IterBytes { } } +impl FloatVid : to_bytes::IterBytes { + pure fn iter_bytes(+lsb0: bool, f: to_bytes::Cb) { + (*self).iter_bytes(lsb0, f) + } +} + impl FnVid : to_bytes::IterBytes { pure fn iter_bytes(+lsb0: bool, f: to_bytes::Cb) { (*self).iter_bytes(lsb0, f) @@ -1030,6 +1049,10 @@ fn mk_u32(cx: ctxt) -> t { mk_t(cx, ty_uint(ast::ty_u32)) } fn mk_u64(cx: ctxt) -> t { mk_t(cx, ty_uint(ast::ty_u64)) } +fn mk_f32(cx: ctxt) -> t { mk_t(cx, ty_float(ast::ty_f32)) } + +fn mk_f64(cx: ctxt) -> t { mk_t(cx, ty_float(ast::ty_f64)) } + fn mk_mach_int(cx: ctxt, tm: ast::int_ty) -> t { mk_t(cx, ty_int(tm)) } fn mk_mach_uint(cx: ctxt, tm: ast::uint_ty) -> t { mk_t(cx, ty_uint(tm)) } @@ -1110,9 +1133,9 @@ fn mk_class(cx: ctxt, class_id: ast::def_id, +substs: substs) -> t { fn mk_var(cx: ctxt, v: TyVid) -> t { mk_infer(cx, TyVar(v)) } -fn mk_int_var(cx: ctxt, v: IntVid) -> t { - mk_infer(cx, IntVar(v)) -} +fn mk_int_var(cx: ctxt, v: IntVid) -> t { mk_infer(cx, IntVar(v)) } + +fn mk_float_var(cx: ctxt, v: FloatVid) -> t { mk_infer(cx, FloatVar(v)) } fn mk_infer(cx: ctxt, it: InferTy) -> t { mk_t(cx, ty_infer(it)) } @@ -1661,7 +1684,8 @@ pure fn type_is_unique(ty: t) -> bool { pure fn type_is_scalar(ty: t) -> bool { match get(ty).sty { ty_nil | ty_bool | ty_int(_) | ty_float(_) | ty_uint(_) | - ty_infer(IntVar(_)) | ty_type | ty_ptr(_) => true, + ty_infer(IntVar(_)) | ty_infer(FloatVar(_)) | ty_type | + ty_ptr(_) => true, _ => false } } @@ -2428,7 +2452,7 @@ fn type_is_integral(ty: t) -> bool { fn type_is_fp(ty: t) -> bool { match get(ty).sty { - ty_float(_) => true, + ty_infer(FloatVar(_)) | ty_float(_) => true, _ => false } } @@ -2532,18 +2556,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) } @@ -3259,6 +3284,7 @@ fn ty_sort_str(cx: ctxt, t: t) -> ~str { ty_tup(_) => ~"tuple", ty_infer(TyVar(_)) => ~"inferred type", ty_infer(IntVar(_)) => ~"integral variable", + ty_infer(FloatVar(_)) => ~"floating-point variable", ty_param(_) => ~"type parameter", ty_self => ~"self" } @@ -3386,6 +3412,10 @@ fn type_err_to_str(cx: ctxt, err: &type_err) -> ~str { ~"couldn't determine an appropriate integral type for integer \ literal" } + terr_no_floating_point_type => { + ~"couldn't determine an appropriate floating point type for \ + floating point literal" + } } } @@ -3443,7 +3473,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) } } @@ -3999,7 +4029,7 @@ fn is_binopable(_cx: ctxt, ty: t, op: ast::binop) -> bool { match get(ty).sty { ty_bool => tycat_bool, ty_int(_) | ty_uint(_) | ty_infer(IntVar(_)) => tycat_int, - ty_float(_) => tycat_float, + ty_float(_) | ty_infer(FloatVar(_)) => tycat_float, ty_rec(_) | ty_tup(_) | ty_enum(_, _) => tycat_struct, ty_bot => tycat_bot, _ => tycat_other @@ -4229,6 +4259,11 @@ impl IntVid : cmp::Eq { pure fn ne(other: &IntVid) -> bool { *self != *(*other) } } +impl FloatVid : cmp::Eq { + pure fn eq(other: &FloatVid) -> bool { *self == *(*other) } + pure fn ne(other: &FloatVid) -> bool { *self != *(*other) } +} + impl FnVid : cmp::Eq { pure fn eq(other: &FnVid) -> bool { *self == *(*other) } pure fn ne(other: &FnVid) -> bool { *self != *(*other) } diff --git a/src/librustc/middle/typeck/check.rs b/src/librustc/middle/typeck/check.rs index 3de9955455411..3f96f5af1a1a3 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. @@ -838,6 +850,11 @@ fn check_lit(fcx: @fn_ctxt, lit: @ast::lit) -> ty::t { ty::mk_int_var(tcx, fcx.infcx().next_int_var_id()) } ast::lit_float(_, t) => ty::mk_mach_float(tcx, t), + ast::lit_float_unsuffixed(_) => { + // An unsuffixed floating point literal could have any floating point + // type, so we create a floating point type variable for it. + ty::mk_float_var(tcx, fcx.infcx().next_float_var_id()) + } ast::lit_nil => ty::mk_nil(tcx), ast::lit_bool(_) => ty::mk_bool(tcx) } 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/method.rs b/src/librustc/middle/typeck/check/method.rs index 8afd28a591468..ae6d7cd40e824 100644 --- a/src/librustc/middle/typeck/check/method.rs +++ b/src/librustc/middle/typeck/check/method.rs @@ -664,6 +664,7 @@ impl LookupContext { match ty::get(self_ty).sty { ty_box(*) | ty_uniq(*) | ty_rptr(*) | ty_infer(IntVar(_)) | // FIXME(#3211)---should be resolved + ty_infer(FloatVar(_)) | // FIXME(#3211)---should be resolved ty_self | ty_param(*) | ty_nil | ty_bot | ty_bool | ty_int(*) | ty_uint(*) | ty_float(*) | ty_enum(*) | ty_ptr(*) | ty_rec(*) | 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/librustc/middle/typeck/infer.rs b/src/librustc/middle/typeck/infer.rs index 61dc10ee09e05..edb6452ab50e4 100644 --- a/src/librustc/middle/typeck/infer.rs +++ b/src/librustc/middle/typeck/infer.rs @@ -209,6 +209,8 @@ overconstrains the type, it's a type error; if we reach the point at which type variables must be resolved and an integral type variable is still underconstrained, it defaults to `int` as a last resort. +Floating point types are handled similarly to integral types. + ## GLB/LUB Computing the greatest-lower-bound and least-upper-bound of two @@ -250,8 +252,8 @@ use std::smallintmap; use std::smallintmap::smallintmap; use std::map::HashMap; use middle::ty; -use middle::ty::{TyVid, IntVid, RegionVid, vid, - ty_int, ty_uint, get, terr_fn, TyVar, IntVar}; +use middle::ty::{TyVid, IntVid, FloatVid, RegionVid, vid, + ty_int, ty_uint, get, terr_fn, TyVar, IntVar, FloatVar}; use syntax::{ast, ast_util}; use syntax::ast::{ret_style, purity}; use util::ppaux::{ty_to_str, mt_to_str}; @@ -272,6 +274,7 @@ use resolve::{resolve_nested_tvar, resolve_rvar, resolve_ivar, resolve_all, resolve_and_force_all_but_regions, resolver}; use unify::{vals_and_bindings, root}; use integral::{int_ty_set, int_ty_set_all}; +use floating::{float_ty_set, float_ty_set_all}; use combine::{combine_fields, eq_tys}; use assignment::Assign; use to_str::ToStr; @@ -318,12 +321,17 @@ enum infer_ctxt = @{ // represented by an int_ty_set. int_var_bindings: vals_and_bindings, + // The types that might instantiate a floating-point type variable are + // represented by an float_ty_set. + float_var_bindings: vals_and_bindings, + // For region variables. region_vars: RegionVarBindings, // For keeping track of existing type and region variables. ty_var_counter: @mut uint, int_var_counter: @mut uint, + float_var_counter: @mut uint, region_var_counter: @mut uint }; @@ -359,9 +367,11 @@ fn new_infer_ctxt(tcx: ty::ctxt) -> infer_ctxt { infer_ctxt(@{tcx: tcx, ty_var_bindings: new_vals_and_bindings(), int_var_bindings: new_vals_and_bindings(), + float_var_bindings: new_vals_and_bindings(), region_vars: RegionVarBindings(tcx), ty_var_counter: @mut 0u, int_var_counter: @mut 0u, + float_var_counter: @mut 0u, region_var_counter: @mut 0u})} fn mk_subty(cx: infer_ctxt, a_is_expected: bool, span: span, @@ -627,6 +637,18 @@ impl infer_ctxt { ty::mk_int_var(self.tcx, self.next_int_var_id()) } + fn next_float_var_id() -> FloatVid { + let id = *self.float_var_counter; + *self.float_var_counter += 1; + + self.float_var_bindings.vals.insert(id, root(float_ty_set_all(), 0)); + return FloatVid(id); + } + + fn next_float_var() -> ty::t { + ty::mk_float_var(self.tcx, self.next_float_var_id()) + } + fn next_region_var_nb(span: span) -> ty::Region { ty::re_infer(ty::ReVar(self.region_vars.new_region_var(span))) } diff --git a/src/librustc/middle/typeck/infer/combine.rs b/src/librustc/middle/typeck/infer/combine.rs index c43f1e9c3865c..099b0469bcf90 100644 --- a/src/librustc/middle/typeck/infer/combine.rs +++ b/src/librustc/middle/typeck/infer/combine.rs @@ -385,6 +385,17 @@ fn super_tys( self.infcx().t_sub_int_var(a, b_id).then(|| Ok(a) ) } + // Relate floating-point variables to other types + (ty::ty_infer(FloatVar(a_id)), ty::ty_infer(FloatVar(b_id))) => { + self.infcx().float_vars(a_id, b_id).then(|| Ok(a) ) + } + (ty::ty_infer(FloatVar(a_id)), ty::ty_float(_)) => { + self.infcx().float_var_sub_t(a_id, b).then(|| Ok(a) ) + } + (ty::ty_float(_), ty::ty_infer(FloatVar(b_id))) => { + self.infcx().t_sub_float_var(a, b_id).then(|| Ok(a) ) + } + (ty::ty_int(_), _) | (ty::ty_uint(_), _) | (ty::ty_float(_), _) => { diff --git a/src/librustc/middle/typeck/infer/floating.rs b/src/librustc/middle/typeck/infer/floating.rs new file mode 100644 index 0000000000000..1f2158090533b --- /dev/null +++ b/src/librustc/middle/typeck/infer/floating.rs @@ -0,0 +1,48 @@ +/*! + +Code related to floating-point type inference. + +*/ + +use to_str::ToStr; +use middle::ty::ty_float; + +// Bitvector to represent sets of floating-point types. +pub enum float_ty_set = uint; + +// Constants representing singleton sets containing each of the floating-point +// types. +pub const FLOAT_TY_SET_EMPTY: uint = 0b000u; +pub const FLOAT_TY_SET_FLOAT: uint = 0b001u; +pub const FLOAT_TY_SET_F32: uint = 0b010u; +pub const FLOAT_TY_SET_F64: uint = 0b100u; + +pub fn float_ty_set_all() -> float_ty_set { + float_ty_set(FLOAT_TY_SET_FLOAT | FLOAT_TY_SET_F32 | FLOAT_TY_SET_F64) +} + +pub fn intersection(a: float_ty_set, b: float_ty_set) -> float_ty_set { + float_ty_set(*a & *b) +} + +pub fn single_type_contained_in(tcx: ty::ctxt, a: float_ty_set) + -> Option { + debug!("single_type_contained_in(a=%s)", uint::to_str(*a, 10)); + + if *a == FLOAT_TY_SET_FLOAT { return Some(ty::mk_float(tcx)); } + if *a == FLOAT_TY_SET_F32 { return Some(ty::mk_f32(tcx)); } + if *a == FLOAT_TY_SET_F64 { return Some(ty::mk_f64(tcx)); } + return None; +} + +pub fn convert_floating_point_ty_to_float_ty_set(tcx: ty::ctxt, t: ty::t) + -> float_ty_set { + match get(t).sty { + ty::ty_float(ast::ty_f) => float_ty_set(FLOAT_TY_SET_FLOAT), + ty::ty_float(ast::ty_f32) => float_ty_set(FLOAT_TY_SET_F32), + ty::ty_float(ast::ty_f64) => float_ty_set(FLOAT_TY_SET_F64), + _ => tcx.sess.bug(~"non-floating-point type passed to \ + convert_floating_point_ty_to_float_ty_set()") + } +} + diff --git a/src/librustc/middle/typeck/infer/resolve.rs b/src/librustc/middle/typeck/infer/resolve.rs index f0794bf752e98..956ab9998dea0 100644 --- a/src/librustc/middle/typeck/infer/resolve.rs +++ b/src/librustc/middle/typeck/infer/resolve.rs @@ -15,8 +15,10 @@ // `resolve_nested_tvar` is passed, we will then go and recursively // resolve ``. // -// The options `resolve_rvar` and `resolve_ivar` control whether we -// resolve region and integral variables, respectively. +// The options `resolve_rvar` controls whether we resolve region +// variables. The options `resolve_fvar` and `resolve_ivar` control +// whether we resolve floating point and integral variables, +// respectively. // // # What do if things are unconstrained // @@ -35,16 +37,19 @@ // probably better off writing `resolve_all - resolve_ivar`. use integral::*; +use floating::*; use to_str::ToStr; const resolve_nested_tvar: uint = 0b00000001; const resolve_rvar: uint = 0b00000010; const resolve_ivar: uint = 0b00000100; -const resolve_all: uint = 0b00000111; +const resolve_fvar: uint = 0b00001000; +const resolve_all: uint = 0b00001111; const force_tvar: uint = 0b00010000; const force_rvar: uint = 0b00100000; const force_ivar: uint = 0b01000000; -const force_all: uint = 0b01110000; +const force_fvar: uint = 0b11000000; +const force_all: uint = 0b11110000; const not_regions: uint = !(force_rvar | resolve_rvar); @@ -119,6 +124,9 @@ impl resolve_state { ty::ty_infer(IntVar(vid)) => { self.resolve_int_var(vid) } + ty::ty_infer(FloatVar(vid)) => { + self.resolve_float_var(vid) + } _ => { if !self.should(resolve_rvar) && !self.should(resolve_nested_tvar) { @@ -212,7 +220,7 @@ impl resolve_state { // If there's only one type in the set of possible types, then // that's the answer. - match single_type_contained_in(self.infcx.tcx, pt) { + match integral::single_type_contained_in(self.infcx.tcx, pt) { Some(t) => t, None => { if self.should(force_ivar) { @@ -230,5 +238,36 @@ impl resolve_state { } } } + + fn resolve_float_var(vid: FloatVid) -> ty::t { + if !self.should(resolve_fvar) { + return ty::mk_float_var(self.infcx.tcx, vid); + } + + let nde = self.infcx.get(&self.infcx.float_var_bindings, vid); + let pt = nde.possible_types; + + // If there's only one type in the set of possible types, then + // that's the answer. + match floating::single_type_contained_in(self.infcx.tcx, pt) { + Some(t) => t, + None => { + if self.should(force_fvar) { + // As a last resort, default to float. + let ty = ty::mk_float(self.infcx.tcx); + self.infcx.set( + &self.infcx.float_var_bindings, + vid, + root( + convert_floating_point_ty_to_float_ty_set( + self.infcx.tcx, ty), + nde.rank)); + ty + } else { + ty::mk_float_var(self.infcx.tcx, vid) + } + } + } + } } diff --git a/src/librustc/middle/typeck/infer/to_str.rs b/src/librustc/middle/typeck/infer/to_str.rs index 3c9b22ff66f4d..73eef376b1ed2 100644 --- a/src/librustc/middle/typeck/infer/to_str.rs +++ b/src/librustc/middle/typeck/infer/to_str.rs @@ -1,4 +1,5 @@ use integral::{int_ty_set}; +use floating::{float_ty_set}; use unify::{var_value, redirect, root}; trait ToStr { @@ -54,6 +55,14 @@ impl int_ty_set: ToStr { } } +impl float_ty_set: ToStr { + fn to_str(_cx: infer_ctxt) -> ~str { + match self { + float_ty_set(v) => uint::to_str(v, 10u) + } + } +} + impl var_value: ToStr { fn to_str(cx: infer_ctxt) -> ~str { match self { diff --git a/src/librustc/middle/typeck/infer/unify.rs b/src/librustc/middle/typeck/infer/unify.rs index f865705563c60..88827849fa608 100644 --- a/src/librustc/middle/typeck/infer/unify.rs +++ b/src/librustc/middle/typeck/infer/unify.rs @@ -1,5 +1,6 @@ use combine::combine; use integral::*; +use floating::*; use to_str::ToStr; use std::smallintmap::SmallIntMap; @@ -294,6 +295,34 @@ fn bnds( // Integral variables impl infer_ctxt { + fn optimize_ranks(vb: &vals_and_bindings, + nde_a: node, + nde_b: node, + a_id: V, + b_id: V, + intersection: T) { + if nde_a.rank > nde_b.rank { + debug!("int_vars(): a has smaller rank"); + // a has greater rank, so a should become b's parent, + // i.e., b should redirect to a. + self.set(vb, a_id, root(intersection, nde_a.rank)); + self.set(vb, b_id, redirect(a_id)); + } else if nde_a.rank < nde_b.rank { + debug!("int_vars(): b has smaller rank"); + // b has greater rank, so a should redirect to b. + self.set(vb, b_id, root(intersection, nde_b.rank)); + self.set(vb, a_id, redirect(b_id)); + } else { + debug!("int_vars(): a and b have equal rank"); + assert nde_a.rank == nde_b.rank; + // If equal, just redirect one to the other and increment + // the other's rank. We choose arbitrarily to redirect b + // to a and increment a's rank. + self.set(vb, a_id, root(intersection, nde_a.rank + 1u)); + self.set(vb, b_id, redirect(a_id)); + }; + } + fn int_vars(a_id: ty::IntVid, b_id: ty::IntVid) -> ures { let vb = &self.int_var_bindings; @@ -310,32 +339,13 @@ impl infer_ctxt { // Otherwise, take the intersection of the two sets of // possible types. - let intersection = intersection(a_pt, b_pt); + let intersection = integral::intersection(a_pt, b_pt); if *intersection == INT_TY_SET_EMPTY { return Err(ty::terr_no_integral_type); } // Rank optimization - if nde_a.rank > nde_b.rank { - debug!("int_vars(): a has smaller rank"); - // a has greater rank, so a should become b's parent, - // i.e., b should redirect to a. - self.set(vb, a_id, root(intersection, nde_a.rank)); - self.set(vb, b_id, redirect(a_id)); - } else if nde_a.rank < nde_b.rank { - debug!("int_vars(): b has smaller rank"); - // b has greater rank, so a should redirect to b. - self.set(vb, b_id, root(intersection, nde_b.rank)); - self.set(vb, a_id, redirect(b_id)); - } else { - debug!("int_vars(): a and b have equal rank"); - assert nde_a.rank == nde_b.rank; - // If equal, just redirect one to the other and increment - // the other's rank. We choose arbitrarily to redirect b - // to a and increment a's rank. - self.set(vb, a_id, root(intersection, nde_a.rank + 1u)); - self.set(vb, b_id, redirect(a_id)); - }; + self.optimize_ranks(vb, nde_a, nde_b, a_id, b_id, intersection); uok() } @@ -349,7 +359,7 @@ impl infer_ctxt { let a_pt = nde_a.possible_types; let intersection = - intersection(a_pt, + integral::intersection(a_pt, convert_integral_ty_to_int_ty_set(self.tcx, b)); if *intersection == INT_TY_SET_EMPTY { return Err(ty::terr_no_integral_type); @@ -367,7 +377,7 @@ impl infer_ctxt { let b_pt = nde_b.possible_types; let intersection = - intersection(b_pt, + integral::intersection(b_pt, convert_integral_ty_to_int_ty_set(self.tcx, a)); if *intersection == INT_TY_SET_EMPTY { return Err(ty::terr_no_integral_type); @@ -378,3 +388,74 @@ impl infer_ctxt { } + +// ______________________________________________________________________ +// Floating point variables + +impl infer_ctxt { + fn float_vars(a_id: ty::FloatVid, b_id: ty::FloatVid) -> ures { + let vb = &self.float_var_bindings; + + let nde_a = self.get(vb, a_id); + let nde_b = self.get(vb, b_id); + let a_id = nde_a.root; + let b_id = nde_b.root; + let a_pt = nde_a.possible_types; + let b_pt = nde_b.possible_types; + + // If we're already dealing with the same two variables, + // there's nothing to do. + if a_id == b_id { return uok(); } + + // Otherwise, take the intersection of the two sets of + // possible types. + let intersection = floating::intersection(a_pt, b_pt); + if *intersection == FLOAT_TY_SET_EMPTY { + return Err(ty::terr_no_floating_point_type); + } + + // Rank optimization + self.optimize_ranks(vb, nde_a, nde_b, a_id, b_id, intersection); + + uok() + } + + fn float_var_sub_t(a_id: ty::FloatVid, b: ty::t) -> ures { + assert ty::type_is_fp(b); + + let vb = &self.float_var_bindings; + let nde_a = self.get(vb, a_id); + let a_id = nde_a.root; + let a_pt = nde_a.possible_types; + + let intersection = + floating::intersection( + a_pt, + convert_floating_point_ty_to_float_ty_set(self.tcx, b)); + if *intersection == FLOAT_TY_SET_EMPTY { + return Err(ty::terr_no_floating_point_type); + } + self.set(vb, a_id, root(intersection, nde_a.rank)); + uok() + } + + fn t_sub_float_var(a: ty::t, b_id: ty::FloatVid) -> ures { + assert ty::type_is_fp(a); + let vb = &self.float_var_bindings; + + let nde_b = self.get(vb, b_id); + let b_id = nde_b.root; + let b_pt = nde_b.possible_types; + + let intersection = + floating::intersection( + b_pt, + convert_floating_point_ty_to_float_ty_set(self.tcx, a)); + if *intersection == FLOAT_TY_SET_EMPTY { + return Err(ty::terr_no_floating_point_type); + } + self.set(vb, b_id, root(intersection, nde_b.rank)); + uok() + } +} + diff --git a/src/librustc/rustc.rc b/src/librustc/rustc.rc index 0e6f6536bf57e..0dd9ae7217f47 100644 --- a/src/librustc/rustc.rc +++ b/src/librustc/rustc.rc @@ -128,6 +128,7 @@ mod middle { mod glb; #[legacy_exports] mod integral; + mod floating; #[legacy_exports] mod lattice; #[legacy_exports] diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 8fcb9300b52e9..dd90dfee683da 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] @@ -862,6 +862,7 @@ enum lit_ { lit_uint(u64, uint_ty), lit_int_unsuffixed(i64), lit_float(@~str, float_ty), + lit_float_unsuffixed(@~str), lit_nil, lit_bool(bool), } @@ -880,6 +881,7 @@ impl ast::lit_: cmp::Eq { (lit_float(val_a, ty_a), lit_float(val_b, ty_b)) => { val_a == val_b && ty_a == ty_b } + (lit_float_unsuffixed(a), lit_float_unsuffixed(b)) => a == b, (lit_nil, lit_nil) => true, (lit_bool(a), lit_bool(b)) => a == b, (lit_str(_), _) => false, @@ -887,6 +889,7 @@ impl ast::lit_: cmp::Eq { (lit_uint(*), _) => false, (lit_int_unsuffixed(*), _) => false, (lit_float(*), _) => false, + (lit_float_unsuffixed(*), _) => false, (lit_nil, _) => false, (lit_bool(_), _) => false } @@ -1137,7 +1140,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/lexer.rs b/src/libsyntax/parse/lexer.rs index 8f57d733eb51f..482813f3fd02e 100644 --- a/src/libsyntax/parse/lexer.rs +++ b/src/libsyntax/parse/lexer.rs @@ -385,6 +385,8 @@ fn scan_number(c: char, rdr: string_reader) -> token::Token { } None => () } + + let mut is_machine_float = false; if rdr.curr == 'f' { bump(rdr); c = rdr.curr; @@ -404,10 +406,14 @@ fn scan_number(c: char, rdr: string_reader) -> token::Token { back-end. */ } else { is_float = true; + is_machine_float = true; } } if is_float { - return token::LIT_FLOAT(rdr.interner.intern(@num_str), ast::ty_f); + if is_machine_float { + return token::LIT_FLOAT(rdr.interner.intern(@num_str), ast::ty_f); + } + return token::LIT_FLOAT_UNSUFFIXED(rdr.interner.intern(@num_str)); } else { if str::len(num_str) == 0u { rdr.fatal(~"no valid digits found for number"); diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index db3f6abbf7b79..f1f49c63a7d69 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -43,9 +43,9 @@ use ast::{_mod, add, arg, arm, attribute, ident, impure_fn, infer, inherited, item, item_, item_class, item_const, item_enum, item_fn, item_foreign_mod, item_impl, item_mac, item_mod, item_trait, - item_ty, lit, lit_, lit_bool, lit_float, lit_int, - lit_int_unsuffixed, lit_nil, lit_str, lit_uint, local, m_const, - m_imm, m_mutbl, mac_, mac_aq, mac_ellipsis, mac_invoc, + item_ty, lit, lit_, lit_bool, lit_float, lit_float_unsuffixed, + lit_int, lit_int_unsuffixed, lit_nil, lit_str, lit_uint, local, + m_const, m_imm, m_mutbl, mac_, mac_aq, mac_ellipsis, mac_invoc, mac_invoc_tt, mac_var, matcher, match_nonterminal, match_seq, match_tok, method, mode, module_ns, mt, mul, mutability, named_field, neg, noreturn, not, pat, pat_box, pat_enum, @@ -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()}) } } @@ -785,6 +787,8 @@ impl Parser { token::LIT_UINT(u, ut) => lit_uint(u, ut), token::LIT_INT_UNSUFFIXED(i) => lit_int_unsuffixed(i), token::LIT_FLOAT(s, ft) => lit_float(self.id_to_str(s), ft), + token::LIT_FLOAT_UNSUFFIXED(s) => + lit_float_unsuffixed(self.id_to_str(s)), token::LIT_STR(s) => lit_str(self.id_to_str(s)), token::LPAREN => { self.expect(token::RPAREN); lit_nil }, _ => { self.unexpected_last(tok); } @@ -1042,7 +1046,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 +2712,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/parse/token.rs b/src/libsyntax/parse/token.rs index 0d139b101d8f3..baf963942e2b8 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -62,6 +62,7 @@ enum Token { LIT_UINT(u64, ast::uint_ty), LIT_INT_UNSUFFIXED(i64), LIT_FLOAT(ast::ident, ast::float_ty), + LIT_FLOAT_UNSUFFIXED(ast::ident), LIT_STR(ast::ident), /* Name components */ @@ -164,6 +165,13 @@ fn to_str(in: @ident_interner, t: Token) -> ~str { } body + ast_util::float_ty_to_str(t) } + LIT_FLOAT_UNSUFFIXED(s) => { + let mut body = *in.get(s); + if body.ends_with(~".") { + body = body + ~"0"; // `10.f` is not a float literal + } + body + } LIT_STR(s) => { ~"\"" + str::escape_default(*in.get(s)) + ~"\"" } /* Name components */ @@ -204,6 +212,7 @@ pure fn can_begin_expr(t: Token) -> bool { LIT_UINT(_, _) => true, LIT_INT_UNSUFFIXED(_) => true, LIT_FLOAT(_, _) => true, + LIT_FLOAT_UNSUFFIXED(_) => true, LIT_STR(_) => true, POUND => true, AT => true, @@ -243,6 +252,7 @@ fn is_lit(t: Token) -> bool { LIT_UINT(_, _) => true, LIT_INT_UNSUFFIXED(_) => true, LIT_FLOAT(_, _) => true, + LIT_FLOAT_UNSUFFIXED(_) => true, LIT_STR(_) => true, _ => false } @@ -684,6 +694,12 @@ impl Token : cmp::Eq { _ => false } } + LIT_FLOAT_UNSUFFIXED(e0a) => { + match (*other) { + LIT_FLOAT_UNSUFFIXED(e0b) => e0a == e0b, + _ => false + } + } LIT_STR(e0a) => { match (*other) { LIT_STR(e0b) => e0a == e0b, diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index ed64d02cea36e..54ed5085435d8 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); } @@ -1963,6 +1970,7 @@ fn print_literal(s: ps, &&lit: @ast::lit) { ast::lit_float(f, t) => { word(s.s, *f + ast_util::float_ty_to_str(t)); } + ast::lit_float_unsuffixed(f) => word(s.s, *f), ast::lit_nil => word(s.s, ~"()"), ast::lit_bool(val) => { if val { word(s.s, ~"true"); } else { word(s.s, ~"false"); } 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/float-literal-inference-restrictions.rs b/src/test/compile-fail/float-literal-inference-restrictions.rs new file mode 100644 index 0000000000000..e272b194fe1dc --- /dev/null +++ b/src/test/compile-fail/float-literal-inference-restrictions.rs @@ -0,0 +1,5 @@ +fn main() { + let x: f32 = 1; //~ ERROR mismatched types + let y: f32 = 1f; //~ ERROR mismatched types +} + 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/float-literal-inference.rs b/src/test/run-pass/float-literal-inference.rs new file mode 100644 index 0000000000000..f930537130c7d --- /dev/null +++ b/src/test/run-pass/float-literal-inference.rs @@ -0,0 +1,13 @@ +struct S { + z: f64 +} + +fn main() { + let x: f32 = 4.0; + io::println(x.to_str()); + let y: float = 64.0; + io::println(y.to_str()); + let z = S { z: 1.0 }; + io::println(z.z.to_str()); +} + 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 }); +} +