From 3edb4fc56345ba2d33a04e952e1d402b08bc676c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 26 Oct 2016 20:51:49 -0700 Subject: [PATCH] Point to type argument span when used as trait Given the following code: ```rust struct Foo(T); use std::ops::Add; impl Add for Foo { type Output = usize; fn add(self, rhs: Self) -> Self::Output { unimplemented!(); } } ``` present the following output: ```nocode error[E0404]: `Add` is not a trait --> file3.rs:5:21 | 5 | impl Add for Okok { | --- ^^^ expected trait, found type parameter | | | type parameter defined here ``` --- src/librustc_resolve/lib.rs | 36 +++++++++++++++------- src/libsyntax/ast.rs | 8 +++++ src/test/compile-fail/issue-3907.rs | 2 +- src/test/compile-fail/issue-5035.rs | 2 +- src/test/ui/codemap_tests/two_files.stderr | 2 +- src/test/ui/span/issue-35987.rs | 21 +++++++++++++ src/test/ui/span/issue-35987.stderr | 12 ++++++++ 7 files changed, 69 insertions(+), 14 deletions(-) create mode 100644 src/test/ui/span/issue-35987.rs create mode 100644 src/test/ui/span/issue-35987.stderr diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 7091d7d2a6321..061708127a3d1 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -108,7 +108,7 @@ enum ResolutionError<'a> { /// error E0403: the name is already used for a type parameter in this type parameter list NameAlreadyUsedInTypeParameterList(Name, &'a Span), /// error E0404: is not a trait - IsNotATrait(&'a str), + IsNotATrait(&'a str, &'a str), /// error E0405: use of undeclared trait name UndeclaredTraitName(&'a str, SuggestedCandidates), /// error E0407: method is not a member of trait @@ -225,13 +225,13 @@ fn resolve_struct_error<'b, 'a: 'b, 'c>(resolver: &'b Resolver<'a>, err } - ResolutionError::IsNotATrait(name) => { + ResolutionError::IsNotATrait(name, kind_name) => { let mut err = struct_span_err!(resolver.session, span, E0404, "`{}` is not a trait", name); - err.span_label(span, &format!("not a trait")); + err.span_label(span, &format!("expected trait, found {}", kind_name)); err } ResolutionError::UndeclaredTraitName(name, candidates) => { @@ -566,7 +566,7 @@ impl<'a> Visitor for Resolver<'a> { self.resolve_type(ty); } fn visit_poly_trait_ref(&mut self, tref: &ast::PolyTraitRef, m: &ast::TraitBoundModifier) { - match self.resolve_trait_reference(tref.trait_ref.ref_id, &tref.trait_ref.path, 0) { + match self.resolve_trait_reference(tref.trait_ref.ref_id, &tref.trait_ref.path, 0, None) { Ok(def) => self.record_def(tref.trait_ref.ref_id, def), Err(_) => { // error already reported @@ -1703,7 +1703,7 @@ impl<'a> Resolver<'a> { } ItemKind::DefaultImpl(_, ref trait_ref) => { - self.with_optional_trait_ref(Some(trait_ref), |_, _| {}); + self.with_optional_trait_ref(Some(trait_ref), |_, _| {}, None); } ItemKind::Impl(.., ref generics, ref opt_trait_ref, ref self_type, ref impl_items) => self.resolve_implementation(generics, @@ -1893,7 +1893,8 @@ impl<'a> Resolver<'a> { fn resolve_trait_reference(&mut self, id: NodeId, trait_path: &Path, - path_depth: usize) + path_depth: usize, + generics: Option<&Generics>) -> Result { self.resolve_path(id, trait_path, path_depth, TypeNS).and_then(|path_res| { match path_res.base_def { @@ -1906,8 +1907,16 @@ impl<'a> Resolver<'a> { } let mut err = resolve_struct_error(self, trait_path.span, { - ResolutionError::IsNotATrait(&path_names_to_string(trait_path, path_depth)) + ResolutionError::IsNotATrait(&path_names_to_string(trait_path, path_depth), + path_res.base_def.kind_name()) }); + if let Some(generics) = generics { + if let Some(span) = generics.span_for_name( + &path_names_to_string(trait_path, path_depth)) { + + err.span_label(span, &"type parameter defined here"); + } + } // If it's a typedef, give a note if let Def::TyAlias(..) = path_res.base_def { @@ -1952,7 +1961,11 @@ impl<'a> Resolver<'a> { result } - fn with_optional_trait_ref(&mut self, opt_trait_ref: Option<&TraitRef>, f: F) -> T + fn with_optional_trait_ref(&mut self, + opt_trait_ref: Option<&TraitRef>, + f: F, + generics: Option<&Generics>) + -> T where F: FnOnce(&mut Resolver, Option) -> T { let mut new_val = None; @@ -1960,7 +1973,8 @@ impl<'a> Resolver<'a> { if let Some(trait_ref) = opt_trait_ref { if let Ok(path_res) = self.resolve_trait_reference(trait_ref.ref_id, &trait_ref.path, - 0) { + 0, + generics) { assert!(path_res.depth == 0); self.record_def(trait_ref.ref_id, path_res); new_val = Some((path_res.base_def.def_id(), trait_ref.clone())); @@ -2048,7 +2062,7 @@ impl<'a> Resolver<'a> { } }); }); - }); + }, Some(&generics)); }); } @@ -2492,7 +2506,7 @@ impl<'a> Resolver<'a> { } max_assoc_types = path.segments.len() - qself.position; // Make sure the trait is valid. - let _ = self.resolve_trait_reference(id, path, max_assoc_types); + let _ = self.resolve_trait_reference(id, path, max_assoc_types, None); } None => { max_assoc_types = path.segments.len(); diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 30fc4c3dd8045..cc39e81fdaeeb 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -399,6 +399,14 @@ impl Generics { pub fn is_parameterized(&self) -> bool { self.is_lt_parameterized() || self.is_type_parameterized() } + pub fn span_for_name(&self, name: &str) -> Option { + for t in &self.ty_params { + if t.ident.name.as_str() == name { + return Some(t.span); + } + } + None + } } impl Default for Generics { diff --git a/src/test/compile-fail/issue-3907.rs b/src/test/compile-fail/issue-3907.rs index 93556577ad345..86906ed9af206 100644 --- a/src/test/compile-fail/issue-3907.rs +++ b/src/test/compile-fail/issue-3907.rs @@ -18,7 +18,7 @@ struct S { } impl Foo for S { //~ ERROR: `Foo` is not a trait - //~| NOTE: not a trait + //~| NOTE: expected trait, found type alias //~| NOTE: type aliases cannot be used for traits fn bar() { } } diff --git a/src/test/compile-fail/issue-5035.rs b/src/test/compile-fail/issue-5035.rs index 7a36012925eed..8ebcba4713400 100644 --- a/src/test/compile-fail/issue-5035.rs +++ b/src/test/compile-fail/issue-5035.rs @@ -11,7 +11,7 @@ trait I {} type K = I; impl K for isize {} //~ ERROR: `K` is not a trait - //~| NOTE: not a trait + //~| NOTE: expected trait, found type alias //~| NOTE: aliases cannot be used for traits use ImportError; //~ ERROR unresolved import `ImportError` [E0432] diff --git a/src/test/ui/codemap_tests/two_files.stderr b/src/test/ui/codemap_tests/two_files.stderr index d58e7148f6104..d05e6eb2bbe4d 100644 --- a/src/test/ui/codemap_tests/two_files.stderr +++ b/src/test/ui/codemap_tests/two_files.stderr @@ -2,7 +2,7 @@ error[E0404]: `Bar` is not a trait --> $DIR/two_files.rs:15:6 | 15 | impl Bar for Baz { } - | ^^^ not a trait + | ^^^ expected trait, found type alias | = note: type aliases cannot be used for traits diff --git a/src/test/ui/span/issue-35987.rs b/src/test/ui/span/issue-35987.rs new file mode 100644 index 0000000000000..8ff5f3b83986c --- /dev/null +++ b/src/test/ui/span/issue-35987.rs @@ -0,0 +1,21 @@ +// Copyright 2016 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. + +struct Foo(T); + +use std::ops::Add; + +impl Add for Foo { + type Output = usize; + + fn add(self, rhs: Self) -> Self::Output { + unimplemented!(); + } +} diff --git a/src/test/ui/span/issue-35987.stderr b/src/test/ui/span/issue-35987.stderr new file mode 100644 index 0000000000000..2370b3d6c612e --- /dev/null +++ b/src/test/ui/span/issue-35987.stderr @@ -0,0 +1,12 @@ +error[E0404]: `Add` is not a trait + --> $DIR/issue-35987.rs:15:21 + | +15 | impl Add for Foo { + | --- ^^^ expected trait, found type parameter + | | + | type parameter defined here + +error: main function not found + +error: cannot continue compilation due to previous error +