Skip to content

Commit 2093952

Browse files
committed
Partial fix for rust-lang#2687---impl method must only be subtype of trait method, not exact match.
1 parent 2ab614f commit 2093952

File tree

3 files changed

+66
-14
lines changed

3 files changed

+66
-14
lines changed

src/rustc/middle/typeck/collect.rs

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -288,15 +288,10 @@ fn compare_impl_method(tcx: ty::ctxt,
288288

289289
let impl_m = &cm.mty;
290290

291-
if impl_m.fty.meta.purity != trait_m.fty.meta.purity {
292-
tcx.sess.span_err(
293-
cm.span,
294-
fmt!("method `%s`'s purity does \
295-
not match the trait method's \
296-
purity", tcx.sess.str_of(impl_m.ident)));
297-
}
298-
299-
// is this check right?
291+
// FIXME(#2687)---this check is too strict. For example, a trait
292+
// method with self type `&self` or `&mut self` should be
293+
// implementable by an `&const self` method (the impl assumes less
294+
// than the trait provides).
300295
if impl_m.self_ty != trait_m.self_ty {
301296
tcx.sess.span_err(
302297
cm.span,
@@ -328,6 +323,9 @@ fn compare_impl_method(tcx: ty::ctxt,
328323
return;
329324
}
330325
326+
// FIXME(#2687)---we should be checking that the bounds of the
327+
// trait imply the bounds of the subtype, but it appears
328+
// we are...not checking this.
331329
for trait_m.tps.eachi() |i, trait_param_bounds| {
332330
// For each of the corresponding impl ty param's bounds...
333331
let impl_param_bounds = impl_m.tps[i];
@@ -389,11 +387,19 @@ fn compare_impl_method(tcx: ty::ctxt,
389387
debug!("trait_fty (pre-subst): %s", ty_to_str(tcx, trait_fty));
390388
ty::subst(tcx, &substs, trait_fty)
391389
};
392-
debug!("trait_fty: %s", ty_to_str(tcx, trait_fty));
393-
require_same_types(
394-
tcx, None, false, cm.span, impl_fty, trait_fty,
395-
|| fmt!("method `%s` has an incompatible type",
396-
tcx.sess.str_of(trait_m.ident)));
390+
391+
let infcx = infer::new_infer_ctxt(tcx);
392+
match infer::mk_subty(infcx, false, cm.span, impl_fty, trait_fty) {
393+
result::Ok(()) => {}
394+
result::Err(ref terr) => {
395+
tcx.sess.span_err(
396+
cm.span,
397+
fmt!("method `%s` has an incompatible type: %s",
398+
tcx.sess.str_of(trait_m.ident),
399+
ty::type_err_to_str(tcx, terr)));
400+
ty::note_and_explain_type_err(tcx, terr);
401+
}
402+
}
397403
return;
398404
399405
// Replaces bound references to the self region with `with_r`.
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
trait Mumbo {
2+
pure fn jumbo(&self, x: @uint) -> uint;
3+
fn jambo(&self, x: @const uint) -> uint;
4+
fn jbmbo(&self) -> @uint;
5+
}
6+
7+
impl uint: Mumbo {
8+
// Cannot have a larger effect than the trait:
9+
fn jumbo(&self, x: @uint) { *self + *x; }
10+
//~^ ERROR expected pure fn but found impure fn
11+
12+
// Cannot accept a narrower range of parameters:
13+
fn jambo(&self, x: @uint) { *self + *x; }
14+
//~^ ERROR values differ in mutability
15+
16+
// Cannot return a wider range of values:
17+
fn jbmbo(&self) -> @const uint { @const 0 }
18+
//~^ ERROR values differ in mutability
19+
}
20+
21+
fn main() {}
22+
23+
24+
25+
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
trait Mumbo {
2+
fn jumbo(&self, x: @uint) -> uint;
3+
}
4+
5+
impl uint: Mumbo {
6+
// Note: this method def is ok, it is more accepting and
7+
// less effecting than the trait method:
8+
pure fn jumbo(&self, x: @const uint) -> uint { *self + *x }
9+
}
10+
11+
fn main() {
12+
let a = 3u;
13+
let b = a.jumbo(@mut 6);
14+
15+
let x = @a as @Mumbo;
16+
let y = x.jumbo(@mut 6); //~ ERROR values differ in mutability
17+
let z = x.jumbo(@6);
18+
}
19+
20+
21+

0 commit comments

Comments
 (0)