Skip to content

Commit

Permalink
Implement new type-checking strategy for binary operators. Basically,
Browse files Browse the repository at this point in the history
the plan is to treat all binary operators as if they were overloaded,
relying on the fact that we have impls for all the builtin scalar
operations (and no more). But then during writeback we clear the
overload if the types correspond to a builtin op.

This strategy allows us to avoid having to know the types of the
operands ahead of time. It also avoids us overspecializing as we did in
the past.
  • Loading branch information
nikomatsakis committed Mar 30, 2015
1 parent f55d03c commit d649292
Show file tree
Hide file tree
Showing 10 changed files with 573 additions and 472 deletions.
84 changes: 10 additions & 74 deletions src/librustc/middle/ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3039,6 +3039,10 @@ pub fn mk_nil<'tcx>(cx: &ctxt<'tcx>) -> Ty<'tcx> {
mk_tup(cx, Vec::new())
}

pub fn mk_bool<'tcx>(cx: &ctxt<'tcx>) -> Ty<'tcx> {
mk_t(cx, ty_bool)
}

pub fn mk_bare_fn<'tcx>(cx: &ctxt<'tcx>,
opt_def_id: Option<ast::DefId>,
fty: &'tcx BareFnTy<'tcx>) -> Ty<'tcx> {
Expand Down Expand Up @@ -3406,8 +3410,12 @@ pub fn type_is_scalar(ty: Ty) -> bool {
/// Returns true if this type is a floating point type and false otherwise.
pub fn type_is_floating_point(ty: Ty) -> bool {
match ty.sty {
ty_float(_) => true,
_ => false,
ty_float(_) |
ty_infer(FloatVar(_)) =>
true,

_ =>
false,
}
}

Expand Down Expand Up @@ -5805,78 +5813,6 @@ pub fn closure_upvars<'tcx>(typer: &mc::Typer<'tcx>,
}
}

pub fn is_binopable<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>, op: ast::BinOp) -> bool {
#![allow(non_upper_case_globals)]
const tycat_other: isize = 0;
const tycat_bool: isize = 1;
const tycat_char: isize = 2;
const tycat_int: isize = 3;
const tycat_float: isize = 4;
const tycat_raw_ptr: isize = 6;

const opcat_add: isize = 0;
const opcat_sub: isize = 1;
const opcat_mult: isize = 2;
const opcat_shift: isize = 3;
const opcat_rel: isize = 4;
const opcat_eq: isize = 5;
const opcat_bit: isize = 6;
const opcat_logic: isize = 7;
const opcat_mod: isize = 8;

fn opcat(op: ast::BinOp) -> isize {
match op.node {
ast::BiAdd => opcat_add,
ast::BiSub => opcat_sub,
ast::BiMul => opcat_mult,
ast::BiDiv => opcat_mult,
ast::BiRem => opcat_mod,
ast::BiAnd => opcat_logic,
ast::BiOr => opcat_logic,
ast::BiBitXor => opcat_bit,
ast::BiBitAnd => opcat_bit,
ast::BiBitOr => opcat_bit,
ast::BiShl => opcat_shift,
ast::BiShr => opcat_shift,
ast::BiEq => opcat_eq,
ast::BiNe => opcat_eq,
ast::BiLt => opcat_rel,
ast::BiLe => opcat_rel,
ast::BiGe => opcat_rel,
ast::BiGt => opcat_rel
}
}

fn tycat<'tcx>(cx: &ctxt<'tcx>, ty: Ty<'tcx>) -> isize {
if type_is_simd(cx, ty) {
return tycat(cx, simd_type(cx, ty))
}
match ty.sty {
ty_char => tycat_char,
ty_bool => tycat_bool,
ty_int(_) | ty_uint(_) | ty_infer(IntVar(_)) => tycat_int,
ty_float(_) | ty_infer(FloatVar(_)) => tycat_float,
ty_ptr(_) => tycat_raw_ptr,
_ => tycat_other
}
}

const t: bool = true;
const f: bool = false;

let tbl = [
// +, -, *, shift, rel, ==, bit, logic, mod
/*other*/ [f, f, f, f, f, f, f, f, f],
/*bool*/ [f, f, f, f, t, t, t, t, f],
/*char*/ [f, f, f, f, t, t, f, f, f],
/*isize*/ [t, t, t, t, t, t, t, f, t],
/*float*/ [t, t, t, f, t, t, f, f, f],
/*bot*/ [t, t, t, t, t, t, t, t, t],
/*raw ptr*/ [f, f, f, f, t, t, f, f, f]];

return tbl[tycat(cx, ty) as usize ][opcat(op) as usize];
}

// Returns the repeat count for a repeating vector expression.
pub fn eval_repeat_count(tcx: &ctxt, count_expr: &ast::Expr) -> usize {
match const_eval::eval_const_expr_partial(tcx, count_expr, Some(tcx.types.usize)) {
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_trans/trans/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -560,7 +560,7 @@ pub fn compare_scalar_types<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
_ => bcx.sess().bug("compare_scalar_types: must be a comparison operator")
}
}
ty::ty_bool | ty::ty_uint(_) | ty::ty_char => {
ty::ty_bare_fn(..) | ty::ty_bool | ty::ty_uint(_) | ty::ty_char => {
ICmp(bcx, bin_op_to_icmp_predicate(bcx.ccx(), op, false), lhs, rhs, debug_loc)
}
ty::ty_ptr(mt) if common::type_is_sized(bcx.tcx(), mt.ty) => {
Expand Down
12 changes: 11 additions & 1 deletion src/librustc_trans/trans/consts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -351,7 +351,14 @@ pub fn const_expr<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
e: &ast::Expr,
ety: Ty<'tcx>,
param_substs: &'tcx Substs<'tcx>) -> ValueRef {
param_substs: &'tcx Substs<'tcx>)
-> ValueRef
{
debug!("const_expr_unadjusted(e={}, ety={}, param_substs={})",
e.repr(cx.tcx()),
ety.repr(cx.tcx()),
param_substs.repr(cx.tcx()));

let map_list = |exprs: &[P<ast::Expr>]| {
exprs.iter().map(|e| const_expr(cx, &**e, param_substs).0)
.fold(Vec::new(), |mut l, val| { l.push(val); l })
Expand All @@ -366,6 +373,9 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
/* Neither type is bottom, and we expect them to be unified
* already, so the following is safe. */
let (te1, ty) = const_expr(cx, &**e1, param_substs);
debug!("const_expr_unadjusted: te1={}, ty={}",
cx.tn().val_to_string(te1),
ty.repr(cx.tcx()));
let is_simd = ty::type_is_simd(cx.tcx(), ty);
let intype = if is_simd {
ty::simd_type(cx.tcx(), ty)
Expand Down
5 changes: 4 additions & 1 deletion src/librustc_trans/trans/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2384,6 +2384,7 @@ fn deref_once<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
}
}

#[derive(Debug)]
enum OverflowOp {
Add,
Sub,
Expand Down Expand Up @@ -2413,6 +2414,7 @@ enum OverflowCodegen {

enum OverflowOpViaInputCheck { Shl, Shr, }

#[derive(Debug)]
enum OverflowOpViaIntrinsic { Add, Sub, Mul, }

impl OverflowOpViaIntrinsic {
Expand All @@ -2437,7 +2439,8 @@ impl OverflowOpViaIntrinsic {
_ => panic!("unsupported target word size")
},
ref t @ ty_uint(_) | ref t @ ty_int(_) => t.clone(),
_ => panic!("tried to get overflow intrinsic for non-int type")
_ => panic!("tried to get overflow intrinsic for {:?} applied to non-int type",
*self)
};

match *self {
Expand Down
4 changes: 0 additions & 4 deletions src/librustc_typeck/check/callee.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
// except according to those terms.

use super::autoderef;
use super::AutorefArgs;
use super::check_argument_types;
use super::check_expr;
use super::check_method_argument_types;
Expand Down Expand Up @@ -258,7 +257,6 @@ fn confirm_builtin_call<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
&fn_sig.inputs,
&expected_arg_tys[..],
arg_exprs,
AutorefArgs::No,
fn_sig.variadic,
TupleArgumentsFlag::DontTupleArguments);

Expand Down Expand Up @@ -288,7 +286,6 @@ fn confirm_deferred_closure_call<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
&*fn_sig.inputs,
&*expected_arg_tys,
arg_exprs,
AutorefArgs::No,
fn_sig.variadic,
TupleArgumentsFlag::TupleArguments);

Expand All @@ -308,7 +305,6 @@ fn confirm_overloaded_call<'a,'tcx>(fcx: &FnCtxt<'a, 'tcx>,
method_callee.ty,
callee_expr,
arg_exprs,
AutorefArgs::No,
TupleArgumentsFlag::TupleArguments,
expected);
write_call(fcx, call_expr, output_type);
Expand Down
Loading

0 comments on commit d649292

Please sign in to comment.