Skip to content

Commit

Permalink
auto merge of rust-lang#12491 : eddyb/rust/deref, r=nikomatsakis
Browse files Browse the repository at this point in the history
Add the `Deref` and `DerefMut` traits and implement overloading explicit dereferences.
  • Loading branch information
bors committed Mar 5, 2014
2 parents 712c630 + bcc5486 commit 87a31f6
Show file tree
Hide file tree
Showing 19 changed files with 520 additions and 138 deletions.
7 changes: 5 additions & 2 deletions src/doc/rust.md
Original file line number Diff line number Diff line change
Expand Up @@ -2485,8 +2485,11 @@ before the expression they apply to.
`*`
: Dereference. When applied to a [pointer](#pointer-types) it denotes the pointed-to location.
For pointers to mutable locations, the resulting [lvalue](#lvalues-rvalues-and-temporaries) can be assigned to.
For [enums](#enumerated-types) that have only a single variant, containing a single parameter,
the dereference operator accesses this parameter.
On non-pointer types, it calls calls the `deref` method of the `std::ops::Deref` trait, or the
`deref_mut` method of the `std::ops::DerefMut` trait (if implemented by the type and required
for an outer expression that will or could mutate the dereference), and produces the
result of dereferencing the `&` or `&mut` borrowed pointer returned from the overload method.

`!`
: Logical negation. On the boolean type, this flips between `true` and
`false`. On integer types, this inverts the individual bits in the
Expand Down
7 changes: 5 additions & 2 deletions src/librustc/middle/borrowck/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -921,14 +921,17 @@ impl mc::Typer for TcxTyper {
Ok(ty::node_id_to_type(self.tcx, id))
}

fn node_method_ty(&mut self, id: ast::NodeId) -> Option<ty::t> {
self.method_map.borrow().get().find(&id).map(|method| method.ty)
}

fn adjustment(&mut self, id: ast::NodeId) -> Option<@ty::AutoAdjustment> {
let adjustments = self.tcx.adjustments.borrow();
adjustments.get().find_copy(&id)
}

fn is_method_call(&mut self, id: ast::NodeId) -> bool {
let method_map = self.method_map.borrow();
method_map.get().contains_key(&id)
self.method_map.borrow().get().contains_key(&id)
}

fn temporary_scope(&mut self, id: ast::NodeId) -> Option<ast::NodeId> {
Expand Down
3 changes: 3 additions & 0 deletions src/librustc/middle/lang_items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,9 @@ lets_do_this! {
ShrTraitLangItem, "shr", shr_trait;
IndexTraitLangItem, "index", index_trait;

DerefTraitLangItem, "deref", deref_trait;
DerefMutTraitLangItem, "deref_mut", deref_mut_trait;

EqTraitLangItem, "eq", eq_trait;
OrdTraitLangItem, "ord", ord_trait;

Expand Down
13 changes: 8 additions & 5 deletions src/librustc/middle/mem_categorization.rs
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,7 @@ pub type McResult<T> = Result<T, ()>;
pub trait Typer {
fn tcx(&self) -> ty::ctxt;
fn node_ty(&mut self, id: ast::NodeId) -> McResult<ty::t>;
fn node_method_ty(&mut self, id: ast::NodeId) -> Option<ty::t>;
fn adjustment(&mut self, node_id: ast::NodeId) -> Option<@ty::AutoAdjustment>;
fn is_method_call(&mut self, id: ast::NodeId) -> bool;
fn temporary_scope(&mut self, rvalue_id: ast::NodeId) -> Option<ast::NodeId>;
Expand Down Expand Up @@ -433,11 +434,13 @@ impl<TYPER:Typer> MemCategorizationContext<TYPER> {
let expr_ty = if_ok!(self.expr_ty(expr));
match expr.node {
ast::ExprUnary(ast::UnDeref, e_base) => {
if self.typer.is_method_call(expr.id) {
return Ok(self.cat_rvalue_node(expr.id(), expr.span(), expr_ty));
}

let base_cmt = if_ok!(self.cat_expr(e_base));
let base_cmt = match self.typer.node_method_ty(expr.id) {
Some(method_ty) => {
let ref_ty = ty::ty_fn_ret(method_ty);
self.cat_rvalue_node(expr.id(), expr.span(), ref_ty)
}
None => if_ok!(self.cat_expr(e_base))
};
Ok(self.cat_deref(expr, base_cmt, 0))
}

Expand Down
15 changes: 4 additions & 11 deletions src/librustc/middle/trans/callee.rs
Original file line number Diff line number Diff line change
Expand Up @@ -444,14 +444,12 @@ pub fn trans_call<'a>(
call_ex: &ast::Expr,
f: &ast::Expr,
args: CallArgs,
id: ast::NodeId,
dest: expr::Dest)
-> &'a Block<'a> {
let _icx = push_ctxt("trans_call");
trans_call_inner(in_cx,
Some(common::expr_info(call_ex)),
expr_ty(in_cx, f),
node_id_type(in_cx, id),
|cx, _| trans(cx, f),
args,
Some(dest)).bcx
Expand All @@ -471,7 +469,6 @@ pub fn trans_method_call<'a>(
bcx,
Some(common::expr_info(call_ex)),
monomorphize_type(bcx, method_ty),
expr_ty(bcx, call_ex),
|cx, arg_cleanup_scope| {
meth::trans_method_callee(cx, call_ex.id, rcvr, arg_cleanup_scope)
},
Expand All @@ -490,11 +487,9 @@ pub fn trans_lang_call<'a>(
} else {
csearch::get_type(bcx.ccx().tcx, did).ty
};
let rty = ty::ty_fn_ret(fty);
callee::trans_call_inner(bcx,
None,
fty,
rty,
|bcx, _| {
trans_fn_ref_with_vtables_to_callee(bcx,
did,
Expand All @@ -520,12 +515,10 @@ pub fn trans_lang_call_with_type_params<'a>(
fty = csearch::get_type(bcx.tcx(), did).ty;
}

let rty = ty::ty_fn_ret(fty);
return callee::trans_call_inner(
bcx,
None,
fty,
rty,
|bcx, _| {
let callee =
trans_fn_ref_with_vtables_to_callee(bcx, did, 0,
Expand Down Expand Up @@ -554,7 +547,6 @@ pub fn trans_call_inner<'a>(
bcx: &'a Block<'a>,
call_info: Option<NodeInfo>,
callee_ty: ty::t,
ret_ty: ty::t,
get_callee: |bcx: &'a Block<'a>,
arg_cleanup_scope: cleanup::ScopeId|
-> Callee<'a>,
Expand Down Expand Up @@ -610,9 +602,10 @@ pub fn trans_call_inner<'a>(
}
};

let abi = match ty::get(callee_ty).sty {
ty::ty_bare_fn(ref f) => f.abis,
_ => AbiSet::Rust()
let (abi, ret_ty) = match ty::get(callee_ty).sty {
ty::ty_bare_fn(ref f) => (f.abis, f.sig.output),
ty::ty_closure(ref f) => (AbiSet::Rust(), f.sig.output),
_ => fail!("expected bare rust fn or closure in trans_call_inner")
};
let is_rust_fn =
abi.is_rust() ||
Expand Down
55 changes: 21 additions & 34 deletions src/librustc/middle/trans/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -467,10 +467,6 @@ fn trans_datum_unadjusted<'a>(bcx: &'a Block<'a>,

trans_binary(bcx, expr, op, lhs, rhs)
}
ast::ExprUnary(ast::UnDeref, base) => {
let basedatum = unpack_datum!(bcx, trans(bcx, base));
deref_once(bcx, expr, basedatum, 0)
}
ast::ExprUnary(op, x) => {
trans_unary_datum(bcx, expr, op, x)
}
Expand Down Expand Up @@ -782,12 +778,7 @@ fn trans_rvalue_dps_unadjusted<'a>(bcx: &'a Block<'a>,
closure::trans_expr_fn(bcx, sigil, decl, body, expr.id, dest)
}
ast::ExprCall(f, ref args) => {
callee::trans_call(bcx,
expr,
f,
callee::ArgExprs(args.as_slice()),
expr.id,
dest)
callee::trans_call(bcx, expr, f, callee::ArgExprs(args.as_slice()), dest)
}
ast::ExprMethodCall(_, _, ref args) => {
callee::trans_method_call(bcx,
Expand All @@ -798,18 +789,15 @@ fn trans_rvalue_dps_unadjusted<'a>(bcx: &'a Block<'a>,
}
ast::ExprBinary(_, lhs, rhs) => {
// if not overloaded, would be RvalueDatumExpr
trans_overloaded_op(bcx, expr, lhs,
Some(&*rhs), expr_ty(bcx, expr), dest)
trans_overloaded_op(bcx, expr, lhs, Some(&*rhs), Some(dest)).bcx
}
ast::ExprUnary(_, subexpr) => {
// if not overloaded, would be RvalueDatumExpr
trans_overloaded_op(bcx, expr, subexpr,
None, expr_ty(bcx, expr), dest)
trans_overloaded_op(bcx, expr, subexpr, None, Some(dest)).bcx
}
ast::ExprIndex(base, idx) => {
// if not overloaded, would be RvalueDatumExpr
trans_overloaded_op(bcx, expr, base,
Some(&*idx), expr_ty(bcx, expr), dest)
trans_overloaded_op(bcx, expr, base, Some(&*idx), Some(dest)).bcx
}
ast::ExprCast(val, _) => {
// DPS output mode means this is a trait cast:
Expand Down Expand Up @@ -1185,17 +1173,14 @@ fn trans_unary_datum<'a>(
let mut bcx = bcx;
let _icx = push_ctxt("trans_unary_datum");

// if deref, would be LvalueExpr
assert!(op != ast::UnDeref);

// if overloaded, would be RvalueDpsExpr
{
let overloaded = {
let method_map = bcx.ccx().maps.method_map.borrow();
assert!(!method_map.get().contains_key(&un_expr.id));
}
method_map.get().contains_key(&un_expr.id)
};
// if overloaded, would be RvalueDpsExpr
assert!(!overloaded || op == ast::UnDeref);

let un_ty = expr_ty(bcx, un_expr);
let sub_ty = expr_ty(bcx, sub_expr);

return match op {
ast::UnNot => {
Expand Down Expand Up @@ -1226,15 +1211,19 @@ fn trans_unary_datum<'a>(
immediate_rvalue_bcx(bcx, llneg, un_ty).to_expr_datumblock()
}
ast::UnBox => {
trans_boxed_expr(bcx, un_ty, sub_expr, sub_ty, heap_managed)
trans_boxed_expr(bcx, un_ty, sub_expr, expr_ty(bcx, sub_expr), heap_managed)
}
ast::UnUniq => {
trans_boxed_expr(bcx, un_ty, sub_expr, sub_ty, heap_exchange)
trans_boxed_expr(bcx, un_ty, sub_expr, expr_ty(bcx, sub_expr), heap_exchange)
}
ast::UnDeref => {
bcx.sess().bug("deref expressions should have been \
translated using trans_lvalue(), not \
trans_unary_datum()")
if overloaded {
let r = trans_overloaded_op(bcx, un_expr, sub_expr, None, None);
DatumBlock(r.bcx, Datum(r.val, un_ty, LvalueExpr))
} else {
let datum = unpack_datum!(bcx, trans(bcx, sub_expr));
deref_once(bcx, un_expr, datum, 0)
}
}
};
}
Expand Down Expand Up @@ -1506,22 +1495,20 @@ fn trans_overloaded_op<'a, 'b>(
expr: &ast::Expr,
rcvr: &'b ast::Expr,
arg: Option<&'b ast::Expr>,
ret_ty: ty::t,
dest: Dest)
-> &'a Block<'a> {
dest: Option<Dest>)
-> Result<'a> {
let method_ty = bcx.ccx().maps.method_map.borrow().get().get(&expr.id).ty;
callee::trans_call_inner(bcx,
Some(expr_info(expr)),
monomorphize_type(bcx, method_ty),
ret_ty,
|bcx, arg_cleanup_scope| {
meth::trans_method_callee(bcx,
expr.id,
rcvr,
arg_cleanup_scope)
},
callee::ArgAutorefSecond(rcvr, arg),
Some(dest)).bcx
dest)
}

fn int_cast(bcx: &Block,
Expand Down
3 changes: 1 addition & 2 deletions src/librustc/middle/trans/reflect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,9 +105,8 @@ impl<'a> Reflector<'a> {
for (i, a) in args.iter().enumerate() {
debug!("arg {}: {}", i, bcx.val_to_str(*a));
}
let bool_ty = ty::mk_bool();
let result = unpack_result!(bcx, callee::trans_call_inner(
self.bcx, None, mth_ty, bool_ty,
self.bcx, None, mth_ty,
|bcx, _| meth::trans_trait_callee_from_llval(bcx,
mth_ty,
mth_idx,
Expand Down
1 change: 1 addition & 0 deletions src/librustc/middle/ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3284,6 +3284,7 @@ pub fn expr_kind(tcx: ctxt,
// exception, as its result is always unit.
return match expr.node {
ast::ExprAssignOp(..) => RvalueStmtExpr,
ast::ExprUnary(ast::UnDeref, _) => LvalueExpr,
_ => RvalueDpsExpr
};
}
Expand Down
Loading

0 comments on commit 87a31f6

Please sign in to comment.