about summary refs log tree commit diff
path: root/src/comp/middle
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 /src/comp/middle
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.
Diffstat (limited to 'src/comp/middle')
-rw-r--r--src/comp/middle/resolve.rs14
-rw-r--r--src/comp/middle/trans.rs7
-rw-r--r--src/comp/middle/typeck.rs52
3 files changed, 65 insertions, 8 deletions
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();
 }
 //