Started adding support for return checking and non-returning function annotations

* Reorganized typestate into several modules.

* Made typestate check that any function with a non-nil return type
  returns a value. For now, the check is a warning and not an error
  (see next item).

* Added a "bot" type (prettyprinted as _|_), for constructs like be, ret, break, cont, and
  fail that don't locally return a value that can be inspected. "bot"
  is distinct from "nil". There is no concrete syntax for _|_, while
  the concrete syntax for the nil type is ().

* Added support to the parser for a ! annotation on functions whose
  result type is _|_. Such a function is required to have either a
  fail or a call to another ! function that is reached in all control
  flow paths. The point of this annotation is to mark functions like
  unimpl() and span_err(), so that an alt with a call to err() in one
  case isn't a false positive for the return-value checker. I haven't
  actually annotated anything with it yet.

* Random bugfixes:

* * Fixed bug in trans::trans_binary that was throwing away the
    cleanups for nested subexpressions of an and or or
    (tests: box-inside-if and box-inside-if2).

** In typeck, unify the expected type arguments of a tag with the
   actual specified arguments.
This commit is contained in:
Tim Chevalier 2011-05-14 19:02:30 -07:00
parent c75125fcce
commit 971b5d5151
22 changed files with 3276 additions and 51 deletions

View file

@ -23,6 +23,11 @@ tag file_type {
SOURCE_FILE;
}
tag ty_or_bang {
a_ty(@ast::ty);
a_bang;
}
state type parser =
state obj {
fn peek() -> token::token;
@ -448,6 +453,13 @@ fn parse_ty_constrs(@ast::ty t, parser p) -> @ast::ty {
ret t;
}
fn parse_ty_or_bang(parser p) -> ty_or_bang {
alt (p.peek()) {
case (token::NOT) { p.bump(); ret a_bang; }
case (_) { ret a_ty(parse_ty(p)); }
}
}
fn parse_ty(parser p) -> @ast::ty {
auto lo = p.get_lo_pos();
auto hi = lo;
@ -1713,7 +1725,7 @@ fn parse_fn_decl(parser p, ast::purity purity) -> ast::fn_decl {
some(token::COMMA),
pf, p);
let @ast::ty output;
let ty_or_bang res;
// FIXME: dropping constrs on the floor at the moment.
// pick them up when they're used by typestate pass.
@ -1721,12 +1733,23 @@ fn parse_fn_decl(parser p, ast::purity purity) -> ast::fn_decl {
if (p.peek() == token::RARROW) {
p.bump();
output = parse_ty(p);
res = parse_ty_or_bang(p);
} else {
output = @spanned(inputs.span.lo, inputs.span.hi, ast::ty_nil);
res = a_ty(@spanned(inputs.span.lo, inputs.span.hi, ast::ty_nil));
}
alt (res) {
case (a_ty(?t)) {
ret rec(inputs=inputs.node, output=t,
purity=purity, cf=ast::return);
}
case (a_bang) {
ret rec(inputs=inputs.node,
output=@spanned(p.get_lo_pos(),
p.get_hi_pos(), ast::ty_bot),
purity=purity, cf=ast::noreturn);
}
}
// FIXME
ret rec(inputs=inputs.node, output=output, purity=purity);
}
fn parse_fn(parser p, ast::proto proto, ast::purity purity) -> ast::_fn {
@ -1778,11 +1801,12 @@ fn parse_dtor(parser p) -> @ast::method {
let vec[ast::arg] inputs = vec();
let @ast::ty output = @spanned(lo, lo, ast::ty_nil);
let ast::fn_decl d = rec(inputs=inputs,
output=output,
purity=ast::impure_fn);
output=output,
purity=ast::impure_fn,
cf=ast::return);
let ast::_fn f = rec(decl = d,
proto = ast::proto_fn,
body = b);
proto = ast::proto_fn,
body = b);
let ast::method_ m = rec(ident="drop",
meth=f,
id=p.next_def_id(),