Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

first half of fix for #1215 #1248

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 8 additions & 3 deletions doc/rust.texi
Original file line number Diff line number Diff line change
Expand Up @@ -2954,9 +2954,8 @@ analogous to a @code{become} expression in Newsqueak or Alef.} destroys the
current function activation frame and replaces it with an activation frame for
the called function. In other words, @code{be} executes a tail-call. The
syntactic form of a @code{be} expression is therefore limited to @emph{tail
position}: its argument must be a @emph{call expression}, and it must be the
last expression in a block.

position}: its argument must be a @emph{call expression} or a @{trivial cast}
of a @emph{call expression}, and it must be the last expression in a block.
An example of a @code{be} expression:
@example
fn print_loop(n: int) @{
Expand All @@ -2971,6 +2970,7 @@ fn print_loop(n: int) @{

The above example executes in constant space, replacing each frame with a new
copy of itself.

@end ignore


Expand Down Expand Up @@ -3001,6 +3001,7 @@ execution and destroying the iterator frame.
@cindex As expression
@cindex Cast
@cindex Typecast
@cindex Trivial cast

Executing an @code{as} expression casts the value on the left-hand side to the
type on the right-hand side.
Expand All @@ -3018,6 +3019,10 @@ fn avg(v: [float]) -> float @{
@}
@end example

A cast is a @emph{trivial cast} iff the type of the casted expression and the
target type are identical after replacing all occurences of @code{int},
@code{uint}, @code{float} with their machine type equivalents of the
target architecture in both types.

@node Ref.Expr.Fail
@subsection Ref.Expr.Fail
Expand Down
1 change: 1 addition & 0 deletions src/comp/middle/check_const.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ fn check_item(tcx: ty::ctxt, it: @item, &&s: (), v: visit::vt<()>) {
fn check_const_expr(tcx: ty::ctxt, ex: @expr, &&s: (), v: visit::vt<()>) {
visit::visit_expr(ex, s, v);
alt ex.node {
expr_cast(_, _) { }
expr_lit(_) { }
expr_binary(_, _, _) { /* subexps covered by visit */ }
expr_unary(u, _) {
Expand Down
22 changes: 19 additions & 3 deletions src/comp/middle/trans.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4086,7 +4086,12 @@ fn trans_expr(bcx: @block_ctxt, e: @ast::expr, dest: dest) -> @block_ctxt {
if !ty::expr_is_lval(tcx, a) { ret trans_expr(bcx, a, dest); }
else { ret lval_to_dps(bcx, a, dest); }
}
ast::expr_cast(val, _) { ret trans_cast(bcx, val, e.id, dest); }
ast::expr_cast(val, _) {
alt tcx.cast_map.find(e.id) {
some(ty::triv_cast.) { ret trans_expr(bcx, val, dest); }
_ { ret trans_cast(bcx, val, e.id, dest); }
}
}
ast::expr_anon_obj(anon_obj) {
ret trans_anon_obj(bcx, e.span, anon_obj, e.id, dest);
}
Expand Down Expand Up @@ -4115,7 +4120,7 @@ fn trans_expr(bcx: @block_ctxt, e: @ast::expr, dest: dest) -> @block_ctxt {
// that is_call_expr(ex) -- but we don't support that
// yet
// FIXME
check (ast_util::is_call_expr(ex));
check (ast_util::is_tail_call_expr(ex));
ret trans_be(bcx, ex);
}
ast::expr_fail(expr) {
Expand Down Expand Up @@ -4448,7 +4453,8 @@ fn trans_ret(bcx: @block_ctxt, e: option::t<@ast::expr>) -> @block_ctxt {
fn build_return(bcx: @block_ctxt) { Br(bcx, bcx_fcx(bcx).llreturn); }

// fn trans_be(cx: &@block_ctxt, e: &@ast::expr) -> result {
fn trans_be(cx: @block_ctxt, e: @ast::expr) : ast_util::is_call_expr(e) ->
fn trans_be(cx: @block_ctxt, e: @ast::expr) :
ast_util::is_tail_call_expr(e) ->
@block_ctxt {
// FIXME: Turn this into a real tail call once
// calling convention issues are settled
Expand Down Expand Up @@ -5178,6 +5184,16 @@ fn trans_tag_variant(cx: @local_ctxt, tag_id: ast::node_id,
// that does so later on?
fn trans_const_expr(cx: @crate_ctxt, e: @ast::expr) -> ValueRef {
alt e.node {
ast::expr_cast(e1, _) {
alt ccx_tcx(cx).cast_map.find(e.id) {
some(ty::triv_cast.) { trans_const_expr(cx, e1) }
_ {
cx.sess.span_err(e.span,
"non-trivial cast in constant expression");
fail;
}
}
}
ast::expr_lit(lit) { ret trans_crate_lit(cx, *lit); }
ast::expr_binary(b, e1, e2) {
let te1 = trans_const_expr(cx, e1);
Expand Down
44 changes: 44 additions & 0 deletions src/comp/middle/ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ export ast_constr_to_constr;
export bind_params_in_type;
export block_ty;
export constr;
export cast_type;
export constr_general;
export constr_table;
export count_ty_params;
Expand Down Expand Up @@ -102,6 +103,8 @@ export substitute_type_params;
export t;
export tag_variants;
export tag_variant_with_id;
export triv_cast;
export triv_eq_ty;
export ty_param_substs_opt_and_ty;
export ty_param_kinds_and_ty;
export ty_native_fn;
Expand All @@ -128,6 +131,7 @@ export ty_param;
export ty_ptr;
export ty_rec;
export ty_tag;
export ty_to_machine_ty;
export ty_tup;
export ty_type;
export ty_uint;
Expand Down Expand Up @@ -198,6 +202,12 @@ type mt = {ty: t, mut: ast::mutability};
// the types of AST nodes.
type creader_cache = hashmap<{cnum: int, pos: uint, len: uint}, ty::t>;

tag cast_type {
/* cast may be ignored after substituting primitive with machine types
since expr already has the right type */
triv_cast;
}

type ctxt =
// constr_table fn_constrs,
// We need the ext_map just for printing the types of tags defined in
Expand All @@ -206,6 +216,7 @@ type ctxt =
sess: session::session,
def_map: resolve::def_map,
ext_map: resolve::ext_map,
cast_map: hashmap<ast::node_id, cast_type>,
node_types: node_type_table,
items: ast_map::map,
freevars: freevars::freevar_map,
Expand Down Expand Up @@ -393,6 +404,7 @@ fn mk_ctxt(s: session::session, dm: resolve::def_map,
sess: s,
def_map: dm,
ext_map: em,
cast_map: ast_util::new_node_hash(),
node_types: ntt,
items: amap,
freevars: freevars,
Expand Down Expand Up @@ -1481,6 +1493,38 @@ fn eq_raw_ty(&&a: @raw_t, &&b: @raw_t) -> bool {
fn eq_ty(&&a: t, &&b: t) -> bool { ret a == b; }


// Convert type to machine type
// (i.e. replace uint, int, float with target architecture machine types)
//
// FIXME somewhat expensive but this should only be called rarely
fn ty_to_machine_ty(cx: ctxt, ty: t) -> t {
fn sub_fn(cx: ctxt, uint_ty: t, int_ty: t, float_ty: t, in: t) -> t {
alt struct(cx, in) {
ty_uint. { ret uint_ty; }
ty_int. { ret int_ty; }
ty_float. { ret float_ty; }
_ { ret in; }
}
}

let cfg = cx.sess.get_targ_cfg();
let uint_ty = mk_mach(cx, cfg.uint_type);
let int_ty = mk_mach(cx, cfg.int_type);
let float_ty = mk_mach(cx, cfg.float_type);
let fold_m = fm_general(bind sub_fn(cx, uint_ty, int_ty, float_ty, _));

ret fold_ty(cx, fold_m, ty);
}

// Two types are trivially equal if they are either
// equal or if they are equal after substituting all occurences of
// machine independent primitive types by their machine type equivalents
// for the current target architecture
fn triv_eq_ty(cx: ctxt, &&a: t, &&b: t) -> bool {
ret eq_ty(a, b)
|| eq_ty(ty_to_machine_ty(cx, a), ty_to_machine_ty(cx, b));
}

// Type lookups
fn node_id_to_ty_param_substs_opt_and_ty(cx: ctxt, id: ast::node_id) ->
ty_param_substs_opt_and_ty {
Expand Down
27 changes: 23 additions & 4 deletions src/comp/middle/typeck.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1848,8 +1848,21 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier,
}
ast::expr_be(e) {
// FIXME: prove instead of assert
assert (ast_util::is_call_expr(e));
assert (ast_util::is_tail_call_expr(e));
check_expr_with(fcx, e, fcx.ret_ty);

alt e.node {
ast::expr_cast(_, _) {
alt tcx.cast_map.find(e.id) {
option::some(ty::triv_cast.) { }
_ { tcx.sess.span_err(expr.span,
"non-trivial cast of tail-call return value");
}
}
}
_ { /* regular tail call */ }
}

bot = true;
write::nil_ty(tcx, id);
}
Expand Down Expand Up @@ -2103,15 +2116,21 @@ fn check_expr_with_unifier(fcx: @fn_ctxt, expr: @ast::expr, unify: unifier,
ast::expr_cast(e, t) {
bot = check_expr(fcx, e);
let t_1 = ast_ty_to_ty_crate(fcx.ccx, t);
// FIXME: there are more forms of cast to support, eventually.
let t_e = expr_ty(tcx, e);

if !(type_is_scalar(fcx, expr.span, expr_ty(tcx, e)) &&
type_is_scalar(fcx, expr.span, t_1)) {
// FIXME there are more forms of cast to support, eventually.
if !( type_is_scalar(fcx, expr.span, t_e)
&& type_is_scalar(fcx, expr.span, t_1)) {
tcx.sess.span_err(expr.span,
"non-scalar cast: " +
ty_to_str(tcx, expr_ty(tcx, e)) + " as " +
ty_to_str(tcx, t_1));
}

// mark as triv_cast for later dropping in trans
if ty::triv_eq_ty(tcx, t_1, t_e)
{ tcx.cast_map.insert(expr.id, ty::triv_cast); }

write::ty_only_fixup(fcx, id, t_1);
}
ast::expr_vec(args, mut) {
Expand Down
17 changes: 16 additions & 1 deletion src/comp/syntax/ast_util.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@
import std::{str, option};
import std::{str, option, int, map};
import codemap::span;
import ast::*;

fn respan<copy T>(sp: span, t: T) -> spanned<T> {
ret {node: t, span: sp};
}

fn new_node_hash<copy V>() -> map::hashmap<node_id, V> {
fn node_id_hash(&&i: node_id) -> uint { ret int::hash(i as int); }
fn node_id_eq(&&a: node_id, &&b: node_id) -> bool
{ ret int::eq(a as int, b as int); }
ret map::mk_hashmap(node_id_hash, node_id_eq);
}

/* assuming that we're not in macro expansion */
fn mk_sp(lo: uint, hi: uint) -> span {
ret {lo: lo, hi: hi, expanded_from: codemap::os_none};
Expand Down Expand Up @@ -168,6 +175,14 @@ pure fn is_call_expr(e: @expr) -> bool {
alt e.node { expr_call(_, _, _) { true } _ { false } }
}

pure fn is_tail_call_expr(e: @expr) -> bool {
alt e.node {
expr_call(_, _, _) { true }
expr_cast(inner_e, _) { is_call_expr(inner_e) }
_ { false }
}
}

fn is_constraint_arg(e: @expr) -> bool {
alt e.node {
expr_lit(_) { ret true; }
Expand Down
2 changes: 1 addition & 1 deletion src/comp/syntax/parse/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -962,7 +962,7 @@ fn parse_bottom_expr(p: parser) -> @ast::expr {
let e = parse_expr(p);

// FIXME: Is this the right place for this check?
if /*check*/ast_util::is_call_expr(e) {
if /*check*/ ast_util::is_tail_call_expr(e) {
hi = e.span.hi;
ex = ast::expr_be(e);
} else { p.fatal("Non-call expression in tail call"); }
Expand Down
17 changes: 15 additions & 2 deletions src/lib/ctypes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ Definitions useful for C interop
*/

type c_int = i32;
type c_uint = u32;

type void = int; // Not really the same as C
type long = int;
Expand All @@ -15,8 +16,20 @@ type intptr_t = uint;
type uintptr_t = uint;
type uint32_t = u32;

// This *must* match with "import c_float = fXX" in std::math per arch
type c_float = f64;
// machine type equivalents of rust int, uint, float

#[cfg(target_arch="x86")]
type m_int = i32;
#[cfg(target_arch="x86_64")]
type m_int = i64;

#[cfg(target_arch="x86")]
type m_uint = u32;
#[cfg(target_arch="x86_64")]
type m_uint = u64;

// This *must* match with "import m_float = fXX" in std::math per arch
type m_float = f64;

type size_t = uint;
type ssize_t = int;
Expand Down
Loading