diff --git a/src/librustc/middle/typeck/check/method.rs b/src/librustc/middle/typeck/check/method.rs index 765bf0cfdff4d..7eb0aff536134 100644 --- a/src/librustc/middle/typeck/check/method.rs +++ b/src/librustc/middle/typeck/check/method.rs @@ -459,7 +459,9 @@ impl LookupContext { let tcx = self.tcx(); let ms = ty::trait_methods(tcx, did); - let index = match vec::position(*ms, |m| m.ident == self.m_name) { + let index = match vec::position(*ms, + |m| (m.self_ty != ast::sty_static && + m.ident == self.m_name)) { Some(i) => i, None => { return; } // no method with the right name }; @@ -508,7 +510,9 @@ impl LookupContext { let tcx = self.tcx(); let methods = ty::trait_methods(tcx, did); // XXX: Inherited methods. let index; - match vec::position(*methods, |m| m.ident == self.m_name) { + match vec::position(*methods, + |m| (m.self_ty != ast::sty_static && + m.ident == self.m_name)) { Some(i) => index = i, None => return } @@ -552,7 +556,8 @@ impl LookupContext { let idx = { // FIXME #3453 can't use impl_info.methods.position match vec::position(impl_info.methods, - |m| m.ident == self.m_name) { + |m| (m.self_type != ast::sty_static && + m.ident == self.m_name)) { Some(idx) => idx, None => { return; } // No method with the right name. } diff --git a/src/librustc/middle/typeck/collect.rs b/src/librustc/middle/typeck/collect.rs index b4ba9c3d65447..64cb36f8c19ba 100644 --- a/src/librustc/middle/typeck/collect.rs +++ b/src/librustc/middle/typeck/collect.rs @@ -314,34 +314,6 @@ fn compare_impl_method(tcx: ty::ctxt, let impl_m = &cm.mty; - // 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 { - if impl_m.self_ty == ast::sty_static { - // Needs to be a fatal error because otherwise, - // method::transform_self_type_for_method ICEs - tcx.sess.span_fatal(cm.span, - fmt!("method `%s` is declared as \ - static in its impl, but not in \ - its trait", tcx.sess.str_of(impl_m.ident))); - } - else if trait_m.self_ty == ast::sty_static { - tcx.sess.span_fatal(cm.span, - fmt!("method `%s` is declared as \ - static in its trait, but not in \ - its impl", tcx.sess.str_of(impl_m.ident))); - } - else { - tcx.sess.span_err( - cm.span, - fmt!("method `%s`'s self type does \ - not match the trait method's \ - self type", tcx.sess.str_of(impl_m.ident))); - } - } - if impl_m.tps.len() != trait_m.tps.len() { tcx.sess.span_err( cm.span, @@ -483,12 +455,37 @@ fn check_methods_against_trait(ccx: @crate_ctxt, // we'll catch it in coherence let trait_ms = ty::trait_methods(tcx, did); for impl_ms.each |impl_m| { - match trait_ms.find(|trait_m| trait_m.ident == impl_m.mty.ident) { - Some(ref trait_m) => { + match find_matching_trait_method(impl_m, trait_ms) { + Some(ref trait_m) if trait_m.self_ty == impl_m.mty.self_ty => { compare_impl_method( ccx.tcx, tps.len(), impl_m, trait_m, &tpt.substs, selfty); } + Some(ref trait_m) => { + // Method name matches, self-type differs. + // Needs to be a fatal error because otherwise, + // method::transform_self_type_for_method ICEs + if (impl_m.mty.self_ty == ast::sty_static) { + tcx.sess.span_fatal(impl_m.span, + fmt!("method `%s` is declared as \ + static in its impl, but not in \ + its trait", tcx.sess.str_of(impl_m.mty.ident))); + } else if (trait_m.self_ty == ast::sty_static) { + tcx.sess.span_fatal(impl_m.span, + fmt!("method `%s` is declared as \ + static in its trait, but not in \ + its impl", tcx.sess.str_of(impl_m.mty.ident))); + } else { + // 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). + tcx.sess.span_err(impl_m.span, + fmt!("method `%s`'s self type does \ + not match the trait method's \ + self type", tcx.sess.str_of(impl_m.mty.ident))); + } + } None => { // This method is not part of the trait tcx.sess.span_err( @@ -501,6 +498,26 @@ fn check_methods_against_trait(ccx: @crate_ctxt, } } // fn +// Find a matching method in the trait. We favor those +// with the same name and self-type as the impl method. +// At least, we try to find one with the same name to +// fail with an explicit error message. +fn find_matching_trait_method(impl_m: &ConvertedMethod, + trait_ms: &~[ty::method]) + -> Option { + + let mut last_name_match = None; + for trait_ms.each |m| { + if (m.ident == impl_m.mty.ident) { + last_name_match = Some(*m); + if (m.self_ty == impl_m.mty.self_ty) { + return last_name_match; + } + } + } + last_name_match +} + fn convert_field(ccx: @crate_ctxt, rp: Option, bounds: @~[ty::param_bounds], diff --git a/src/test/compile-fail/issue-4265.rs b/src/test/compile-fail/issue-4265.rs new file mode 100644 index 0000000000000..d8f4be2e90519 --- /dev/null +++ b/src/test/compile-fail/issue-4265.rs @@ -0,0 +1,20 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +trait Trait { + static fn bar(); + + fn foo() { + self.bar(); + //~^ ERROR type `self` does not implement any method in scope named `bar` + } +} + +fn main() {} diff --git a/src/test/run-pass/issue-4265.rs b/src/test/run-pass/issue-4265.rs new file mode 100644 index 0000000000000..41a5a54a2d646 --- /dev/null +++ b/src/test/run-pass/issue-4265.rs @@ -0,0 +1,27 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +trait Trait { + static fn fun(); + fn fun(); +} + +struct A { + v: bool +} + +impl A: Trait { + static fn fun() {} + fn fun() {} +} + +fn main() { + A { v: true }.fun(); +}