Skip to content

Commit 75d7d52

Browse files
committed
Implement vtable support for autoderef.
Closes #13042.
1 parent 7e7a5e3 commit 75d7d52

File tree

10 files changed

+118
-66
lines changed

10 files changed

+118
-66
lines changed

src/librustc/middle/astencode.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -1023,7 +1023,7 @@ fn encode_side_tables_for_id(ecx: &e::EncodeContext,
10231023
})
10241024
}
10251025

1026-
for &dr in maps.vtable_map.borrow().find(&id).iter() {
1026+
for &dr in maps.vtable_map.borrow().find(&method_call).iter() {
10271027
ebml_w.tag(c::tag_table_vtable_map, |ebml_w| {
10281028
ebml_w.id(id);
10291029
ebml_w.tag(c::tag_table_val, |ebml_w| {
@@ -1344,7 +1344,8 @@ fn decode_side_tables(xcx: &ExtendedDecodeContext,
13441344
let vtable_res =
13451345
val_dsr.read_vtable_res(xcx.dcx.tcx,
13461346
xcx.dcx.cdata);
1347-
dcx.maps.vtable_map.borrow_mut().insert(id, vtable_res);
1347+
let vtable_key = MethodCall::expr(id);
1348+
dcx.maps.vtable_map.borrow_mut().insert(vtable_key, vtable_res);
13481349
}
13491350
c::tag_table_adjustments => {
13501351
let adj: @ty::AutoAdjustment = @val_dsr.read_auto_adjustment(xcx);

src/librustc/middle/const_eval.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ pub fn lookup_variant_by_id(tcx: &ty::ctxt,
129129
let maps = astencode::Maps {
130130
root_map: @RefCell::new(HashMap::new()),
131131
method_map: @RefCell::new(FnvHashMap::new()),
132-
vtable_map: @RefCell::new(NodeMap::new()),
132+
vtable_map: @RefCell::new(FnvHashMap::new()),
133133
capture_map: RefCell::new(NodeMap::new())
134134
};
135135
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)
170170
let maps = astencode::Maps {
171171
root_map: @RefCell::new(HashMap::new()),
172172
method_map: @RefCell::new(FnvHashMap::new()),
173-
vtable_map: @RefCell::new(NodeMap::new()),
173+
vtable_map: @RefCell::new(FnvHashMap::new()),
174174
capture_map: RefCell::new(NodeMap::new())
175175
};
176176
let e = match csearch::maybe_get_item_ast(tcx, def_id,

src/librustc/middle/trans/callee.rs

+4-9
Original file line numberDiff line numberDiff line change
@@ -170,16 +170,11 @@ pub fn trans_fn_ref(bcx: &Block, def_id: ast::DefId, node: ExprOrMethodCall) ->
170170
let _icx = push_ctxt("trans_fn_ref");
171171

172172
let type_params = node_id_type_params(bcx, node);
173-
let vtables = match node {
174-
ExprId(id) => node_vtables(bcx, id),
175-
MethodCall(ref method_call) => {
176-
if method_call.autoderef == 0 {
177-
node_vtables(bcx, method_call.expr_id)
178-
} else {
179-
None
180-
}
181-
}
173+
let vtable_key = match node {
174+
ExprId(id) => MethodCall::expr(id),
175+
MethodCall(method_call) => method_call
182176
};
177+
let vtables = node_vtables(bcx, vtable_key);
183178
debug!("trans_fn_ref(def_id={}, node={:?}, type_params={}, vtables={})",
184179
def_id.repr(bcx.tcx()), node, type_params.repr(bcx.tcx()),
185180
vtables.repr(bcx.tcx()));

src/librustc/middle/trans/common.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -829,7 +829,7 @@ pub fn node_id_type_params(bcx: &Block, node: ExprOrMethodCall) -> Vec<ty::t> {
829829
}
830830
}
831831

832-
pub fn node_vtables(bcx: &Block, id: ast::NodeId)
832+
pub fn node_vtables(bcx: &Block, id: typeck::MethodCall)
833833
-> Option<typeck::vtable_res> {
834834
let vtable_map = bcx.ccx().maps.vtable_map.borrow();
835835
let raw_vtables = vtable_map.find(&id);

src/librustc/middle/trans/meth.rs

+8-14
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,8 @@ pub fn trans_static_method_callee(bcx: &Block,
208208
debug!("trans_static_method_callee: method_id={:?}, expr_id={:?}, \
209209
name={}", method_id, expr_id, token::get_name(mname));
210210

211-
let vtbls = ccx.maps.vtable_map.borrow().get_copy(&expr_id);
211+
let vtable_key = MethodCall::expr(expr_id);
212+
let vtbls = ccx.maps.vtable_map.borrow().get_copy(&vtable_key);
212213
let vtbls = resolve_vtables_in_fn_ctxt(bcx.fcx, vtbls);
213214

214215
match vtbls.get(bound_index).get(0) {
@@ -327,16 +328,11 @@ fn combine_impl_and_methods_tps(bcx: &Block,
327328

328329
// Now, do the same work for the vtables. The vtables might not
329330
// exist, in which case we need to make them.
330-
let vtables = match node {
331-
ExprId(id) => node_vtables(bcx, id),
332-
MethodCall(method_call) => {
333-
if method_call.autoderef == 0 {
334-
node_vtables(bcx, method_call.expr_id)
335-
} else {
336-
None
337-
}
338-
}
331+
let vtable_key = match node {
332+
ExprId(id) => MethodCall::expr(id),
333+
MethodCall(method_call) => method_call
339334
};
335+
let vtables = node_vtables(bcx, vtable_key);
340336
let r_m_origins = match vtables {
341337
Some(vt) => vt,
342338
None => @Vec::from_elem(node_substs.len(), @Vec::new())
@@ -597,10 +593,8 @@ pub fn trans_trait_cast<'a>(bcx: &'a Block<'a>,
597593
bcx = datum.store_to(bcx, llboxdest);
598594

599595
// Store the vtable into the second half of pair.
600-
// This is structured a bit funny because of dynamic borrow failures.
601-
let res = *ccx.maps.vtable_map.borrow().get(&id);
602-
let res = resolve_vtables_in_fn_ctxt(bcx.fcx, res);
603-
let origins = *res.get(0);
596+
let res = *ccx.maps.vtable_map.borrow().get(&MethodCall::expr(id));
597+
let origins = *resolve_vtables_in_fn_ctxt(bcx.fcx, res).get(0);
604598
let vtable = get_vtable(bcx, v_ty, origins);
605599
let llvtabledest = GEPi(bcx, lldest, [0u, abi::trt_field_vtable]);
606600
let llvtabledest = PointerCast(bcx, llvtabledest, val_ty(vtable).ptr_to());

src/librustc/middle/typeck/check/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -267,7 +267,7 @@ impl<'a> Inherited<'a> {
267267
node_type_substs: RefCell::new(NodeMap::new()),
268268
adjustments: RefCell::new(NodeMap::new()),
269269
method_map: @RefCell::new(FnvHashMap::new()),
270-
vtable_map: @RefCell::new(NodeMap::new()),
270+
vtable_map: @RefCell::new(FnvHashMap::new()),
271271
upvar_borrow_map: RefCell::new(HashMap::new()),
272272
}
273273
}

src/librustc/middle/typeck/check/vtable.rs

+32-8
Original file line numberDiff line numberDiff line change
@@ -516,10 +516,10 @@ fn connect_trait_tps(vcx: &VtableContext,
516516
relate_trait_refs(vcx, span, impl_trait_ref, trait_ref);
517517
}
518518

519-
fn insert_vtables(fcx: &FnCtxt, expr_id: ast::NodeId, vtables: vtable_res) {
520-
debug!("insert_vtables(expr_id={}, vtables={:?})",
521-
expr_id, vtables.repr(fcx.tcx()));
522-
fcx.inh.vtable_map.borrow_mut().insert(expr_id, vtables);
519+
fn insert_vtables(fcx: &FnCtxt, vtable_key: MethodCall, vtables: vtable_res) {
520+
debug!("insert_vtables(vtable_key={}, vtables={:?})",
521+
vtable_key, vtables.repr(fcx.tcx()));
522+
fcx.inh.vtable_map.borrow_mut().insert(vtable_key, vtables);
523523
}
524524

525525
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) {
591591
is_early);
592592

593593
if !is_early {
594-
insert_vtables(fcx, ex.id, @vec!(vtables));
594+
insert_vtables(fcx, MethodCall::expr(ex.id), @vec!(vtables));
595595
}
596596

597597
// 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) {
648648
item_ty.generics.type_param_defs(),
649649
substs, is_early);
650650
if !is_early {
651-
insert_vtables(fcx, ex.id, vtbls);
651+
insert_vtables(fcx, MethodCall::expr(ex.id), vtbls);
652652
}
653653
}
654654
true
@@ -673,7 +673,7 @@ pub fn early_resolve_expr(ex: &ast::Expr, fcx: &FnCtxt, is_early: bool) {
673673
type_param_defs.as_slice(),
674674
&substs, is_early);
675675
if !is_early {
676-
insert_vtables(fcx, ex.id, vtbls);
676+
insert_vtables(fcx, MethodCall::expr(ex.id), vtbls);
677677
}
678678
}
679679
}
@@ -692,6 +692,30 @@ pub fn early_resolve_expr(ex: &ast::Expr, fcx: &FnCtxt, is_early: bool) {
692692
match fcx.inh.adjustments.borrow().find(&ex.id) {
693693
Some(adjustment) => {
694694
match **adjustment {
695+
AutoDerefRef(adj) => {
696+
for autoderef in range(0, adj.autoderefs) {
697+
let method_call = MethodCall::autoderef(ex.id, autoderef as u32);
698+
match fcx.inh.method_map.borrow().find(&method_call) {
699+
Some(method) => {
700+
debug!("vtable resolution on parameter bounds for autoderef {}",
701+
ex.repr(fcx.tcx()));
702+
let type_param_defs =
703+
ty::method_call_type_param_defs(cx.tcx, method.origin);
704+
if has_trait_bounds(type_param_defs.deref().as_slice()) {
705+
let vcx = fcx.vtable_context();
706+
let vtbls = lookup_vtables(&vcx, ex.span,
707+
type_param_defs.deref()
708+
.as_slice(),
709+
&method.substs, is_early);
710+
if !is_early {
711+
insert_vtables(fcx, method_call, vtbls);
712+
}
713+
}
714+
}
715+
None => {}
716+
}
717+
}
718+
}
695719
AutoObject(ref sigil,
696720
ref region,
697721
m,
@@ -713,7 +737,7 @@ pub fn early_resolve_expr(ex: &ast::Expr, fcx: &FnCtxt, is_early: bool) {
713737
b);
714738
resolve_object_cast(ex, object_ty);
715739
}
716-
AutoAddEnv(..) | AutoDerefRef(..) => {}
740+
AutoAddEnv(..) => {}
717741
}
718742
}
719743
None => {}

src/librustc/middle/typeck/check/writeback.rs

+21-25
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,7 @@ use middle::typeck::infer::{force_all, resolve_all, resolve_region};
2121
use middle::typeck::infer::resolve_type;
2222
use middle::typeck::infer;
2323
use middle::typeck::{MethodCall, MethodCallee};
24-
use middle::typeck::{vtable_res, vtable_origin};
25-
use middle::typeck::{vtable_static, vtable_param};
24+
use middle::typeck::{vtable_res, vtable_static, vtable_param};
2625
use middle::typeck::write_substs_to_tcx;
2726
use middle::typeck::write_ty_to_tcx;
2827
use util::ppaux;
@@ -100,38 +99,34 @@ fn resolve_method_map_entry(wbcx: &mut WbCtxt, sp: Span, method_call: MethodCall
10099
}
101100
}
102101

103-
fn resolve_vtable_map_entry(fcx: &FnCtxt, sp: Span, id: ast::NodeId) {
102+
fn resolve_vtable_map_entry(fcx: &FnCtxt, sp: Span, vtable_key: MethodCall) {
104103
// Resolve any vtable map entry
105-
match fcx.inh.vtable_map.borrow().find_copy(&id) {
104+
match fcx.inh.vtable_map.borrow().find_copy(&vtable_key) {
106105
Some(origins) => {
107106
let r_origins = resolve_origins(fcx, sp, origins);
108-
fcx.ccx.vtable_map.borrow_mut().insert(id, r_origins);
109-
debug!("writeback::resolve_vtable_map_entry(id={}, vtables={:?})",
110-
id, r_origins.repr(fcx.tcx()));
107+
fcx.ccx.vtable_map.borrow_mut().insert(vtable_key, r_origins);
108+
debug!("writeback::resolve_vtable_map_entry(vtable_key={}, vtables={:?})",
109+
vtable_key, r_origins.repr(fcx.tcx()));
111110
}
112111
None => {}
113112
}
114113

115114
fn resolve_origins(fcx: &FnCtxt, sp: Span,
116115
vtbls: vtable_res) -> vtable_res {
117-
@vtbls.map(|os| @os.map(|o| resolve_origin(fcx, sp, o)))
118-
}
119-
120-
fn resolve_origin(fcx: &FnCtxt,
121-
sp: Span,
122-
origin: &vtable_origin) -> vtable_origin {
123-
match origin {
124-
&vtable_static(def_id, ref tys, origins) => {
125-
let r_tys = resolve_type_vars_in_types(fcx,
126-
sp,
127-
tys.as_slice());
128-
let r_origins = resolve_origins(fcx, sp, origins);
129-
vtable_static(def_id, r_tys, r_origins)
130-
}
131-
&vtable_param(n, b) => {
132-
vtable_param(n, b)
116+
@vtbls.map(|os| @os.map(|origin| {
117+
match origin {
118+
&vtable_static(def_id, ref tys, origins) => {
119+
let r_tys = resolve_type_vars_in_types(fcx,
120+
sp,
121+
tys.as_slice());
122+
let r_origins = resolve_origins(fcx, sp, origins);
123+
vtable_static(def_id, r_tys, r_origins)
124+
}
125+
&vtable_param(n, b) => {
126+
vtable_param(n, b)
127+
}
133128
}
134-
}
129+
}))
135130
}
136131
}
137132

@@ -183,6 +178,7 @@ fn resolve_type_vars_for_node(wbcx: &mut WbCtxt, sp: Span, id: ast::NodeId)
183178
for autoderef in range(0, adj.autoderefs) {
184179
let method_call = MethodCall::autoderef(id, autoderef as u32);
185180
resolve_method_map_entry(wbcx, sp, method_call);
181+
resolve_vtable_map_entry(wbcx.fcx, sp, method_call);
186182
}
187183

188184
let fixup_region = |r| {
@@ -273,7 +269,7 @@ fn visit_expr(e: &ast::Expr, wbcx: &mut WbCtxt) {
273269

274270
resolve_type_vars_for_node(wbcx, e.span, e.id);
275271
resolve_method_map_entry(wbcx, e.span, MethodCall::expr(e.id));
276-
resolve_vtable_map_entry(wbcx.fcx, e.span, e.id);
272+
resolve_vtable_map_entry(wbcx.fcx, e.span, MethodCall::expr(e.id));
277273

278274
match e.node {
279275
ast::ExprFnBlock(ref decl, _) | ast::ExprProc(ref decl, _) => {

src/librustc/middle/typeck/mod.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ use middle::ty;
6868
use util::common::time;
6969
use util::ppaux::Repr;
7070
use util::ppaux;
71-
use util::nodemap::{DefIdMap, FnvHashMap, NodeMap};
71+
use util::nodemap::{DefIdMap, FnvHashMap};
7272

7373
use std::cell::RefCell;
7474
use std::rc::Rc;
@@ -148,7 +148,7 @@ pub struct MethodCallee {
148148
substs: ty::substs
149149
}
150150

151-
#[deriving(Clone, Eq, Hash)]
151+
#[deriving(Clone, Eq, Hash, Show)]
152152
pub struct MethodCall {
153153
expr_id: ast::NodeId,
154154
autoderef: u32
@@ -216,7 +216,7 @@ impl Repr for vtable_origin {
216216
}
217217
}
218218

219-
pub type vtable_map = @RefCell<NodeMap<vtable_res>>;
219+
pub type vtable_map = @RefCell<FnvHashMap<MethodCall, vtable_res>>;
220220

221221

222222
// Information about the vtable resolutions for a trait impl.
@@ -461,7 +461,7 @@ pub fn check_crate(tcx: &ty::ctxt,
461461
let ccx = CrateCtxt {
462462
trait_map: trait_map,
463463
method_map: @RefCell::new(FnvHashMap::new()),
464-
vtable_map: @RefCell::new(NodeMap::new()),
464+
vtable_map: @RefCell::new(FnvHashMap::new()),
465465
tcx: tcx
466466
};
467467

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
use std::ops::Deref;
12+
13+
struct DerefWithHelper<H, T> {
14+
helper: H
15+
}
16+
17+
trait Helper<T> {
18+
fn helper_borrow<'a>(&'a self) -> &'a T;
19+
}
20+
21+
impl<T> Helper<T> for Option<T> {
22+
fn helper_borrow<'a>(&'a self) -> &'a T {
23+
self.as_ref().unwrap()
24+
}
25+
}
26+
27+
impl<T, H: Helper<T>> Deref<T> for DerefWithHelper<H, T> {
28+
fn deref<'a>(&'a self) -> &'a T {
29+
self.helper.helper_borrow()
30+
}
31+
}
32+
33+
struct Foo {x: int}
34+
35+
impl Foo {
36+
fn foo(&self) -> int {self.x}
37+
}
38+
39+
pub fn main() {
40+
let x: DerefWithHelper<Option<Foo>, Foo> = DerefWithHelper { helper: Some(Foo {x: 5}) };
41+
assert!(x.foo() == 5);
42+
}

0 commit comments

Comments
 (0)