Skip to content

Commit 449f4fb

Browse files
committed
rustc: Implement deriving involving generic bounded traits. r=brson
1 parent be93b29 commit 449f4fb

File tree

5 files changed

+180
-36
lines changed

5 files changed

+180
-36
lines changed

src/rustc/middle/trans/callee.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ fn trans_fn_ref_with_vtables_to_callee(bcx: block,
153153
fn trans_fn_ref_with_vtables(
154154
bcx: block, //
155155
def_id: ast::def_id, // def id of fn
156-
ref_id: ast::node_id, // node id of use of fn
156+
ref_id: ast::node_id, // node id of use of fn; may be zero if N/A
157157
type_params: ~[ty::t], // values for fn's ty params
158158
vtables: Option<typeck::vtable_res>)
159159
-> FnData

src/rustc/middle/trans/deriving.rs

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ use middle::trans::common;
1313
use middle::trans::common::{C_bool, C_int, T_ptr, block, crate_ctxt};
1414
use middle::trans::expr::SaveIn;
1515
use middle::trans::type_of::type_of;
16-
use middle::typeck::{method_origin, method_static};
16+
use middle::ty::DerivedFieldInfo;
17+
use middle::typeck::method_static;
1718
use syntax::ast;
1819
use syntax::ast::{def_id, ident, node_id, ty_param};
1920
use syntax::ast_map::path;
@@ -229,23 +230,37 @@ fn trans_deriving_enum_method(ccx: @crate_ctxt, llfn: ValueRef,
229230
}
230231

231232
fn call_substructure_method(bcx: block,
232-
derived_method_info: &method_origin,
233+
derived_field_info: &DerivedFieldInfo,
233234
self_ty: ty::t,
234235
llselfval: ValueRef,
235236
llotherval: ValueRef) -> block {
236237
let fcx = bcx.fcx;
237238
let ccx = fcx.ccx;
238239

239240
let target_method_def_id;
240-
match *derived_method_info {
241+
match derived_field_info.method_origin {
241242
method_static(did) => target_method_def_id = did,
242243
_ => fail ~"derived method didn't resolve to a static method"
243244
}
244245

245-
let fn_expr_ty = ty::lookup_item_type(ccx.tcx, target_method_def_id).ty;
246+
let fn_expr_tpbt = ty::lookup_item_type(ccx.tcx, target_method_def_id);
247+
debug!("(calling substructure method) substructure method has %u \
248+
parameter(s), vtable result is %?",
249+
fn_expr_tpbt.bounds.len(),
250+
derived_field_info.vtable_result);
251+
252+
// Get the substructure method we need to call. This may involve
253+
// code generation in the case of generics, default methods, or cross-
254+
// crate inlining.
255+
let fn_data = callee::trans_fn_ref_with_vtables(bcx,
256+
target_method_def_id,
257+
0, // ref id
258+
*derived_field_info.
259+
type_parameter_substitutions,
260+
derived_field_info.
261+
vtable_result);
262+
let llfn = fn_data.llfn;
246263

247-
// XXX: Cross-crate won't work!
248-
let llfn = get_item_val(ccx, target_method_def_id.node);
249264
let cb: &fn(block) -> Callee = |block| {
250265
Callee {
251266
bcx: block,
@@ -260,7 +275,7 @@ fn call_substructure_method(bcx: block,
260275

261276
callee::trans_call_inner(bcx,
262277
None,
263-
fn_expr_ty,
278+
fn_expr_tpbt.ty,
264279
ty::mk_bool(ccx.tcx),
265280
cb,
266281
ArgVals(~[llotherval]),

src/rustc/middle/ty.rs

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,7 @@ export trait_supertraits;
203203
export AutoAdjustment;
204204
export AutoRef, AutoRefKind, AutoSlice, AutoPtr;
205205
export DerivedMethodInfo;
206+
export DerivedFieldInfo;
206207

207208
// Data types
208209

@@ -341,6 +342,12 @@ struct DerivedMethodInfo {
341342
containing_impl: ast::def_id
342343
}
343344

345+
struct DerivedFieldInfo {
346+
method_origin: typeck::method_origin,
347+
type_parameter_substitutions: @~[ty::t],
348+
vtable_result: Option<typeck::vtable_res>
349+
}
350+
344351
type ctxt =
345352
@{diag: syntax::diagnostic::span_handler,
346353
interner: HashMap<intern_key, t_box>,
@@ -386,13 +393,11 @@ type ctxt =
386393
legacy_boxed_traits: HashMap<node_id, ()>,
387394
provided_method_sources: HashMap<ast::def_id, ProvidedMethodSource>,
388395
supertraits: HashMap<ast::def_id, @~[InstantiatedTraitRef]>,
389-
deriving_struct_methods: HashMap<ast::def_id,
390-
@~[typeck::method_origin]>,
396+
deriving_struct_methods: HashMap<ast::def_id, @~[DerivedFieldInfo]>,
391397

392398
// The outer vector here describes each enum variant, while the inner
393399
// nested vector describes each enum variant argument.
394-
deriving_enum_methods: HashMap<ast::def_id,
395-
@~[@~[typeck::method_origin]]>,
400+
deriving_enum_methods: HashMap<ast::def_id, @~[@~[DerivedFieldInfo]]>,
396401

397402
// A mapping from the def ID of a method that was automatically derived
398403
// to information about it.

src/rustc/middle/typeck/deriving.rs

Lines changed: 115 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -11,47 +11,112 @@ use syntax::ast::item_impl;
1111
use syntax::ast::node_id;
1212
use syntax::ast::self_ty_;
1313
use syntax::ast::trait_ref;
14-
use syntax::ast_util::def_id_of_def;
14+
use syntax::ast_util::{def_id_of_def, dummy_sp};
1515
use syntax::codemap::span;
1616
use syntax::print::pprust;
1717
use syntax::visit::{default_simple_visitor, mk_simple_visitor, visit_crate};
1818
use middle::resolve::{Impl, MethodInfo};
1919
use middle::ty;
20-
use middle::ty::{substs, ty_class, ty_enum, ty_param_bounds_and_ty};
20+
use middle::ty::{DerivedFieldInfo, substs, ty_class, ty_enum};
21+
use middle::ty::{ty_param_bounds_and_ty};
2122
use /*middle::typeck::*/check::method;
23+
use /*middle::typeck::*/check::vtable;
2224
use /*middle::typeck::*/infer::infer_ctxt;
25+
use /*middle::typeck::*/vtable::{LocationInfo, VtableContext};
26+
use util::ppaux;
27+
28+
struct MethodMatch {
29+
method_def_id: def_id,
30+
type_parameter_substitutions: @~[ty::t],
31+
vtable_result: Option<vtable_res>
32+
}
2333

2434
struct DerivingChecker {
25-
crate_context: @crate_ctxt,
26-
inference_context: infer_ctxt
35+
crate_context: @crate_ctxt
2736
}
2837

2938
fn DerivingChecker_new(crate_context: @crate_ctxt) -> DerivingChecker {
3039
DerivingChecker {
3140
crate_context: crate_context,
32-
inference_context: infer::new_infer_ctxt(crate_context.tcx)
3341
}
3442
}
3543

44+
struct TyParamSubstsAndVtableResult {
45+
type_parameter_substitutions: @~[ty::t],
46+
vtable_result: Option<vtable_res>
47+
}
48+
3649
impl DerivingChecker {
3750
/// Matches one substructure type against an implementation.
3851
fn match_impl_method(impl_info: @Impl,
3952
substructure_type: ty::t,
40-
method_info: @MethodInfo) -> bool {
41-
// XXX: Generics and regions are not handled properly.
53+
method_info: @MethodInfo,
54+
span: span) ->
55+
Option<TyParamSubstsAndVtableResult> {
4256
let tcx = self.crate_context.tcx;
43-
let impl_self_ty = ty::lookup_item_type(tcx, impl_info.did).ty;
57+
58+
let impl_self_tpbt = ty::lookup_item_type(tcx, impl_info.did);
4459
let transformed_type = method::transform_self_type_for_method(
45-
tcx, None, impl_self_ty, method_info.self_type);
46-
return infer::can_mk_subty(self.inference_context,
47-
substructure_type,
48-
transformed_type).is_ok();
60+
tcx, None, impl_self_tpbt.ty, method_info.self_type);
61+
62+
let inference_context = infer::new_infer_ctxt(self.crate_context.tcx);
63+
let substs = {
64+
self_r: None,
65+
self_ty: None,
66+
tps: inference_context.next_ty_vars(impl_self_tpbt.bounds.len())
67+
};
68+
let transformed_type = ty::subst(
69+
self.crate_context.tcx, &substs, transformed_type);
70+
71+
debug!("(matching impl method) substructure type %s, transformed \
72+
type %s, subst tps %u",
73+
ppaux::ty_to_str(self.crate_context.tcx, substructure_type),
74+
ppaux::ty_to_str(self.crate_context.tcx, transformed_type),
75+
substs.tps.len());
76+
77+
if !infer::mk_subty(inference_context,
78+
true,
79+
ast_util::dummy_sp(),
80+
substructure_type,
81+
transformed_type).is_ok() {
82+
return None;
83+
}
84+
85+
// Get the vtables.
86+
let vtable_result;
87+
if substs.tps.len() == 0 {
88+
vtable_result = None;
89+
} else {
90+
let vcx = VtableContext {
91+
ccx: self.crate_context,
92+
infcx: inference_context
93+
};
94+
let location_info = LocationInfo {
95+
span: span,
96+
id: impl_info.did.node
97+
};
98+
vtable_result = Some(vtable::lookup_vtables(&vcx,
99+
&location_info,
100+
impl_self_tpbt.bounds,
101+
&substs,
102+
false,
103+
false));
104+
}
105+
106+
// Extract the type parameter substitutions.
107+
let type_parameter_substitutions = @substs.tps.map(|ty_var|
108+
inference_context.resolve_type_vars_if_possible(*ty_var));
109+
110+
Some(TyParamSubstsAndVtableResult {
111+
type_parameter_substitutions: type_parameter_substitutions,
112+
vtable_result: vtable_result
113+
})
49114
}
50115

51116
fn check_deriving_for_substructure_type(substructure_type: ty::t,
52117
trait_ref: @trait_ref,
53118
impl_span: span) ->
54-
Option<def_id> {
119+
Option<MethodMatch> {
55120
let tcx = self.crate_context.tcx;
56121
let sess = tcx.sess;
57122
let coherence_info = self.crate_context.coherence_info;
@@ -64,12 +129,25 @@ impl DerivingChecker {
64129
Some(impls) => {
65130
// Try to unify each of these impls with the substructure
66131
// type.
67-
for impls.each |impl_info| {
68-
for impl_info.methods.each |method_info| {
69-
if self.match_impl_method(*impl_info,
70-
substructure_type,
71-
*method_info) {
72-
return Some(method_info.did);
132+
//
133+
// NB: Using range to avoid a recursive-use-of-dvec error.
134+
for uint::range(0, impls.len()) |i| {
135+
let impl_info = impls[i];
136+
for uint::range(0, impl_info.methods.len()) |j| {
137+
let method_info = impl_info.methods[j];
138+
match self.match_impl_method(impl_info,
139+
substructure_type,
140+
method_info,
141+
trait_ref.path.span) {
142+
Some(move result) => {
143+
return Some(MethodMatch {
144+
method_def_id: method_info.did,
145+
type_parameter_substitutions:
146+
result.type_parameter_substitutions,
147+
vtable_result: result.vtable_result
148+
});
149+
}
150+
None => {} // Continue.
73151
}
74152
}
75153
}
@@ -91,8 +169,15 @@ impl DerivingChecker {
91169
match self.check_deriving_for_substructure_type(field_type,
92170
trait_ref,
93171
impl_span) {
94-
Some(method_target_def_id) => {
95-
field_info.push(method_static(method_target_def_id));
172+
Some(method_match) => {
173+
field_info.push(DerivedFieldInfo {
174+
method_origin:
175+
method_static(method_match.method_def_id),
176+
type_parameter_substitutions:
177+
method_match.type_parameter_substitutions,
178+
vtable_result:
179+
method_match.vtable_result
180+
});
96181
}
97182
None => {
98183
let trait_str = pprust::path_to_str(
@@ -127,9 +212,15 @@ impl DerivingChecker {
127212
for enum_variant_info.args.eachi |i, variant_arg_type| {
128213
match self.check_deriving_for_substructure_type(
129214
*variant_arg_type, trait_ref, impl_span) {
130-
Some(method_target_def_id) => {
131-
variant_methods.push(method_static(
132-
method_target_def_id));
215+
Some(method_match) => {
216+
variant_methods.push(DerivedFieldInfo {
217+
method_origin:
218+
method_static(method_match.method_def_id),
219+
type_parameter_substitutions:
220+
method_match.type_parameter_substitutions,
221+
vtable_result:
222+
method_match.vtable_result
223+
});
133224
}
134225
None => {
135226
let trait_str = pprust::path_to_str(
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
trait MyEq {
2+
pure fn eq(other: &self) -> bool;
3+
}
4+
5+
impl int : MyEq {
6+
pure fn eq(other: &int) -> bool {
7+
self == *other
8+
}
9+
}
10+
11+
impl<T:MyEq> @T : MyEq {
12+
pure fn eq(other: &@T) -> bool {
13+
unsafe {
14+
io::println("@T");
15+
}
16+
(*self).eq(&**other)
17+
}
18+
}
19+
20+
struct A {
21+
x: @int,
22+
y: @int
23+
}
24+
25+
impl A : MyEq;
26+
27+
fn main() {
28+
let a = A { x: @3, y: @5 };
29+
let b = A { x: @10, y: @20 };
30+
assert a.eq(&a);
31+
assert !a.eq(&b);
32+
}
33+

0 commit comments

Comments
 (0)