From f26ca025dee246500552076cc650137e12c04464 Mon Sep 17 00:00:00 2001 From: Tim Chevalier Date: Wed, 13 Jul 2011 17:26:06 -0700 Subject: 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. --- src/comp/middle/resolve.rs | 14 ++++++++++++- src/comp/middle/trans.rs | 7 ++----- src/comp/middle/typeck.rs | 52 ++++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 65 insertions(+), 8 deletions(-) (limited to 'src/comp/middle') 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(); } // -- cgit 1.4.1-3-g733a5