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.
This commit is contained in:
Tim Chevalier 2011-07-13 17:26:06 -07:00
parent 196753e4c3
commit f26ca025de
9 changed files with 89 additions and 10 deletions

View 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 {

View 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 @@ 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;

View File

@ -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.

View File

@ -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 =

View File

@ -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();
}
//

View 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

View File

@ -0,0 +1,4 @@
// xfail-stage0
// error-pattern:Wrong type in main function: found fn() -> char
fn main() -> char {
}

View File

@ -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) {
}

View File

@ -0,0 +1,4 @@
// xfail-stage0
// error-pattern:Main function not found
fn mian() {
}