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:
parent
196753e4c3
commit
f26ca025de
@ -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 {
|
||||
|
@ -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;
|
||||
|
@ -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.
|
||||
|
||||
|
@ -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 =
|
||||
|
@ -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();
|
||||
}
|
||||
//
|
||||
|
@ -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
|
||||
|
4
src/test/compile-fail/main-wrong-type-2.rs
Normal file
4
src/test/compile-fail/main-wrong-type-2.rs
Normal file
@ -0,0 +1,4 @@
|
||||
// xfail-stage0
|
||||
// error-pattern:Wrong type in main function: found fn() -> char
|
||||
fn main() -> char {
|
||||
}
|
4
src/test/compile-fail/main-wrong-type.rs
Normal file
4
src/test/compile-fail/main-wrong-type.rs
Normal 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) {
|
||||
}
|
4
src/test/compile-fail/missing-main.rs
Normal file
4
src/test/compile-fail/missing-main.rs
Normal file
@ -0,0 +1,4 @@
|
||||
// xfail-stage0
|
||||
// error-pattern:Main function not found
|
||||
fn mian() {
|
||||
}
|
Loading…
Reference in New Issue
Block a user