about summary refs log tree commit diff
diff options
context:
space:
mode:
authorTim Chevalier <chevalier@alum.wellesley.edu>2011-07-13 17:26:06 -0700
committerTim Chevalier <chevalier@alum.wellesley.edu>2011-07-13 18:30:53 -0700
commitf26ca025dee246500552076cc650137e12c04464 (patch)
tree9a48b4b129b4f4293f352934ab6f4a8329c05387
parent196753e4c3a4848ce92a84c596c385dc00f66578 (diff)
downloadrust-f26ca025dee246500552076cc650137e12c04464.tar.gz
rust-f26ca025dee246500552076cc650137e12c04464.zip
Make resolve and the typechecker check for a main fn of the
correct type

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

Closes #626.
-rw-r--r--src/comp/driver/rustc.rs2
-rw-r--r--src/comp/driver/session.rs7
-rw-r--r--src/comp/middle/resolve.rs14
-rw-r--r--src/comp/middle/trans.rs7
-rw-r--r--src/comp/middle/typeck.rs52
-rw-r--r--src/comp/util/common.rs5
-rw-r--r--src/test/compile-fail/main-wrong-type-2.rs4
-rw-r--r--src/test/compile-fail/main-wrong-type.rs4
-rw-r--r--src/test/compile-fail/missing-main.rs4
9 files changed, 89 insertions, 10 deletions
diff --git a/src/comp/driver/rustc.rs b/src/comp/driver/rustc.rs
index a8c9738eb4a..a6409209b75 100644
--- a/src/comp/driver/rustc.rs
+++ b/src/comp/driver/rustc.rs
@@ -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 {
diff --git a/src/comp/driver/session.rs b/src/comp/driver/session.rs
index 8da3e40baa6..4adcb7cee5f 100644
--- a/src/comp/driver/session.rs
+++ b/src/comp/driver/session.rs
@@ -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 @@ obj session(@config targ_cfg,
             @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 @@ obj session(@config targ_cfg,
     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;
diff --git a/src/comp/middle/resolve.rs b/src/comp/middle/resolve.rs
index d312372ea55..d32e4b7f4e7 100644
--- a/src/comp/middle/resolve.rs
+++ b/src/comp/middle/resolve.rs
@@ -10,7 +10,7 @@ import ast::local_def;
 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.
 
diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs
index f5894ece83e..b80fccab076 100644
--- a/src/comp/middle/trans.rs
+++ b/src/comp/middle/trans.rs
@@ -33,10 +33,9 @@ import back::upcall;
 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 =
diff --git a/src/comp/middle/typeck.rs b/src/comp/middle/typeck.rs
index 29acb7d9e53..8d28e1e53a4 100644
--- a/src/comp/middle/typeck.rs
+++ b/src/comp/middle/typeck.rs
@@ -1624,8 +1624,7 @@ fn check_expr(&@fn_ctxt fcx, &@ast::expr expr) {
                     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();
 }
 //
diff --git a/src/comp/util/common.rs b/src/comp/util/common.rs
index d55c8bba3d5..3c8b6b7ca09 100644
--- a/src/comp/util/common.rs
+++ b/src/comp/util/common.rs
@@ -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
index 00000000000..50bf187284f
--- /dev/null
+++ b/src/test/compile-fail/main-wrong-type-2.rs
@@ -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
index 00000000000..4998867e6b2
--- /dev/null
+++ b/src/test/compile-fail/main-wrong-type.rs
@@ -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
index 00000000000..6eed36591bf
--- /dev/null
+++ b/src/test/compile-fail/missing-main.rs
@@ -0,0 +1,4 @@
+// xfail-stage0
+// error-pattern:Main function not found
+fn mian() {
+}