]> git.lizzy.rs Git - rust.git/commitdiff
Make resolve and the typechecker check for a main fn of the
authorTim Chevalier <chevalier@alum.wellesley.edu>
Thu, 14 Jul 2011 00:26:06 +0000 (17:26 -0700)
committerTim Chevalier <chevalier@alum.wellesley.edu>
Thu, 14 Jul 2011 01:30:53 +0000 (18:30 -0700)
correct type

This means if a non-library program leaves out the main program,
the error gets caught earlier than link.

Closes #626.

src/comp/driver/rustc.rs
src/comp/driver/session.rs
src/comp/middle/resolve.rs
src/comp/middle/trans.rs
src/comp/middle/typeck.rs
src/comp/util/common.rs
src/test/compile-fail/main-wrong-type-2.rs [new file with mode: 0644]
src/test/compile-fail/main-wrong-type.rs [new file with mode: 0644]
src/test/compile-fail/missing-main.rs [new file with mode: 0644]

index a8c9738eb4a14e5f699d14269d608ce9f1f29840..a6409209b75aa85dd101e23a40b632193ea8e7d2 100644 (file)
@@ -361,7 +361,7 @@ fn build_session(@session::options sopts) -> session::session {
     auto cstore = cstore::mk_cstore();
     ret session::session(target_cfg, sopts, cstore,
                          @rec(cm=codemap::new_codemap(), mutable next_id=0),
-                         0u);
+                         none, 0u);
 }
 
 fn parse_pretty(session::session sess, &str name) -> pp_mode {
index 8da3e40baa6c09def83b4fa3d1b7aae79ff2d533..4adcb7cee5f47d4ea51dedd71db57fcea78c4c23 100644 (file)
@@ -1,5 +1,6 @@
 
 import syntax::ast;
+import syntax::ast::node_id;
 import syntax::codemap;
 import codemap::span;
 import syntax::ast::ty_mach;
@@ -49,6 +50,8 @@
             @options opts,
             metadata::cstore::cstore cstore,
             parse_sess parse_sess,
+            // For a library crate, this is always none
+            mutable option::t[node_id] main_fn,
             mutable uint err_count) {
     fn get_targ_cfg() -> @config { ret targ_cfg; }
     fn get_opts() -> @options { ret opts; }
@@ -110,6 +113,10 @@ fn next_node_id() -> ast::node_id {
     fn span_str(span sp) -> str {
         ret codemap::span_to_str(sp, self.get_codemap());
     }
+    fn set_main_id(node_id d) {
+        main_fn = some(d);
+    }
+    fn get_main_id() -> option::t[node_id] { main_fn }
 }
 // Local Variables:
 // fill-column: 78;
index d312372ea55c6768decfdffb99f2b202b74578f0..d32e4b7f4e75361843296cddbf4ce4da22a1fdc8 100644 (file)
@@ -10,7 +10,7 @@
 import metadata::csearch;
 import metadata::cstore;
 import driver::session::session;
-import util::common::new_def_hash;
+import util::common::*;
 import std::map::new_int_hash;
 import std::map::new_str_hash;
 import syntax::codemap::span;
@@ -337,6 +337,18 @@ fn visit_native_item_with_scope(&@ast::native_item ni, &scopes sc,
 fn visit_fn_with_scope(&@env e, &ast::_fn f, &ast::ty_param[] tp, &span sp,
                        &fn_ident name, node_id id, &scopes sc,
                        &vt[scopes] v) {
+    // is this a main fn declaration?
+    alt (name) {
+        case (some(?nm)) {
+            if (is_main_name(~[nm]) && !e.sess.get_opts().library) {
+                // This is a main function -- set it in the session
+                // as the main ID
+                e.sess.set_main_id(id);
+            }
+        }
+        case (_) {}
+    }
+
     // here's where we need to set up the mapping
     // for f's constrs in the table.
 
index f5894ece83e7608946a0bd41a6c653d943009037..b80fccab0767c48a8f9c9cf145543b20f78f05c2 100644 (file)
 import syntax::visit;
 import visit::vt;
 import util::common;
-import util::common::new_def_hash;
+import util::common::*;
 import std::map::new_int_hash;
 import std::map::new_str_hash;
-import util::common::local_rhs_span;
 import syntax::codemap::span;
 import lib::llvm::llvm;
 import lib::llvm::builder;
@@ -8586,9 +8585,7 @@ fn decl_fn_and_pair_full(&@crate_ctxt ccx, &span sp, &str[] path, str flav,
             ccx.sess.bug("decl_fn_and_pair(): fn item doesn't have fn type!");
         }
     }
-    let bool is_main =
-        str::eq(option::get(std::ivec::last(path)), "main") &&
-                !ccx.sess.get_opts().library;
+    let bool is_main = is_main_name(path) && !ccx.sess.get_opts().library;
     // Declare the function itself.
 
     let str s =
index 29acb7d9e53cfb1bc224846174db74c3330f5e42..8d28e1e53a4d6886c7138e933060ab508047bc84 100644 (file)
@@ -1624,8 +1624,7 @@ fn check_pred_expr(&@fn_ctxt fcx, &@ast::expr e) {
                     alt (operator.node) {
                         case (ast::expr_path(?oper_name)) {
                             alt (fcx.ccx.tcx.def_map.find(operator.id)) {
-                                case (some(ast::def_fn(?_d_id,
-                                                       ast::pure_fn))) {
+                                case (some(ast::def_fn(_, ast::pure_fn))) {
                                     // do nothing
                                 }
                                 case (_) {
@@ -2655,6 +2654,54 @@ fn check_item(@crate_ctxt ccx, &@ast::item it) {
     }
 }
 
+fn arg_is_argv_ty(&ty::ctxt tcx, &ty::arg a) -> bool {
+    alt (ty::struct(tcx, a.ty)) {
+        case (ty::ty_vec(?mt)) {
+            if (mt.mut != ast::imm) { ret false; }
+            alt (ty::struct(tcx, mt.ty)) {
+                case (ty::ty_str) { ret true; }
+                case (_) { ret false; }
+            }
+        }
+        case (_) { ret false; }
+    }
+}
+
+fn check_main_fn_ty(&ty::ctxt tcx, &ast::node_id main_id) {
+    auto main_t = ty::node_id_to_monotype(tcx, main_id);
+    alt (ty::struct(tcx, main_t)) {
+        case (ty::ty_fn(ast::proto_fn, ?args, ?rs, ast::return, ?constrs)) {
+            auto ok = ivec::len(constrs) == 0u;
+            ok &= ty::type_is_nil(tcx, rs);
+            auto num_args = ivec::len(args);
+            ok &= num_args == 0u || (num_args == 1u &&
+                                     arg_is_argv_ty(tcx, args.(0)));
+            if (!ok) {
+                    tcx.sess.err("Wrong type in main function: found "
+                         + ty_to_str(tcx, main_t));
+            }
+        }
+        case (_) {
+            tcx.sess.err("Main has a non-function type: found"
+                         + ty_to_str(tcx, main_t));
+        }
+    }
+}
+
+fn check_for_main_fn(&ty::ctxt tcx, &@ast::crate crate) {
+    if (!tcx.sess.get_opts().library) {
+        alt (tcx.sess.get_main_id()) {
+            case (some(?id)) {
+                check_main_fn_ty(tcx, id);
+            }
+            case (none) {
+                tcx.sess.span_err(crate.span,
+                                  "Main function not found");
+            }
+        }
+    }
+}
+
 fn check_crate(&ty::ctxt tcx, &@ast::crate crate) {
     collect::collect_item_types(tcx, crate);
 
@@ -2666,6 +2713,7 @@ fn check_crate(&ty::ctxt tcx, &@ast::crate crate) {
         rec(visit_item_pre=bind check_item(ccx, _)
             with walk::default_visitor());
     walk::walk_crate(visit, *crate);
+    check_for_main_fn(tcx, crate);
     tcx.sess.abort_if_errors();
 }
 //
index d55c8bba3d5a915040d429585d0b743f3277cb08..3c8b6b7ca0986d798ebface7cf484f080219e8b5 100644 (file)
@@ -1,4 +1,4 @@
-
+import std::str;
 import std::map;
 import std::map::hashmap;
 import std::uint;
@@ -187,6 +187,9 @@ fn call_kind_str(call_kind c) -> str {
     }
 }
 
+fn is_main_name(&str[] path) -> bool {
+    str::eq(option::get(std::ivec::last(path)), "main")
+}
 //
 // Local Variables:
 // mode: rust
diff --git a/src/test/compile-fail/main-wrong-type-2.rs b/src/test/compile-fail/main-wrong-type-2.rs
new file mode 100644 (file)
index 0000000..50bf187
--- /dev/null
@@ -0,0 +1,4 @@
+// xfail-stage0
+// error-pattern:Wrong type in main function: found fn() -> char
+fn main() -> char {
+}
diff --git a/src/test/compile-fail/main-wrong-type.rs b/src/test/compile-fail/main-wrong-type.rs
new file mode 100644 (file)
index 0000000..4998867
--- /dev/null
@@ -0,0 +1,4 @@
+// xfail-stage0
+// error-pattern:Wrong type in main function: found fn(rec(int x
+fn main(rec(int x, int y) foo) {
+}
diff --git a/src/test/compile-fail/missing-main.rs b/src/test/compile-fail/missing-main.rs
new file mode 100644 (file)
index 0000000..6eed365
--- /dev/null
@@ -0,0 +1,4 @@
+// xfail-stage0
+// error-pattern:Main function not found
+fn mian() {
+}