Partial fix for #2687---impl method must only be subtype of trait method, not exact match.

This commit is contained in:
Niko Matsakis 2012-10-25 21:55:36 -07:00
parent 2ab614f356
commit 2093952847
3 changed files with 66 additions and 14 deletions

View File

@ -288,15 +288,10 @@ fn compare_impl_method(tcx: ty::ctxt,
let impl_m = &cm.mty;
if impl_m.fty.meta.purity != trait_m.fty.meta.purity {
tcx.sess.span_err(
cm.span,
fmt!("method `%s`'s purity does \
not match the trait method's \
purity", tcx.sess.str_of(impl_m.ident)));
}
// is this check right?
// FIXME(#2687)---this check is too strict. For example, a trait
// method with self type `&self` or `&mut self` should be
// implementable by an `&const self` method (the impl assumes less
// than the trait provides).
if impl_m.self_ty != trait_m.self_ty {
tcx.sess.span_err(
cm.span,
@ -328,6 +323,9 @@ fn compare_impl_method(tcx: ty::ctxt,
return;
}
// FIXME(#2687)---we should be checking that the bounds of the
// trait imply the bounds of the subtype, but it appears
// we are...not checking this.
for trait_m.tps.eachi() |i, trait_param_bounds| {
// For each of the corresponding impl ty param's bounds...
let impl_param_bounds = impl_m.tps[i];
@ -389,11 +387,19 @@ fn compare_impl_method(tcx: ty::ctxt,
debug!("trait_fty (pre-subst): %s", ty_to_str(tcx, trait_fty));
ty::subst(tcx, &substs, trait_fty)
};
debug!("trait_fty: %s", ty_to_str(tcx, trait_fty));
require_same_types(
tcx, None, false, cm.span, impl_fty, trait_fty,
|| fmt!("method `%s` has an incompatible type",
tcx.sess.str_of(trait_m.ident)));
let infcx = infer::new_infer_ctxt(tcx);
match infer::mk_subty(infcx, false, cm.span, impl_fty, trait_fty) {
result::Ok(()) => {}
result::Err(ref terr) => {
tcx.sess.span_err(
cm.span,
fmt!("method `%s` has an incompatible type: %s",
tcx.sess.str_of(trait_m.ident),
ty::type_err_to_str(tcx, terr)));
ty::note_and_explain_type_err(tcx, terr);
}
}
return;
// Replaces bound references to the self region with `with_r`.

View File

@ -0,0 +1,25 @@
trait Mumbo {
pure fn jumbo(&self, x: @uint) -> uint;
fn jambo(&self, x: @const uint) -> uint;
fn jbmbo(&self) -> @uint;
}
impl uint: Mumbo {
// Cannot have a larger effect than the trait:
fn jumbo(&self, x: @uint) { *self + *x; }
//~^ ERROR expected pure fn but found impure fn
// Cannot accept a narrower range of parameters:
fn jambo(&self, x: @uint) { *self + *x; }
//~^ ERROR values differ in mutability
// Cannot return a wider range of values:
fn jbmbo(&self) -> @const uint { @const 0 }
//~^ ERROR values differ in mutability
}
fn main() {}

View File

@ -0,0 +1,21 @@
trait Mumbo {
fn jumbo(&self, x: @uint) -> uint;
}
impl uint: Mumbo {
// Note: this method def is ok, it is more accepting and
// less effecting than the trait method:
pure fn jumbo(&self, x: @const uint) -> uint { *self + *x }
}
fn main() {
let a = 3u;
let b = a.jumbo(@mut 6);
let x = @a as @Mumbo;
let y = x.jumbo(@mut 6); //~ ERROR values differ in mutability
let z = x.jumbo(@6);
}