Skip to content

Commit fe2f3d2

Browse files
committed
Further work on default methods in traits.
And some trait-related code cleanup in typeck::collect.
1 parent a98407e commit fe2f3d2

File tree

1 file changed

+63
-40
lines changed

1 file changed

+63
-40
lines changed

src/rustc/middle/typeck/collect.rs

Lines changed: 63 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -177,33 +177,33 @@ fn ensure_trait_methods(ccx: @crate_ctxt, id: ast::node_id) {
177177
*
178178
* - impl_m: the method in the impl
179179
* - impl_tps: the type params declared on the impl itself (not the method!)
180-
* - if_m: the method in the trait
181-
* - if_substs: the substitutions used on the type of the trait
180+
* - trait_m: the method in the trait
181+
* - trait_substs: the substitutions used on the type of the trait
182182
* - self_ty: the self type of the impl
183183
*/
184184
fn compare_impl_method(tcx: ty::ctxt, sp: span,
185185
impl_m: ty::method, impl_tps: uint,
186-
if_m: ty::method, if_substs: ty::substs,
186+
trait_m: ty::method, trait_substs: ty::substs,
187187
self_ty: ty::t) {
188188

189-
if impl_m.tps != if_m.tps {
190-
tcx.sess.span_err(sp, ~"method `" + *if_m.ident +
189+
if impl_m.tps != trait_m.tps {
190+
tcx.sess.span_err(sp, ~"method `" + *trait_m.ident +
191191
~"` has an incompatible set of type parameters");
192192
return;
193193
}
194194

195-
if vec::len(impl_m.fty.inputs) != vec::len(if_m.fty.inputs) {
195+
if vec::len(impl_m.fty.inputs) != vec::len(trait_m.fty.inputs) {
196196
tcx.sess.span_err(sp,fmt!{"method `%s` has %u parameters \
197197
but the trait has %u",
198-
*if_m.ident,
198+
*trait_m.ident,
199199
vec::len(impl_m.fty.inputs),
200-
vec::len(if_m.fty.inputs)});
200+
vec::len(trait_m.fty.inputs)});
201201
return;
202202
}
203203

204204
// Perform substitutions so that the trait/impl methods are expressed
205205
// in terms of the same set of type/region parameters:
206-
// - replace trait type parameters with those from `if_substs`
206+
// - replace trait type parameters with those from `trait_substs`
207207
// - replace method parameters on the trait with fresh, dummy parameters
208208
// that correspond to the parameters we will find on the impl
209209
// - replace self region with a fresh, dummy region
@@ -212,23 +212,23 @@ fn compare_impl_method(tcx: ty::ctxt, sp: span,
212212
let impl_fty = ty::mk_fn(tcx, impl_m.fty);
213213
replace_bound_self(tcx, impl_fty, dummy_self_r)
214214
};
215-
let if_fty = {
216-
let dummy_tps = do vec::from_fn((*if_m.tps).len()) |i| {
215+
let trait_fty = {
216+
let dummy_tps = do vec::from_fn((*trait_m.tps).len()) |i| {
217217
// hack: we don't know the def id of the impl tp, but it
218218
// is not important for unification
219219
ty::mk_param(tcx, i + impl_tps, {crate: 0, node: 0})
220220
};
221221
let substs = {
222222
self_r: some(dummy_self_r),
223223
self_ty: some(self_ty),
224-
tps: vec::append(if_substs.tps, dummy_tps)
224+
tps: vec::append(trait_substs.tps, dummy_tps)
225225
};
226-
let if_fty = ty::mk_fn(tcx, if_m.fty);
227-
ty::subst(tcx, substs, if_fty)
226+
let trait_fty = ty::mk_fn(tcx, trait_m.fty);
227+
ty::subst(tcx, substs, trait_fty)
228228
};
229229
require_same_types(
230-
tcx, none, sp, impl_fty, if_fty,
231-
|| ~"method `" + *if_m.ident + ~"` has an incompatible type");
230+
tcx, none, sp, impl_fty, trait_fty,
231+
|| ~"method `" + *trait_m.ident + ~"` has an incompatible type");
232232
return;
233233

234234
// Replaces bound references to the self region with `with_r`.
@@ -245,36 +245,59 @@ fn check_methods_against_trait(ccx: @crate_ctxt,
245245
rp: bool,
246246
selfty: ty::t,
247247
a_trait_ty: @ast::trait_ref,
248-
ms: ~[converted_method]) {
248+
impl_ms: ~[converted_method]) {
249249

250250
let tcx = ccx.tcx;
251251
let (did, tpt) = instantiate_trait_ref(ccx, a_trait_ty, rp);
252252
if did.crate == ast::local_crate {
253253
ensure_trait_methods(ccx, did.node);
254254
}
255-
for vec::each(*ty::trait_methods(tcx, did)) |if_m| {
256-
alt vec::find(ms, |m| if_m.ident == m.mty.ident) {
257-
some({mty: m, id, span}) {
258-
if m.purity != if_m.purity {
255+
for vec::each(*ty::trait_methods(tcx, did)) |trait_m| {
256+
alt vec::find(impl_ms, |impl_m| trait_m.ident == impl_m.mty.ident) {
257+
some({mty: impl_m, id, span}) {
258+
if impl_m.purity != trait_m.purity {
259259
ccx.tcx.sess.span_err(
260260
span, fmt!{"method `%s`'s purity does \
261261
not match the trait method's \
262-
purity", *m.ident});
262+
purity", *impl_m.ident});
263263
}
264264
compare_impl_method(
265-
ccx.tcx, span, m, vec::len(tps),
266-
if_m, tpt.substs, selfty);
265+
ccx.tcx, span, impl_m, vec::len(tps),
266+
trait_m, tpt.substs, selfty);
267267
}
268268
none {
269-
// FIXME (#2794): if there's a default impl in the trait,
270-
// use that.
271-
272-
tcx.sess.span_err(
273-
a_trait_ty.path.span,
274-
fmt!{"missing method `%s`", *if_m.ident});
269+
// If we couldn't find an implementation for trait_m in
270+
// the impl, then see if there was a default
271+
// implementation in the trait itself. If not, raise a
272+
// "missing method" error.
273+
274+
alt tcx.items.get(did.node) {
275+
ast_map::node_item(
276+
@{node: ast::item_trait(_, _, trait_methods), _}, _) {
277+
let (_, provided_methods) =
278+
split_trait_methods(trait_methods);
279+
280+
alt vec::find(provided_methods, |provided_method|
281+
provided_method.ident == trait_m.ident) {
282+
some(m) {
283+
// If there's a provided method with the name we
284+
// want, then we're fine; nothing else to do.
285+
}
286+
none {
287+
tcx.sess.span_err(
288+
a_trait_ty.path.span,
289+
fmt!{"missing method `%s`", *trait_m.ident});
290+
}
291+
}
292+
}
293+
_ {
294+
tcx.sess.bug(~"check_methods_against_trait(): trait_ref \
295+
didn't refer to a trait");
296+
}
297+
}
275298
}
276299
} // alt
277-
} // |if_m|
300+
} // |trait_m|
278301
} // fn
279302

280303
fn convert_field(ccx: @crate_ctxt,
@@ -324,7 +347,7 @@ fn convert(ccx: @crate_ctxt, it: @ast::item) {
324347
write_ty_to_tcx(tcx, it.id, tpt.ty);
325348
get_enum_variant_types(ccx, tpt.ty, variants, ty_params, rp);
326349
}
327-
ast::item_impl(tps, trt, selfty, ms) {
350+
ast::item_impl(tps, trait_ref, selfty, ms) {
328351
let i_bounds = ty_param_bounds(ccx, tps);
329352
let selfty = ccx.to_ty(type_rscope(rp), selfty);
330353
write_ty_to_tcx(tcx, it.id, selfty);
@@ -334,7 +357,7 @@ fn convert(ccx: @crate_ctxt, it: @ast::item) {
334357
ty: selfty});
335358

336359
let cms = convert_methods(ccx, ms, rp, i_bounds, selfty);
337-
for trt.each |t| {
360+
for trait_ref.each |t| {
338361
check_methods_against_trait(ccx, tps, rp, selfty, t, cms);
339362
}
340363
}
@@ -351,11 +374,11 @@ fn convert(ccx: @crate_ctxt, it: @ast::item) {
351374
let _cms = convert_methods(ccx, provided_methods, rp, bounds, selfty);
352375
// FIXME (#2616): something like this, when we start having
353376
// trait inheritance?
354-
// for trt.each |t| {
377+
// for trait_ref.each |t| {
355378
// check_methods_against_trait(ccx, tps, rp, selfty, t, cms);
356379
// }
357380
}
358-
ast::item_class(tps, traits, members, m_ctor, m_dtor) {
381+
ast::item_class(tps, trait_refs, members, m_ctor, m_dtor) {
359382
// Write the class type
360383
let tpt = ty_of_item(ccx, it);
361384
write_ty_to_tcx(tcx, it.id, tpt.ty);
@@ -405,11 +428,11 @@ fn convert(ccx: @crate_ctxt, it: @ast::item) {
405428
let {bounds, substs} = mk_substs(ccx, tps, rp);
406429
let selfty = ty::mk_class(tcx, local_def(it.id), substs);
407430
let cms = convert_methods(ccx, methods, rp, bounds, selfty);
408-
for traits.each |trt| {
409-
check_methods_against_trait(ccx, tps, rp, selfty, trt, cms);
410-
// trt.impl_id represents (class, trait) pair
411-
write_ty_to_tcx(tcx, trt.impl_id, tpt.ty);
412-
tcx.tcache.insert(local_def(trt.impl_id), tpt);
431+
for trait_refs.each |trait_ref| {
432+
check_methods_against_trait(ccx, tps, rp, selfty, trait_ref, cms);
433+
// trait_ref.impl_id represents (class, trait) pair
434+
write_ty_to_tcx(tcx, trait_ref.impl_id, tpt.ty);
435+
tcx.tcache.insert(local_def(trait_ref.impl_id), tpt);
413436
}
414437
}
415438
_ {

0 commit comments

Comments
 (0)