From 579a1392158a44ecabb36fe586500d862b3e95b7 Mon Sep 17 00:00:00 2001 From: Kevin Butler Date: Wed, 18 Jun 2014 14:16:45 +0100 Subject: [PATCH] rustc: catch non-trait methods before typeck. Closes #3973. --- src/librustc/middle/resolve.rs | 18 ++++++++++++++++++ src/librustc/middle/typeck/check/mod.rs | 3 ++- src/test/compile-fail/issue-3973.rs | 18 +++++++++++------- 3 files changed, 31 insertions(+), 8 deletions(-) diff --git a/src/librustc/middle/resolve.rs b/src/librustc/middle/resolve.rs index 5ce63b94b24..6c916272593 100644 --- a/src/librustc/middle/resolve.rs +++ b/src/librustc/middle/resolve.rs @@ -4021,6 +4021,9 @@ fn resolve_implementation(&mut self, this.with_current_self_type(self_type, |this| { for method in methods.iter() { + // If this is a trait impl, ensure the method exists in trait + this.check_trait_method(&**method); + // We also need a new scope for the method-specific type parameters. this.resolve_method(MethodRibKind(id, Provided(method.id)), &**method); @@ -4030,6 +4033,21 @@ fn resolve_implementation(&mut self, }); } + fn check_trait_method(&self, method: &Method) { + // If there is a TraitRef in scope for an impl, then the method must be in the trait. + for &(did, ref trait_ref) in self.current_trait_ref.iter() { + let method_name = method.ident.name; + + if self.method_map.borrow().find(&(method_name, did)).is_none() { + let path_str = self.path_idents_to_str(&trait_ref.path); + self.resolve_error(method.span, + format!("method `{}` is not a member of trait `{}`", + token::get_name(method_name), + path_str).as_slice()); + } + } + } + fn resolve_module(&mut self, module: &Mod, _span: Span, _name: Ident, id: NodeId) { // Write the implementations in scope into the module metadata. diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs index 1c5cfc45afd..04db13feff6 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc/middle/typeck/check/mod.rs @@ -784,7 +784,8 @@ fn check_impl_methods_against_trait(ccx: &CrateCtxt, &impl_trait_ref.substs); } None => { - tcx.sess.span_err( + // This is span_bug as it should have already been caught in resolve. + tcx.sess.span_bug( impl_method.span, format!( "method `{}` is not a member of trait `{}`", diff --git a/src/test/compile-fail/issue-3973.rs b/src/test/compile-fail/issue-3973.rs index 7fe7778c1a5..d2d7625842a 100644 --- a/src/test/compile-fail/issue-3973.rs +++ b/src/test/compile-fail/issue-3973.rs @@ -8,26 +8,30 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// ignore-test - -use std::io; - struct Point { x: f64, y: f64, } -impl ToStr for Point { //~ ERROR implements a method not defined in the trait +trait NewTrait { + fn a(&self) -> String; +} + +impl NewTrait for Point { fn new(x: f64, y: f64) -> Point { + //~^ ERROR method `new` is not a member of trait `NewTrait` Point { x: x, y: y } } - fn to_str(&self) -> String { + fn a(&self) -> String { format!("({}, {})", self.x, self.y) } } fn main() { let p = Point::new(0.0, 0.0); - println!("{}", p.to_str()); + //~^ ERROR unresolved name `Point::new` + //~^^ ERROR unresolved name + //~^^^ ERROR use of undeclared module `Point` + println!("{}", p.a()); } -- 2.44.0