diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs index db62e6bedf08..96a3203e56c0 100644 --- a/src/librustc/middle/astencode.rs +++ b/src/librustc/middle/astencode.rs @@ -1023,7 +1023,7 @@ fn encode_side_tables_for_id(ecx: &e::EncodeContext, }) } - for &dr in maps.vtable_map.borrow().find(&id).iter() { + for &dr in maps.vtable_map.borrow().find(&method_call).iter() { ebml_w.tag(c::tag_table_vtable_map, |ebml_w| { ebml_w.id(id); ebml_w.tag(c::tag_table_val, |ebml_w| { @@ -1344,7 +1344,8 @@ fn decode_side_tables(xcx: &ExtendedDecodeContext, let vtable_res = val_dsr.read_vtable_res(xcx.dcx.tcx, xcx.dcx.cdata); - dcx.maps.vtable_map.borrow_mut().insert(id, vtable_res); + let vtable_key = MethodCall::expr(id); + dcx.maps.vtable_map.borrow_mut().insert(vtable_key, vtable_res); } c::tag_table_adjustments => { let adj: @ty::AutoAdjustment = @val_dsr.read_auto_adjustment(xcx); diff --git a/src/librustc/middle/const_eval.rs b/src/librustc/middle/const_eval.rs index e1b341987775..8d7cff98f42b 100644 --- a/src/librustc/middle/const_eval.rs +++ b/src/librustc/middle/const_eval.rs @@ -129,7 +129,7 @@ pub fn lookup_variant_by_id(tcx: &ty::ctxt, let maps = astencode::Maps { root_map: @RefCell::new(HashMap::new()), method_map: @RefCell::new(FnvHashMap::new()), - vtable_map: @RefCell::new(NodeMap::new()), + vtable_map: @RefCell::new(FnvHashMap::new()), capture_map: RefCell::new(NodeMap::new()) }; let e = match csearch::maybe_get_item_ast(tcx, enum_def, @@ -170,7 +170,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(FnvHashMap::new()), - vtable_map: @RefCell::new(NodeMap::new()), + vtable_map: @RefCell::new(FnvHashMap::new()), capture_map: RefCell::new(NodeMap::new()) }; let e = match csearch::maybe_get_item_ast(tcx, def_id, diff --git a/src/librustc/middle/trans/callee.rs b/src/librustc/middle/trans/callee.rs index 5ab94240357b..92b97cdfc9f0 100644 --- a/src/librustc/middle/trans/callee.rs +++ b/src/librustc/middle/trans/callee.rs @@ -170,16 +170,11 @@ pub fn trans_fn_ref(bcx: &Block, def_id: ast::DefId, node: ExprOrMethodCall) -> let _icx = push_ctxt("trans_fn_ref"); let type_params = node_id_type_params(bcx, node); - let vtables = match node { - ExprId(id) => node_vtables(bcx, id), - MethodCall(ref method_call) => { - if method_call.autoderef == 0 { - node_vtables(bcx, method_call.expr_id) - } else { - None - } - } + let vtable_key = match node { + ExprId(id) => MethodCall::expr(id), + MethodCall(method_call) => method_call }; + let vtables = node_vtables(bcx, vtable_key); debug!("trans_fn_ref(def_id={}, node={:?}, type_params={}, vtables={})", def_id.repr(bcx.tcx()), node, type_params.repr(bcx.tcx()), vtables.repr(bcx.tcx())); diff --git a/src/librustc/middle/trans/common.rs b/src/librustc/middle/trans/common.rs index b5b68a521a87..9787e9228bf9 100644 --- a/src/librustc/middle/trans/common.rs +++ b/src/librustc/middle/trans/common.rs @@ -829,7 +829,7 @@ pub fn node_id_type_params(bcx: &Block, node: ExprOrMethodCall) -> Vec { } } -pub fn node_vtables(bcx: &Block, id: ast::NodeId) +pub fn node_vtables(bcx: &Block, id: typeck::MethodCall) -> Option { let vtable_map = bcx.ccx().maps.vtable_map.borrow(); let raw_vtables = vtable_map.find(&id); diff --git a/src/librustc/middle/trans/meth.rs b/src/librustc/middle/trans/meth.rs index c5e4fa49f64b..4701f38c09a8 100644 --- a/src/librustc/middle/trans/meth.rs +++ b/src/librustc/middle/trans/meth.rs @@ -208,7 +208,8 @@ pub fn trans_static_method_callee(bcx: &Block, debug!("trans_static_method_callee: method_id={:?}, expr_id={:?}, \ name={}", method_id, expr_id, token::get_name(mname)); - let vtbls = ccx.maps.vtable_map.borrow().get_copy(&expr_id); + let vtable_key = MethodCall::expr(expr_id); + let vtbls = ccx.maps.vtable_map.borrow().get_copy(&vtable_key); let vtbls = resolve_vtables_in_fn_ctxt(bcx.fcx, vtbls); match vtbls.get(bound_index).get(0) { @@ -327,16 +328,11 @@ fn combine_impl_and_methods_tps(bcx: &Block, // Now, do the same work for the vtables. The vtables might not // exist, in which case we need to make them. - let vtables = match node { - ExprId(id) => node_vtables(bcx, id), - MethodCall(method_call) => { - if method_call.autoderef == 0 { - node_vtables(bcx, method_call.expr_id) - } else { - None - } - } + let vtable_key = match node { + ExprId(id) => MethodCall::expr(id), + MethodCall(method_call) => method_call }; + let vtables = node_vtables(bcx, vtable_key); let r_m_origins = match vtables { Some(vt) => vt, None => @Vec::from_elem(node_substs.len(), @Vec::new()) @@ -597,10 +593,8 @@ pub fn trans_trait_cast<'a>(bcx: &'a Block<'a>, bcx = datum.store_to(bcx, llboxdest); // Store the vtable into the second half of pair. - // This is structured a bit funny because of dynamic borrow failures. - let res = *ccx.maps.vtable_map.borrow().get(&id); - let res = resolve_vtables_in_fn_ctxt(bcx.fcx, res); - let origins = *res.get(0); + let res = *ccx.maps.vtable_map.borrow().get(&MethodCall::expr(id)); + let origins = *resolve_vtables_in_fn_ctxt(bcx.fcx, res).get(0); let vtable = get_vtable(bcx, v_ty, origins); let llvtabledest = GEPi(bcx, lldest, [0u, abi::trt_field_vtable]); let llvtabledest = PointerCast(bcx, llvtabledest, val_ty(vtable).ptr_to()); diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs index d4fd8d439273..2410390b5e74 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc/middle/typeck/check/mod.rs @@ -267,7 +267,7 @@ impl<'a> Inherited<'a> { node_type_substs: RefCell::new(NodeMap::new()), adjustments: RefCell::new(NodeMap::new()), method_map: @RefCell::new(FnvHashMap::new()), - vtable_map: @RefCell::new(NodeMap::new()), + vtable_map: @RefCell::new(FnvHashMap::new()), upvar_borrow_map: RefCell::new(HashMap::new()), } } diff --git a/src/librustc/middle/typeck/check/vtable.rs b/src/librustc/middle/typeck/check/vtable.rs index 29f481f9c04d..15de3bf2b5f8 100644 --- a/src/librustc/middle/typeck/check/vtable.rs +++ b/src/librustc/middle/typeck/check/vtable.rs @@ -516,10 +516,10 @@ fn connect_trait_tps(vcx: &VtableContext, relate_trait_refs(vcx, span, impl_trait_ref, trait_ref); } -fn insert_vtables(fcx: &FnCtxt, expr_id: ast::NodeId, vtables: vtable_res) { - debug!("insert_vtables(expr_id={}, vtables={:?})", - expr_id, vtables.repr(fcx.tcx())); - fcx.inh.vtable_map.borrow_mut().insert(expr_id, vtables); +fn insert_vtables(fcx: &FnCtxt, vtable_key: MethodCall, vtables: vtable_res) { + debug!("insert_vtables(vtable_key={}, vtables={:?})", + vtable_key, vtables.repr(fcx.tcx())); + fcx.inh.vtable_map.borrow_mut().insert(vtable_key, vtables); } pub fn early_resolve_expr(ex: &ast::Expr, fcx: &FnCtxt, is_early: bool) { @@ -591,7 +591,7 @@ pub fn early_resolve_expr(ex: &ast::Expr, fcx: &FnCtxt, is_early: bool) { is_early); if !is_early { - insert_vtables(fcx, ex.id, @vec!(vtables)); + insert_vtables(fcx, MethodCall::expr(ex.id), @vec!(vtables)); } // Now, if this is &trait, we need to link the @@ -648,7 +648,7 @@ pub fn early_resolve_expr(ex: &ast::Expr, fcx: &FnCtxt, is_early: bool) { item_ty.generics.type_param_defs(), substs, is_early); if !is_early { - insert_vtables(fcx, ex.id, vtbls); + insert_vtables(fcx, MethodCall::expr(ex.id), vtbls); } } true @@ -673,7 +673,7 @@ pub fn early_resolve_expr(ex: &ast::Expr, fcx: &FnCtxt, is_early: bool) { type_param_defs.as_slice(), &substs, is_early); if !is_early { - insert_vtables(fcx, ex.id, vtbls); + insert_vtables(fcx, MethodCall::expr(ex.id), vtbls); } } } @@ -692,6 +692,30 @@ pub fn early_resolve_expr(ex: &ast::Expr, fcx: &FnCtxt, is_early: bool) { match fcx.inh.adjustments.borrow().find(&ex.id) { Some(adjustment) => { match **adjustment { + AutoDerefRef(adj) => { + for autoderef in range(0, adj.autoderefs) { + let method_call = MethodCall::autoderef(ex.id, autoderef as u32); + match fcx.inh.method_map.borrow().find(&method_call) { + Some(method) => { + debug!("vtable resolution on parameter bounds for autoderef {}", + ex.repr(fcx.tcx())); + let type_param_defs = + ty::method_call_type_param_defs(cx.tcx, method.origin); + if has_trait_bounds(type_param_defs.deref().as_slice()) { + let vcx = fcx.vtable_context(); + let vtbls = lookup_vtables(&vcx, ex.span, + type_param_defs.deref() + .as_slice(), + &method.substs, is_early); + if !is_early { + insert_vtables(fcx, method_call, vtbls); + } + } + } + None => {} + } + } + } AutoObject(ref sigil, ref region, m, @@ -713,7 +737,7 @@ pub fn early_resolve_expr(ex: &ast::Expr, fcx: &FnCtxt, is_early: bool) { b); resolve_object_cast(ex, object_ty); } - AutoAddEnv(..) | AutoDerefRef(..) => {} + AutoAddEnv(..) => {} } } None => {} diff --git a/src/librustc/middle/typeck/check/writeback.rs b/src/librustc/middle/typeck/check/writeback.rs index 688baa18c95d..31d74a1e938a 100644 --- a/src/librustc/middle/typeck/check/writeback.rs +++ b/src/librustc/middle/typeck/check/writeback.rs @@ -21,8 +21,7 @@ use middle::typeck::infer::{force_all, resolve_all, resolve_region}; use middle::typeck::infer::resolve_type; use middle::typeck::infer; use middle::typeck::{MethodCall, MethodCallee}; -use middle::typeck::{vtable_res, vtable_origin}; -use middle::typeck::{vtable_static, vtable_param}; +use middle::typeck::{vtable_res, vtable_static, vtable_param}; use middle::typeck::write_substs_to_tcx; use middle::typeck::write_ty_to_tcx; use util::ppaux; @@ -100,38 +99,34 @@ fn resolve_method_map_entry(wbcx: &mut WbCtxt, sp: Span, method_call: MethodCall } } -fn resolve_vtable_map_entry(fcx: &FnCtxt, sp: Span, id: ast::NodeId) { +fn resolve_vtable_map_entry(fcx: &FnCtxt, sp: Span, vtable_key: MethodCall) { // Resolve any vtable map entry - match fcx.inh.vtable_map.borrow().find_copy(&id) { + match fcx.inh.vtable_map.borrow().find_copy(&vtable_key) { Some(origins) => { let r_origins = resolve_origins(fcx, sp, origins); - fcx.ccx.vtable_map.borrow_mut().insert(id, r_origins); - debug!("writeback::resolve_vtable_map_entry(id={}, vtables={:?})", - id, r_origins.repr(fcx.tcx())); + fcx.ccx.vtable_map.borrow_mut().insert(vtable_key, r_origins); + debug!("writeback::resolve_vtable_map_entry(vtable_key={}, vtables={:?})", + vtable_key, r_origins.repr(fcx.tcx())); } None => {} } fn resolve_origins(fcx: &FnCtxt, sp: Span, vtbls: vtable_res) -> vtable_res { - @vtbls.map(|os| @os.map(|o| resolve_origin(fcx, sp, o))) - } - - fn resolve_origin(fcx: &FnCtxt, - sp: Span, - origin: &vtable_origin) -> vtable_origin { - match origin { - &vtable_static(def_id, ref tys, origins) => { - let r_tys = resolve_type_vars_in_types(fcx, - sp, - tys.as_slice()); - let r_origins = resolve_origins(fcx, sp, origins); - vtable_static(def_id, r_tys, r_origins) + @vtbls.map(|os| @os.map(|origin| { + match origin { + &vtable_static(def_id, ref tys, origins) => { + let r_tys = resolve_type_vars_in_types(fcx, + sp, + tys.as_slice()); + let r_origins = resolve_origins(fcx, sp, origins); + vtable_static(def_id, r_tys, r_origins) + } + &vtable_param(n, b) => { + vtable_param(n, b) + } } - &vtable_param(n, b) => { - vtable_param(n, b) - } - } + })) } } @@ -183,6 +178,7 @@ fn resolve_type_vars_for_node(wbcx: &mut WbCtxt, sp: Span, id: ast::NodeId) for autoderef in range(0, adj.autoderefs) { let method_call = MethodCall::autoderef(id, autoderef as u32); resolve_method_map_entry(wbcx, sp, method_call); + resolve_vtable_map_entry(wbcx.fcx, sp, method_call); } let fixup_region = |r| { @@ -273,7 +269,7 @@ fn visit_expr(e: &ast::Expr, wbcx: &mut WbCtxt) { resolve_type_vars_for_node(wbcx, e.span, e.id); resolve_method_map_entry(wbcx, e.span, MethodCall::expr(e.id)); - resolve_vtable_map_entry(wbcx.fcx, e.span, e.id); + resolve_vtable_map_entry(wbcx.fcx, e.span, MethodCall::expr(e.id)); match e.node { ast::ExprFnBlock(ref decl, _) | ast::ExprProc(ref decl, _) => { diff --git a/src/librustc/middle/typeck/mod.rs b/src/librustc/middle/typeck/mod.rs index 22881b26f63e..b33819ff7f46 100644 --- a/src/librustc/middle/typeck/mod.rs +++ b/src/librustc/middle/typeck/mod.rs @@ -68,7 +68,7 @@ use middle::ty; use util::common::time; use util::ppaux::Repr; use util::ppaux; -use util::nodemap::{DefIdMap, FnvHashMap, NodeMap}; +use util::nodemap::{DefIdMap, FnvHashMap}; use std::cell::RefCell; use std::rc::Rc; @@ -148,7 +148,7 @@ pub struct MethodCallee { substs: ty::substs } -#[deriving(Clone, Eq, Hash)] +#[deriving(Clone, Eq, Hash, Show)] pub struct MethodCall { expr_id: ast::NodeId, autoderef: u32 @@ -216,7 +216,7 @@ impl Repr for vtable_origin { } } -pub type vtable_map = @RefCell>; +pub type vtable_map = @RefCell>; // Information about the vtable resolutions for a trait impl. @@ -461,7 +461,7 @@ pub fn check_crate(tcx: &ty::ctxt, let ccx = CrateCtxt { trait_map: trait_map, method_map: @RefCell::new(FnvHashMap::new()), - vtable_map: @RefCell::new(NodeMap::new()), + vtable_map: @RefCell::new(FnvHashMap::new()), tcx: tcx }; diff --git a/src/test/run-pass/overloaded-autoderef-vtable.rs b/src/test/run-pass/overloaded-autoderef-vtable.rs new file mode 100644 index 000000000000..15b5cca9cf83 --- /dev/null +++ b/src/test/run-pass/overloaded-autoderef-vtable.rs @@ -0,0 +1,42 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::ops::Deref; + +struct DerefWithHelper { + helper: H +} + +trait Helper { + fn helper_borrow<'a>(&'a self) -> &'a T; +} + +impl Helper for Option { + fn helper_borrow<'a>(&'a self) -> &'a T { + self.as_ref().unwrap() + } +} + +impl> Deref for DerefWithHelper { + fn deref<'a>(&'a self) -> &'a T { + self.helper.helper_borrow() + } +} + +struct Foo {x: int} + +impl Foo { + fn foo(&self) -> int {self.x} +} + +pub fn main() { + let x: DerefWithHelper, Foo> = DerefWithHelper { helper: Some(Foo {x: 5}) }; + assert!(x.foo() == 5); +}