about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/libcore/vec.rs8
-rw-r--r--src/librustsyntax/parse/parser.rs15
-rw-r--r--src/librustsyntax/print/pprust.rs41
-rw-r--r--src/rustc/middle/typeck.rs174
-rw-r--r--src/rustc/util/ppaux.rs15
-rw-r--r--src/test/compile-fail/omitted-arg-in-item-fn.rs2
-rw-r--r--src/test/compile-fail/omitted-arg-wrong-types.rs9
-rw-r--r--src/test/compile-fail/pptypedef.rs8
-rw-r--r--src/test/compile-fail/vec-concat-bug.rs1
-rw-r--r--src/test/run-pass/omitted-arg-type.rs8
10 files changed, 178 insertions, 103 deletions
diff --git a/src/libcore/vec.rs b/src/libcore/vec.rs
index 3215f3b9f28..cddb1346c01 100644
--- a/src/libcore/vec.rs
+++ b/src/libcore/vec.rs
@@ -1096,6 +1096,14 @@ impl extensions<T> for [T] {
     #[inline]
     fn map<U>(f: fn(T) -> U) -> [U] { map(self, f) }
     #[doc = "
+    Apply a function to the index and value of each element in the vector
+    and return the results
+    "]
+    fn mapi<U>(f: fn(uint, T) -> U) -> [U] {
+        let mut i = 0u;
+        self.map { |e| i += 1u; f(i - 1u, e) }
+    }
+    #[doc = "
     Apply a function to each element of a vector and return a concatenation
     of each result vector
     "]
diff --git a/src/librustsyntax/parse/parser.rs b/src/librustsyntax/parse/parser.rs
index 0c681900dd5..7eb537d8cfe 100644
--- a/src/librustsyntax/parse/parser.rs
+++ b/src/librustsyntax/parse/parser.rs
@@ -1206,7 +1206,7 @@ fn parse_capture_clause(p: parser) -> @ast::capture_clause {
 fn parse_fn_expr(p: parser, proto: ast::proto) -> @ast::expr {
     let lo = p.last_span.lo;
     let capture_clause = parse_capture_clause(p);
-    let decl = parse_fn_decl(p, ast::impure_fn);
+    let decl = parse_fn_decl(p, ast::impure_fn, parse_fn_block_arg);
     let body = parse_block(p);
     ret mk_expr(p, lo, body.span.hi,
                 ast::expr_fn(proto, decl, body, capture_clause));
@@ -1699,11 +1699,12 @@ fn parse_ty_params(p: parser) -> [ast::ty_param] {
     } else { [] }
 }
 
-fn parse_fn_decl(p: parser, purity: ast::purity)
+fn parse_fn_decl(p: parser, purity: ast::purity,
+                 parse_arg_fn: fn(parser) -> ast::arg)
     -> ast::fn_decl {
     let inputs: ast::spanned<[ast::arg]> =
         parse_seq(token::LPAREN, token::RPAREN, seq_sep(token::COMMA),
-                  parse_arg, p);
+                  parse_arg_fn, p);
     // Use the args list to translate each bound variable
     // mentioned in a constraint to an arg index.
     // Seems weird to do this in the parser, but I'm not sure how else to.
@@ -1760,7 +1761,7 @@ fn parse_item_fn(p: parser, purity: ast::purity,
                  attrs: [ast::attribute]) -> @ast::item {
     let lo = p.last_span.lo;
     let t = parse_fn_header(p);
-    let decl = parse_fn_decl(p, purity);
+    let decl = parse_fn_decl(p, purity, parse_arg);
     let (inner_attrs, body) = parse_inner_attrs_and_block(p, true);
     let attrs = attrs + inner_attrs;
     ret mk_item(p, lo, body.span.hi, t.ident,
@@ -1785,7 +1786,7 @@ fn parse_method(p: parser, pr: ast::privacy) -> @ast::method {
     let lo = p.span.lo, pur = parse_fn_purity(p);
     let ident = parse_method_name(p);
     let tps = parse_ty_params(p);
-    let decl = parse_fn_decl(p, pur);
+    let decl = parse_fn_decl(p, pur, parse_arg);
     let (inner_attrs, body) = parse_inner_attrs_and_block(p, true);
     let attrs = attrs + inner_attrs;
     @{ident: ident, attrs: attrs, tps: tps, decl: decl, body: body,
@@ -1969,7 +1970,7 @@ fn parse_class_item(p:parser, class_name_with_tps: @ast::path)
         let lo = p.last_span.lo;
         // Can ctors have attrs?
             // result type is always the type of the class
-        let decl_ = parse_fn_decl(p, ast::impure_fn);
+        let decl_ = parse_fn_decl(p, ast::impure_fn, parse_arg);
         let decl = {output: @{id: p.get_id(),
                       node: ast::ty_path(class_name_with_tps, p.get_id()),
                       span: decl_.output.span}
@@ -2048,7 +2049,7 @@ fn parse_item_native_fn(p: parser, attrs: [ast::attribute],
                         purity: ast::purity) -> @ast::native_item {
     let lo = p.last_span.lo;
     let t = parse_fn_header(p);
-    let decl = parse_fn_decl(p, purity);
+    let decl = parse_fn_decl(p, purity, parse_arg);
     let mut hi = p.span.hi;
     expect(p, token::SEMI);
     ret @{ident: t.ident,
diff --git a/src/librustsyntax/print/pprust.rs b/src/librustsyntax/print/pprust.rs
index b50f4f341a7..c6417ab01f4 100644
--- a/src/librustsyntax/print/pprust.rs
+++ b/src/librustsyntax/print/pprust.rs
@@ -1351,13 +1351,6 @@ fn print_cap_clause(s: ps, cap_clause: ast::capture_clause) {
 
 fn print_fn_args_and_ret(s: ps, decl: ast::fn_decl) {
     popen(s);
-    fn print_arg(s: ps, x: ast::arg) {
-        ibox(s, indent_unit);
-        print_arg_mode(s, x.mode);
-        word_space(s, x.ident + ":");
-        print_type(s, x.ty);
-        end(s);
-    }
     commasep(s, inconsistent, decl.inputs, print_arg);
     pclose(s);
     word(s.s, constrs_str(decl.constraints, {|c|
@@ -1374,16 +1367,6 @@ fn print_fn_args_and_ret(s: ps, decl: ast::fn_decl) {
 
 fn print_fn_block_args(s: ps, decl: ast::fn_decl) {
     word(s.s, "|");
-    fn print_arg(s: ps, x: ast::arg) {
-        ibox(s, indent_unit);
-        print_arg_mode(s, x.mode);
-        word(s.s, x.ident);
-        if x.ty.node != ast::ty_infer {
-            word_space(s, ":");
-            print_type(s, x.ty);
-        }
-        end(s);
-    }
     commasep(s, inconsistent, decl.inputs, print_arg);
     word(s.s, "|");
     if decl.output.node != ast::ty_infer {
@@ -1541,6 +1524,23 @@ fn print_mt(s: ps, mt: ast::mt) {
     print_type(s, mt.ty);
 }
 
+fn print_arg(s: ps, input: ast::arg) {
+    ibox(s, indent_unit);
+    print_arg_mode(s, input.mode);
+    alt input.ty.node {
+      ast::ty_infer {
+        word(s.s, input.ident);
+      }
+      _ {
+        if str::len(input.ident) > 0u {
+            word_space(s, input.ident + ":");
+        }
+        print_type(s, input.ty);
+      }
+    }
+    end(s);
+}
+
 fn print_ty_fn(s: ps, opt_proto: option<ast::proto>,
                decl: ast::fn_decl, id: option<ast::ident>,
                tps: option<[ast::ty_param]>) {
@@ -1550,13 +1550,6 @@ fn print_ty_fn(s: ps, opt_proto: option<ast::proto>,
     alt tps { some(tps) { print_type_params(s, tps); } _ { } }
     zerobreak(s.s);
     popen(s);
-    fn print_arg(s: ps, input: ast::arg) {
-        print_arg_mode(s, input.mode);
-        if str::len(input.ident) > 0u {
-            word_space(s, input.ident + ":");
-        }
-        print_type(s, input.ty);
-    }
     commasep(s, inconsistent, decl.inputs, print_arg);
     pclose(s);
     maybe_print_comment(s, decl.output.span.lo);
diff --git a/src/rustc/middle/typeck.rs b/src/rustc/middle/typeck.rs
index d8db45d8919..5ca8ac04342 100644
--- a/src/rustc/middle/typeck.rs
+++ b/src/rustc/middle/typeck.rs
@@ -275,7 +275,8 @@ fn instantiate_path(fcx: @fn_ctxt,
     fcx.write_ty_substs(id, tpt.ty, substs);
 }
 
-// Type tests
+// Resolves `typ` by a single level if `typ` is a type variable.  If no
+// resolution is possible, then an error is reported.
 fn structurally_resolved_type(fcx: @fn_ctxt, sp: span, tp: ty::t) -> ty::t {
     alt infer::resolve_shallow(fcx.infcx, tp, false) {
       result::ok(t_s) if !ty::type_is_var(t_s) { ret t_s; }
@@ -286,7 +287,6 @@ fn structurally_resolved_type(fcx: @fn_ctxt, sp: span, tp: ty::t) -> ty::t {
     }
 }
 
-
 // Returns the one-level-deep structure of the given type.
 fn structure_of(fcx: @fn_ctxt, sp: span, typ: ty::t) -> ty::sty {
     ty::get(structurally_resolved_type(fcx, sp, typ)).struct
@@ -689,7 +689,7 @@ fn ast_ty_to_ty<AC: ast_conv, RS: region_scope copy>(
         ty::mk_rec(tcx, flds)
       }
       ast::ty_fn(proto, decl) {
-        ty::mk_fn(tcx, ty_of_fn_decl(self, rscope, proto, decl))
+        ty::mk_fn(tcx, ty_of_fn_decl(self, rscope, proto, decl, none))
       }
       ast::ty_path(path, id) {
         let a_def = alt tcx.def_map.find(id) {
@@ -777,7 +777,13 @@ fn ast_ty_to_ty<AC: ast_conv, RS: region_scope copy>(
         ty::mk_constr(tcx, ast_ty_to_ty(self, rscope, t), out_cs)
       }
       ast::ty_infer {
-        self.ty_infer(ast_ty.span)
+        // ty_infer should only appear as the type of arguments or return
+        // values in a fn_expr, or as the type of local variables.  Both of
+        // these cases are handled specially and should not descend into this
+        // routine.
+        self.tcx().sess.span_bug(
+            ast_ty.span,
+            "found `ty_infer` in unexpected place");
       }
       ast::ty_mac(_) {
         tcx.sess.span_bug(ast_ty.span,
@@ -850,7 +856,8 @@ fn ty_of_item(ccx: @crate_ctxt, it: @ast::item)
       }
       ast::item_fn(decl, tps, _) {
         let bounds = ty_param_bounds(ccx, tps);
-        let tofd = ty_of_fn_decl(ccx, empty_rscope, ast::proto_bare, decl);
+        let tofd = ty_of_fn_decl(ccx, empty_rscope, ast::proto_bare,
+                                 decl, none);
         let tpt = {bounds: bounds,
                    rp: ast::rp_none, // functions do not have a self
                    ty: ty::mk_fn(ccx.tcx, tofd)};
@@ -884,7 +891,8 @@ fn ty_of_item(ccx: @crate_ctxt, it: @ast::item)
       }
       ast::item_res(decl, tps, _, _, _, rp) {
         let {bounds, substs} = mk_substs(ccx, tps, rp);
-        let t_arg = ty_of_arg(ccx, type_rscope(rp), decl.inputs[0]);
+        let t_arg = ty_of_arg(ccx, type_rscope(rp),
+                              decl.inputs[0], none);
         let t = ty::mk_res(tcx, local_def(it.id), t_arg.ty, substs);
         let t_res = {bounds: bounds, rp: rp, ty: t};
         tcx.tcache.insert(local_def(it.id), t_res);
@@ -1027,16 +1035,27 @@ fn replace_bound_regions(
 }
 
 fn ty_of_arg<AC: ast_conv, RS: region_scope copy>(
-    self: AC, rscope: RS, a: ast::arg) -> ty::arg {
+    self: AC, rscope: RS, a: ast::arg,
+    expected_ty: option<ty::arg>) -> ty::arg {
+
+    let ty = alt a.ty.node {
+      ast::ty_infer if expected_ty.is_some() {expected_ty.get().ty}
+      ast::ty_infer {self.ty_infer(a.ty.span)}
+      _ {ast_ty_to_ty(self, rscope, a.ty)}
+    };
 
-    fn arg_mode(tcx: ty::ctxt, m: ast::mode, ty: ty::t) -> ast::mode {
-        alt m {
+    let mode = {
+        alt a.mode {
+          ast::infer(_) if expected_ty.is_some() {
+            result::get(ty::unify_mode(self.tcx(), a.mode,
+                                       expected_ty.get().mode))
+          }
           ast::infer(_) {
             alt ty::get(ty).struct {
               // If the type is not specified, then this must be a fn expr.
               // Leave the mode as infer(_), it will get inferred based
               // on constraints elsewhere.
-              ty::ty_var(_) { m }
+              ty::ty_var(_) {a.mode}
 
               // If the type is known, then use the default for that type.
               // Here we unify m and the default.  This should update the
@@ -1044,30 +1063,48 @@ fn ty_of_arg<AC: ast_conv, RS: region_scope copy>(
               // will have been unified with m yet:
               _ {
                 let m1 = ast::expl(ty::default_arg_mode_for_ty(ty));
-                result::get(ty::unify_mode(tcx, m, m1))
+                result::get(ty::unify_mode(self.tcx(), a.mode, m1))
               }
             }
           }
-          ast::expl(_) { m }
+          ast::expl(_) {a.mode}
         }
-    }
+    };
 
-    let ty = ast_ty_to_ty(self, rscope, a.ty);
-    let mode = arg_mode(self.tcx(), a.mode, ty);
     {mode: mode, ty: ty}
 }
+
+type expected_tys = option<{inputs: [ty::arg],
+                            output: ty::t}>;
+
 fn ty_of_fn_decl<AC: ast_conv, RS: region_scope copy>(
     self: AC, rscope: RS,
     proto: ast::proto,
-    decl: ast::fn_decl) -> ty::fn_ty {
+    decl: ast::fn_decl,
+    expected_tys: expected_tys) -> ty::fn_ty {
 
     #debug["ty_of_fn_decl"];
     indent {||
         // new region names that appear inside of the fn decl are bound to
         // that function type
         let rb = in_binding_rscope(rscope);
-        let input_tys = vec::map(decl.inputs) { |a| ty_of_arg(self, rb, a) };
-        let output_ty = ast_ty_to_ty(self, rb, decl.output);
+
+        let input_tys = decl.inputs.mapi { |i, a|
+            let expected_arg_ty = expected_tys.chain { |e|
+                // no guarantee that the correct number of expected args
+                // were supplied
+                if i < e.inputs.len() {some(e.inputs[i])} else {none}
+            };
+            ty_of_arg(self, rb, a, expected_arg_ty)
+        };
+
+        let expected_ret_ty = expected_tys.map { |e| e.output };
+        let output_ty = alt decl.output.node {
+          ast::ty_infer if expected_ret_ty.is_some() {expected_ret_ty.get()}
+          ast::ty_infer {self.ty_infer(decl.output.span)}
+          _ {ast_ty_to_ty(self, rb, decl.output)}
+        };
+
         let out_constrs = vec::map(decl.constraints) {|constr|
             ty::ast_constr_to_constr(self.tcx(), constr)
         };
@@ -1083,7 +1120,7 @@ fn ty_of_native_fn_decl(ccx: @crate_ctxt,
 
     let bounds = ty_param_bounds(ccx, ty_params);
     let rb = in_binding_rscope(empty_rscope);
-    let input_tys = vec::map(decl.inputs) { |a| ty_of_arg(ccx, rb, a) };
+    let input_tys = decl.inputs.map { |a| ty_of_arg(ccx, rb, a, none) };
     let output_ty = ast_ty_to_ty(ccx, rb, decl.output);
 
     let t_fn = ty::mk_fn(ccx.tcx, {proto: ast::proto_bare,
@@ -1135,7 +1172,8 @@ fn ty_of_method(ccx: @crate_ctxt,
                 rp: ast::region_param) -> ty::method {
     {ident: m.ident,
      tps: ty_param_bounds(ccx, m.tps),
-     fty: ty_of_fn_decl(ccx, type_rscope(rp), ast::proto_bare, m.decl),
+     fty: ty_of_fn_decl(ccx, type_rscope(rp), ast::proto_bare,
+                        m.decl, none),
      purity: m.decl.purity,
      privacy: m.privacy}
 }
@@ -1145,7 +1183,8 @@ fn ty_of_ty_method(self: @crate_ctxt,
                    rp: ast::region_param) -> ty::method {
     {ident: m.ident,
      tps: ty_param_bounds(self, m.tps),
-     fty: ty_of_fn_decl(self, type_rscope(rp), ast::proto_bare, m.decl),
+     fty: ty_of_fn_decl(self, type_rscope(rp), ast::proto_bare,
+                        m.decl, none),
      // assume public, because this is only invoked on iface methods
      purity: m.decl.purity, privacy: ast::pub}
 }
@@ -1649,7 +1688,8 @@ mod collect {
           ast::item_res(decl, tps, _, dtor_id, ctor_id, rp) {
             let {bounds, substs} = mk_substs(ccx, tps, rp);
             let def_id = local_def(it.id);
-            let t_arg = ty_of_arg(ccx, type_rscope(rp), decl.inputs[0]);
+            let t_arg = ty_of_arg(ccx, type_rscope(rp),
+                                  decl.inputs[0], none);
             let t_res = ty::mk_res(tcx, def_id, t_arg.ty, substs);
 
             let t_ctor = ty::mk_fn(tcx, {
@@ -1691,7 +1731,8 @@ mod collect {
                           ty_of_fn_decl(ccx,
                                         empty_rscope,
                                         ast::proto_any,
-                                        ctor.node.dec));
+                                        ctor.node.dec,
+                                        none));
             write_ty_to_tcx(tcx, ctor.node.id, t_ctor);
             tcx.tcache.insert(local_def(ctor.node.id),
                               {bounds: tpt.bounds,
@@ -2902,35 +2943,6 @@ fn region_of(fcx: @fn_ctxt, expr: @ast::expr) -> ty::region {
     }
 }
 
-fn check_expr_fn_with_unifier(fcx: @fn_ctxt,
-                              expr: @ast::expr,
-                              proto: ast::proto,
-                              decl: ast::fn_decl,
-                              body: ast::blk,
-                              is_loop_body: bool,
-                              unifier: fn()) {
-    let tcx = fcx.ccx.tcx;
-    let fty = ty::mk_fn(tcx, ty_of_fn_decl(fcx, fcx, proto, decl));
-
-    #debug("check_expr_fn_with_unifier %s fty=%s",
-           expr_to_str(expr), fcx.ty_to_str(fty));
-
-    fcx.write_ty(expr.id, fty);
-
-    // Unify the type of the function with the expected type before we
-    // typecheck the body so that we have more information about the
-    // argument types in the body. This is needed to make binops and
-    // record projection work on type inferred arguments.
-    unifier();
-
-    let ret_ty = ty::ty_fn_ret(fty);
-    let arg_tys = vec::map(ty::ty_fn_args(fty)) {|a| a.ty };
-
-    check_fn(fcx.ccx, proto, decl, body, expr.id,
-             ret_ty, arg_tys, is_loop_body, some(fcx),
-             fcx.self_ty);
-}
-
 fn check_expr_with_unifier(fcx: @fn_ctxt,
                            expr: @ast::expr,
                            expected: option<ty::t>,
@@ -3227,6 +3239,11 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
           }
         }
     }
+
+    // Resolves `expected` by a single level if it is a variable and passes it
+    // through the `unpack` function.  It there is no expected type or
+    // resolution is not possible (e.g., no constraints yet present), just
+    // returns `none`.
     fn unpack_expected<O: copy>(fcx: @fn_ctxt, expected: option<ty::t>,
                                 unpack: fn(ty::sty) -> option<O>)
         -> option<O> {
@@ -3241,6 +3258,42 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
         }
     }
 
+    fn check_expr_fn(fcx: @fn_ctxt,
+                     expr: @ast::expr,
+                     proto: ast::proto,
+                     decl: ast::fn_decl,
+                     body: ast::blk,
+                     is_loop_body: bool,
+                     expected: option<ty::t>) {
+        let tcx = fcx.ccx.tcx;
+
+        let expected_tys = unpack_expected(fcx, expected) { |sty|
+            alt sty {
+              ty::ty_fn(fn_ty) {some({inputs:fn_ty.inputs,
+                                      output:fn_ty.output})}
+              _ {none}
+            }
+        };
+
+        // construct the function type
+        let fty = ty::mk_fn(tcx,
+                            ty_of_fn_decl(fcx, fcx, proto, decl,
+                                          expected_tys));
+
+        #debug("check_expr_fn_with_unifier %s fty=%s",
+               expr_to_str(expr), fcx.ty_to_str(fty));
+
+        fcx.write_ty(expr.id, fty);
+
+        let ret_ty = ty::ty_fn_ret(fty);
+        let arg_tys = vec::map(ty::ty_fn_args(fty)) {|a| a.ty };
+
+        check_fn(fcx.ccx, proto, decl, body, expr.id,
+                 ret_ty, arg_tys, is_loop_body, some(fcx),
+                 fcx.self_ty);
+    }
+
+
     let tcx = fcx.ccx.tcx;
     let id = expr.id;
     let mut bot = false;
@@ -3511,8 +3564,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
         fcx.write_ty(id, result_ty);
       }
       ast::expr_fn(proto, decl, body, captures) {
-        check_expr_fn_with_unifier(fcx, expr, proto, decl, body,
-                                   false, unifier);
+        check_expr_fn(fcx, expr, proto, decl, body, false, expected);
         capture::check_capture_clause(tcx, expr.id, proto, *captures);
       }
       ast::expr_fn_block(decl, body) {
@@ -3520,10 +3572,15 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
         let proto = unpack_expected(fcx, expected, {|sty|
             alt sty { ty::ty_fn({proto, _}) { some(proto) } _ { none } }
         }).get_default(ast::proto_box);
-        check_expr_fn_with_unifier(fcx, expr, proto, decl, body,
-                                   false, unifier);
+        check_expr_fn(fcx, expr, proto, decl, body, false, expected);
       }
       ast::expr_loop_body(b) {
+        // a loop body is the special argument to a `for` loop.  We know that
+        // there will be an expected type in this context because it can only
+        // appear in the context of a call, so we get the expected type of the
+        // parameter. The catch here is that we need to validate two things:
+        // 1. a closure that returns a bool is expected
+        // 2. the cloure that was given returns unit
         let expected_sty = unpack_expected(fcx, expected, {|x|some(x)}).get();
         let (inner_ty, proto) = alt expected_sty {
           ty::ty_fn(fty) {
@@ -3545,9 +3602,8 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
         };
         alt check b.node {
           ast::expr_fn_block(decl, body) {
-            check_expr_fn_with_unifier(fcx, b, proto, decl, body, true) {||
-                demand::suptype(fcx, b.span, inner_ty, fcx.expr_ty(b));
-            }
+            check_expr_fn(fcx, b, proto, decl, body, true, some(inner_ty));
+            demand::suptype(fcx, b.span, inner_ty, fcx.expr_ty(b));
           }
         }
         let block_ty = structurally_resolved_type(
diff --git a/src/rustc/util/ppaux.rs b/src/rustc/util/ppaux.rs
index 227dc0c8645..80af3229bc4 100644
--- a/src/rustc/util/ppaux.rs
+++ b/src/rustc/util/ppaux.rs
@@ -130,18 +130,9 @@ fn ty_to_str(cx: ctxt, typ: t) -> str {
     }
 
     // if there is an id, print that instead of the structural type:
-    alt ty::type_def_id(typ) {
-      some(def_id) {
-        let cs = ast_map::path_to_str(ty::item_path(cx, def_id));
-        ret alt ty::get(typ).struct {
-          ty_enum(_, substs) | ty_res(_, _, substs) | ty_class(_, substs) |
-          ty_iface(_, substs) {
-            parameterized(cx, cs, substs.self_r, substs.tps)
-          }
-          _ { cs }
-        };
-      }
-      none { /* fallthrough */}
+    for ty::type_def_id(typ).each { |def_id|
+        // note that this typedef cannot have type parameters
+        ret ast_map::path_to_str(ty::item_path(cx, def_id));
     }
 
     // pretty print the structural type representation:
diff --git a/src/test/compile-fail/omitted-arg-in-item-fn.rs b/src/test/compile-fail/omitted-arg-in-item-fn.rs
new file mode 100644
index 00000000000..8478a925eb6
--- /dev/null
+++ b/src/test/compile-fail/omitted-arg-in-item-fn.rs
@@ -0,0 +1,2 @@
+fn foo(x) { //! ERROR expecting ':' but found ')'
+}
\ No newline at end of file
diff --git a/src/test/compile-fail/omitted-arg-wrong-types.rs b/src/test/compile-fail/omitted-arg-wrong-types.rs
new file mode 100644
index 00000000000..604fed1bc61
--- /dev/null
+++ b/src/test/compile-fail/omitted-arg-wrong-types.rs
@@ -0,0 +1,9 @@
+fn let_in<T>(x: T, f: fn(T)) {}
+
+fn main() {
+    let_in(3u, fn&(i) { assert i == 3; });
+    //!^ ERROR expected `uint` but found `int`
+
+    let_in(3, fn&(i) { assert i == 3u; });
+    //!^ ERROR expected `int` but found `uint`
+}
\ No newline at end of file
diff --git a/src/test/compile-fail/pptypedef.rs b/src/test/compile-fail/pptypedef.rs
new file mode 100644
index 00000000000..941535ef0f1
--- /dev/null
+++ b/src/test/compile-fail/pptypedef.rs
@@ -0,0 +1,8 @@
+type foo = option<int>;
+
+fn bar(_t: foo) {}
+
+fn main() {
+    // we used to print foo<int>:
+    bar(some(3u)); //! ERROR mismatched types: expected `foo`
+}
\ No newline at end of file
diff --git a/src/test/compile-fail/vec-concat-bug.rs b/src/test/compile-fail/vec-concat-bug.rs
index b75623d6233..510bef1cae0 100644
--- a/src/test/compile-fail/vec-concat-bug.rs
+++ b/src/test/compile-fail/vec-concat-bug.rs
@@ -4,7 +4,6 @@ fn concat<T: copy>(v: [const [const T]]) -> [T] {
     // Earlier versions of our type checker accepted this:
     vec::iter(v) {|&&inner: [T]|
         //!^ ERROR values differ in mutability
-        //!^^ ERROR values differ in mutability
         r += inner;
     }
 
diff --git a/src/test/run-pass/omitted-arg-type.rs b/src/test/run-pass/omitted-arg-type.rs
new file mode 100644
index 00000000000..3ae04461bcd
--- /dev/null
+++ b/src/test/run-pass/omitted-arg-type.rs
@@ -0,0 +1,8 @@
+fn let_in<T>(x: T, f: fn(T)) {}
+
+fn main() {
+    let_in(3u) { |i| assert i == 3u; };
+    let_in(3) { |i| assert i == 3; };
+    let_in(3u, fn&(i) { assert i == 3u; });
+    let_in(3, fn&(i) { assert i == 3; });
+}
\ No newline at end of file