Skip to content

Commit

Permalink
Implement automatic overloaded dereference.
Browse files Browse the repository at this point in the history
Closes #7141.
  • Loading branch information
eddyb committed Mar 13, 2014
1 parent cdc18b9 commit 20b4e15
Show file tree
Hide file tree
Showing 33 changed files with 871 additions and 921 deletions.
2 changes: 1 addition & 1 deletion src/libnum/complex.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ impl<T: Clone + Float> Cmplx<T> {
/// Convert a polar representation into a complex number.
#[inline]
pub fn from_polar(r: &T, theta: &T) -> Cmplx<T> {
Cmplx::new(r * theta.cos(), r * theta.sin())
Cmplx::new(*r * theta.cos(), *r * theta.sin())
}
}

Expand Down
8 changes: 5 additions & 3 deletions src/librustc/middle/astencode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ use metadata::tydecode;
use metadata::tydecode::{DefIdSource, NominalType, TypeWithId, TypeParameter,
RegionParameter};
use metadata::tyencode;
use middle::typeck::{MethodCallee, MethodOrigin};
use middle::typeck::{MethodCall, MethodCallee, MethodOrigin};
use middle::{ty, typeck, moves};
use middle;
use util::ppaux::ty_to_str;
Expand Down Expand Up @@ -1039,7 +1039,8 @@ fn encode_side_tables_for_id(ecx: &e::EncodeContext,
}
}

for &method in maps.method_map.borrow().get().find(&id).iter() {
let method_call = MethodCall::expr(id);
for &method in maps.method_map.borrow().get().find(&method_call).iter() {
ebml_w.tag(c::tag_table_method_map, |ebml_w| {
ebml_w.id(id);
ebml_w.tag(c::tag_table_val, |ebml_w| {
Expand Down Expand Up @@ -1385,7 +1386,8 @@ fn decode_side_tables(xcx: @ExtendedDecodeContext,
}
c::tag_table_method_map => {
let method = val_dsr.read_method_callee(xcx);
dcx.maps.method_map.borrow_mut().get().insert(id, method);
let method_call = MethodCall::expr(id);
dcx.maps.method_map.borrow_mut().get().insert(method_call, method);
}
c::tag_table_vtable_map => {
let vtable_res =
Expand Down
5 changes: 3 additions & 2 deletions src/librustc/middle/borrowck/check_loans.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ use mc = middle::mem_categorization;
use middle::borrowck::*;
use middle::moves;
use middle::ty;
use middle::typeck::MethodCall;
use std::vec_ng::Vec;
use syntax::ast;
use syntax::ast_util;
Expand Down Expand Up @@ -838,11 +839,11 @@ fn check_loans_in_expr<'a>(this: &mut CheckLoanCtxt<'a>,
this.check_call(expr, None, expr.span, args.as_slice());
}
ast::ExprIndex(_, rval) | ast::ExprBinary(_, _, rval)
if method_map.get().contains_key(&expr.id) => {
if method_map.get().contains_key(&MethodCall::expr(expr.id)) => {
this.check_call(expr, None, expr.span, [rval]);
}
ast::ExprUnary(_, _) | ast::ExprIndex(_, _)
if method_map.get().contains_key(&expr.id) => {
if method_map.get().contains_key(&MethodCall::expr(expr.id)) => {
this.check_call(expr, None, expr.span, []);
}
ast::ExprInlineAsm(ref ia) => {
Expand Down
3 changes: 2 additions & 1 deletion src/librustc/middle/borrowck/gather_loans/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ use middle::moves;
use middle::pat_util;
use middle::ty::{ty_region};
use middle::ty;
use middle::typeck::MethodCall;
use util::common::indenter;
use util::ppaux::{Repr};

Expand Down Expand Up @@ -242,7 +243,7 @@ fn gather_loans_in_expr(this: &mut GatherLoanCtxt,

ast::ExprIndex(_, arg) |
ast::ExprBinary(_, _, arg)
if method_map.get().contains_key(&ex.id) => {
if method_map.get().contains_key(&MethodCall::expr(ex.id)) => {
// Arguments in method calls are always passed by ref.
//
// Currently these do not use adjustments, so we have to
Expand Down
12 changes: 7 additions & 5 deletions src/librustc/middle/borrowck/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -556,7 +556,8 @@ impl BorrowckCtxt {
move_data::MoveExpr => {
let (expr_ty, expr_span) = match self.tcx.map.find(move.id) {
Some(ast_map::NodeExpr(expr)) => {
(ty::expr_ty_adjusted(self.tcx, expr), expr.span)
(ty::expr_ty_adjusted(self.tcx, expr,
self.method_map.borrow().get()), expr.span)
}
r => self.tcx.sess.bug(format!("MoveExpr({:?}) maps to {:?}, not Expr",
move.id, r))
Expand All @@ -582,7 +583,8 @@ impl BorrowckCtxt {
move_data::Captured => {
let (expr_ty, expr_span) = match self.tcx.map.find(move.id) {
Some(ast_map::NodeExpr(expr)) => {
(ty::expr_ty_adjusted(self.tcx, expr), expr.span)
(ty::expr_ty_adjusted(self.tcx, expr,
self.method_map.borrow().get()), expr.span)
}
r => self.tcx.sess.bug(format!("Captured({:?}) maps to {:?}, not Expr",
move.id, r))
Expand Down Expand Up @@ -922,8 +924,8 @@ 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 node_method_ty(&mut self, method_call: typeck::MethodCall) -> Option<ty::t> {
self.method_map.borrow().get().find(&method_call).map(|method| method.ty)
}

fn adjustment(&mut self, id: ast::NodeId) -> Option<@ty::AutoAdjustment> {
Expand All @@ -932,7 +934,7 @@ impl mc::Typer for TcxTyper {
}

fn is_method_call(&mut self, id: ast::NodeId) -> bool {
self.method_map.borrow().get().contains_key(&id)
self.method_map.borrow().get().contains_key(&typeck::MethodCall::expr(id))
}

fn temporary_scope(&mut self, id: ast::NodeId) -> Option<ast::NodeId> {
Expand Down
4 changes: 2 additions & 2 deletions src/librustc/middle/cfg/construct.rs
Original file line number Diff line number Diff line change
Expand Up @@ -523,7 +523,7 @@ impl CFGBuilder {
}

fn is_method_call(&self, expr: &ast::Expr) -> bool {
let method_map = self.method_map.borrow();
method_map.get().contains_key(&expr.id)
let method_call = typeck::MethodCall::expr(expr.id);
self.method_map.borrow().get().contains_key(&method_call)
}
}
4 changes: 2 additions & 2 deletions src/librustc/middle/check_const.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,8 +117,8 @@ pub fn check_expr(v: &mut CheckCrateVisitor,
}
ExprLit(lit) if ast_util::lit_is_str(lit) => {}
ExprBinary(..) | ExprUnary(..) => {
let method_map = method_map.borrow();
if method_map.get().contains_key(&e.id) {
let method_call = typeck::MethodCall::expr(e.id);
if method_map.borrow().get().contains_key(&method_call) {
sess.span_err(e.span, "user-defined operators are not \
allowed in constant expressions");
}
Expand Down
6 changes: 3 additions & 3 deletions src/librustc/middle/const_eval.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use middle::astencode;
use middle::ty;
use middle::typeck::astconv;
use middle;
use util::nodemap::{DefIdMap, NodeMap};
use util::nodemap::{DefIdMap, FnvHashMap, NodeMap};

use syntax::ast::*;
use syntax::parse::token::InternedString;
Expand Down Expand Up @@ -136,7 +136,7 @@ pub fn lookup_variant_by_id(tcx: ty::ctxt,
}
let maps = astencode::Maps {
root_map: @RefCell::new(HashMap::new()),
method_map: @RefCell::new(NodeMap::new()),
method_map: @RefCell::new(FnvHashMap::new()),
vtable_map: @RefCell::new(NodeMap::new()),
capture_map: @RefCell::new(NodeMap::new())
};
Expand Down Expand Up @@ -186,7 +186,7 @@ pub fn lookup_const_by_id(tcx: ty::ctxt, def_id: ast::DefId)
}
let maps = astencode::Maps {
root_map: @RefCell::new(HashMap::new()),
method_map: @RefCell::new(NodeMap::new()),
method_map: @RefCell::new(FnvHashMap::new()),
vtable_map: @RefCell::new(NodeMap::new()),
capture_map: @RefCell::new(NodeMap::new())
};
Expand Down
4 changes: 2 additions & 2 deletions src/librustc/middle/dataflow.rs
Original file line number Diff line number Diff line change
Expand Up @@ -810,8 +810,8 @@ impl<'a, O:DataFlowOperator> PropagationContext<'a, O> {
}

fn is_method_call(&self, expr: &ast::Expr) -> bool {
let method_map = self.dfcx.method_map.borrow();
method_map.get().contains_key(&expr.id)
let method_call = typeck::MethodCall::expr(expr.id);
self.dfcx.method_map.borrow().get().contains_key(&method_call)
}

fn reset(&mut self, bits: &mut [uint]) {
Expand Down
7 changes: 4 additions & 3 deletions src/librustc/middle/dead.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,9 +92,10 @@ impl MarkSymbolVisitor {
}
}

fn lookup_and_handle_method(&mut self, id: &ast::NodeId,
fn lookup_and_handle_method(&mut self, id: ast::NodeId,
span: codemap::Span) {
match self.method_map.borrow().get().find(id) {
let method_call = typeck::MethodCall::expr(id);
match self.method_map.borrow().get().find(&method_call) {
Some(method) => {
match method.origin {
typeck::MethodStatic(def_id) => {
Expand Down Expand Up @@ -179,7 +180,7 @@ impl Visitor<()> for MarkSymbolVisitor {
fn visit_expr(&mut self, expr: &ast::Expr, _: ()) {
match expr.node {
ast::ExprMethodCall(..) => {
self.lookup_and_handle_method(&expr.id, expr.span);
self.lookup_and_handle_method(expr.id, expr.span);
}
_ => ()
}
Expand Down
5 changes: 3 additions & 2 deletions src/librustc/middle/effect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
/// `unsafe`.

use middle::ty;
use middle::typeck::MethodMap;
use middle::typeck::{MethodCall, MethodMap};
use util::ppaux;

use syntax::ast;
Expand Down Expand Up @@ -138,7 +138,8 @@ impl Visitor<()> for EffectCheckVisitor {
fn visit_expr(&mut self, expr: &ast::Expr, _:()) {
match expr.node {
ast::ExprMethodCall(_, _, _) => {
let base_type = self.method_map.borrow().get().get(&expr.id).ty;
let method_call = MethodCall::expr(expr.id);
let base_type = self.method_map.borrow().get().get(&method_call).ty;
debug!("effect: method call case, base type is {}",
ppaux::ty_to_str(self.tcx, base_type));
if type_is_unsafe_function(base_type) {
Expand Down
5 changes: 3 additions & 2 deletions src/librustc/middle/kind.rs
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,7 @@ pub fn check_expr(cx: &mut Context, e: &Expr) {
// Handle any kind bounds on type parameters
{
let method_map = cx.method_map.borrow();
let method = method_map.get().find(&e.id);
let method = method_map.get().find(&typeck::MethodCall::expr(e.id));
let node_type_substs = cx.tcx.node_type_substs.borrow();
let r = match method {
Some(method) => Some(&method.substs.tps),
Expand Down Expand Up @@ -341,7 +341,8 @@ pub fn check_expr(cx: &mut Context, e: &Expr) {
match **adjustment {
ty::AutoObject(..) => {
let source_ty = ty::expr_ty(cx.tcx, e);
let target_ty = ty::expr_ty_adjusted(cx.tcx, e);
let target_ty = ty::expr_ty_adjusted(cx.tcx, e,
cx.method_map.borrow().get());
check_trait_cast(cx, source_ty, target_ty, e.span);
}
ty::AutoAddEnv(..) |
Expand Down
3 changes: 2 additions & 1 deletion src/librustc/middle/lint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1491,7 +1491,8 @@ fn check_stability(cx: &Context, e: &ast::Expr) {
}
}
ast::ExprMethodCall(..) => {
match cx.method_map.borrow().get().find(&e.id) {
let method_call = typeck::MethodCall::expr(e.id);
match cx.method_map.borrow().get().find(&method_call) {
Some(method) => {
match method.origin {
typeck::MethodStatic(def_id) => {
Expand Down
97 changes: 47 additions & 50 deletions src/librustc/middle/mem_categorization.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@
#[allow(non_camel_case_types)];

use middle::ty;
use middle::typeck;
use util::ppaux::{ty_to_str, region_ptr_to_str, Repr};

use std::vec_ng::Vec;
Expand Down Expand Up @@ -268,7 +269,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 node_method_ty(&mut self, method_call: typeck::MethodCall) -> 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 @@ -365,7 +366,8 @@ impl<TYPER:Typer> MemCategorizationContext<TYPER> {
fn expr_ty_adjusted(&mut self, expr: &ast::Expr) -> McResult<ty::t> {
let unadjusted_ty = if_ok!(self.expr_ty(expr));
let adjustment = self.adjustment(expr.id);
Ok(ty::adjust_ty(self.tcx(), expr.span, unadjusted_ty, adjustment))
Ok(ty::adjust_ty(self.tcx(), expr.span, expr.id, unadjusted_ty, adjustment,
|method_call| self.typer.node_method_ty(method_call)))
}

fn node_ty(&mut self, id: ast::NodeId) -> McResult<ty::t> {
Expand Down Expand Up @@ -435,21 +437,11 @@ impl<TYPER:Typer> MemCategorizationContext<TYPER> {
let expr_ty = if_ok!(self.expr_ty(expr));
match expr.node {
ast::ExprUnary(ast::UnDeref, 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))
};
let base_cmt = if_ok!(self.cat_expr(e_base));
Ok(self.cat_deref(expr, base_cmt, 0))
}

ast::ExprField(base, f_name, _) => {
// Method calls are now a special syntactic form,
// so `a.b` should always be a field.
assert!(!self.typer.is_method_call(expr.id));

let base_cmt = if_ok!(self.cat_expr(base));
Ok(self.cat_field(expr, base_cmt, f_name, expr_ty))
}
Expand Down Expand Up @@ -725,59 +717,64 @@ impl<TYPER:Typer> MemCategorizationContext<TYPER> {
// `()` (the empty tuple).

let opaque_ty = ty::mk_tup(self.tcx(), Vec::new());
return self.cat_deref_common(node, base_cmt, deref_cnt, opaque_ty);
self.cat_deref_common(node, base_cmt, deref_cnt, opaque_ty)
}

pub fn cat_deref<N:ast_node>(&mut self,
node: &N,
base_cmt: cmt,
deref_cnt: uint)
-> cmt {
let mt = match ty::deref(base_cmt.ty, true) {
Some(mt) => mt,
fn cat_deref<N:ast_node>(&mut self,
node: &N,
base_cmt: cmt,
deref_cnt: uint)
-> cmt {
let method_call = typeck::MethodCall {
expr_id: node.id(),
autoderef: deref_cnt as u32
};
let method_ty = self.typer.node_method_ty(method_call);

debug!("cat_deref: method_call={:?} method_ty={}",
method_call, method_ty.map(|ty| ty.repr(self.tcx())));

let base_cmt = match method_ty {
Some(method_ty) => {
let ref_ty = ty::ty_fn_ret(method_ty);
self.cat_rvalue_node(node.id(), node.span(), ref_ty)
}
None => base_cmt
};
match ty::deref(base_cmt.ty, true) {
Some(mt) => self.cat_deref_common(node, base_cmt, deref_cnt, mt.ty),
None => {
self.tcx().sess.span_bug(
node.span(),
format!("Explicit deref of non-derefable type: {}",
base_cmt.ty.repr(self.tcx())));
}
};

return self.cat_deref_common(node, base_cmt, deref_cnt, mt.ty);
}
}

pub fn cat_deref_common<N:ast_node>(&mut self,
node: &N,
base_cmt: cmt,
deref_cnt: uint,
deref_ty: ty::t)
-> cmt {
match deref_kind(self.tcx(), base_cmt.ty) {
fn cat_deref_common<N:ast_node>(&mut self,
node: &N,
base_cmt: cmt,
deref_cnt: uint,
deref_ty: ty::t)
-> cmt {
let (m, cat) = match deref_kind(self.tcx(), base_cmt.ty) {
deref_ptr(ptr) => {
// for unique ptrs, we inherit mutability from the
// owning reference.
let m = MutabilityCategory::from_pointer_kind(base_cmt.mutbl,
ptr);

@cmt_ {
id:node.id(),
span:node.span(),
cat:cat_deref(base_cmt, deref_cnt, ptr),
mutbl:m,
ty:deref_ty
}
(MutabilityCategory::from_pointer_kind(base_cmt.mutbl, ptr),
cat_deref(base_cmt, deref_cnt, ptr))
}

deref_interior(interior) => {
let m = base_cmt.mutbl.inherit();
@cmt_ {
id:node.id(),
span:node.span(),
cat:cat_interior(base_cmt, interior),
mutbl:m,
ty:deref_ty
}
(base_cmt.mutbl.inherit(), cat_interior(base_cmt, interior))
}
};
@cmt_ {
id: node.id(),
span: node.span(),
cat: cat,
mutbl: m,
ty: deref_ty
}
}

Expand Down
Loading

0 comments on commit 20b4e15

Please sign in to comment.