Skip to content

Commit

Permalink
Partial fix for rust-lang#2687---impl method must only be subtype of …
Browse files Browse the repository at this point in the history
…trait method, not exact match.
  • Loading branch information
nikomatsakis committed Oct 27, 2012
1 parent 2ab614f commit 2093952
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 14 deletions.
34 changes: 20 additions & 14 deletions src/rustc/middle/typeck/collect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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];
Expand Down Expand Up @@ -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`.
Expand Down
25 changes: 25 additions & 0 deletions src/test/compile-fail/trait-impl-method-mismatch.rs
Original file line number Diff line number Diff line change
@@ -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() {}




21 changes: 21 additions & 0 deletions src/test/compile-fail/trait-impl-subtype.rs
Original file line number Diff line number Diff line change
@@ -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);
}



0 comments on commit 2093952

Please sign in to comment.