From 209395284799bb86e34cf59493c539a35f6150dd Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 25 Oct 2012 21:55:36 -0700 Subject: [PATCH] Partial fix for #2687---impl method must only be subtype of trait method, not exact match. --- src/rustc/middle/typeck/collect.rs | 34 +++++++++++-------- .../trait-impl-method-mismatch.rs | 25 ++++++++++++++ src/test/compile-fail/trait-impl-subtype.rs | 21 ++++++++++++ 3 files changed, 66 insertions(+), 14 deletions(-) create mode 100644 src/test/compile-fail/trait-impl-method-mismatch.rs create mode 100644 src/test/compile-fail/trait-impl-subtype.rs diff --git a/src/rustc/middle/typeck/collect.rs b/src/rustc/middle/typeck/collect.rs index f0d0349a7fa..611edbb3236 100644 --- a/src/rustc/middle/typeck/collect.rs +++ b/src/rustc/middle/typeck/collect.rs @@ -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`. diff --git a/src/test/compile-fail/trait-impl-method-mismatch.rs b/src/test/compile-fail/trait-impl-method-mismatch.rs new file mode 100644 index 00000000000..895aea49874 --- /dev/null +++ b/src/test/compile-fail/trait-impl-method-mismatch.rs @@ -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() {} + + + + diff --git a/src/test/compile-fail/trait-impl-subtype.rs b/src/test/compile-fail/trait-impl-subtype.rs new file mode 100644 index 00000000000..d1548b6c186 --- /dev/null +++ b/src/test/compile-fail/trait-impl-subtype.rs @@ -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); +} + + +