Skip to content

Commit 3edb4fc

Browse files
committed
Point to type argument span when used as trait
Given the following code: ```rust struct Foo<T: Clone>(T); use std::ops::Add; impl<T: Clone, Add> Add for Foo<T> { 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<T: Clone, Add> Add for Okok<T> { | --- ^^^ expected trait, found type parameter | | | type parameter defined here ```
1 parent b5f6d7e commit 3edb4fc

File tree

7 files changed

+69
-14
lines changed

7 files changed

+69
-14
lines changed

src/librustc_resolve/lib.rs

+25-11
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ enum ResolutionError<'a> {
108108
/// error E0403: the name is already used for a type parameter in this type parameter list
109109
NameAlreadyUsedInTypeParameterList(Name, &'a Span),
110110
/// error E0404: is not a trait
111-
IsNotATrait(&'a str),
111+
IsNotATrait(&'a str, &'a str),
112112
/// error E0405: use of undeclared trait name
113113
UndeclaredTraitName(&'a str, SuggestedCandidates),
114114
/// 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>,
225225
err
226226

227227
}
228-
ResolutionError::IsNotATrait(name) => {
228+
ResolutionError::IsNotATrait(name, kind_name) => {
229229
let mut err = struct_span_err!(resolver.session,
230230
span,
231231
E0404,
232232
"`{}` is not a trait",
233233
name);
234-
err.span_label(span, &format!("not a trait"));
234+
err.span_label(span, &format!("expected trait, found {}", kind_name));
235235
err
236236
}
237237
ResolutionError::UndeclaredTraitName(name, candidates) => {
@@ -566,7 +566,7 @@ impl<'a> Visitor for Resolver<'a> {
566566
self.resolve_type(ty);
567567
}
568568
fn visit_poly_trait_ref(&mut self, tref: &ast::PolyTraitRef, m: &ast::TraitBoundModifier) {
569-
match self.resolve_trait_reference(tref.trait_ref.ref_id, &tref.trait_ref.path, 0) {
569+
match self.resolve_trait_reference(tref.trait_ref.ref_id, &tref.trait_ref.path, 0, None) {
570570
Ok(def) => self.record_def(tref.trait_ref.ref_id, def),
571571
Err(_) => {
572572
// error already reported
@@ -1703,7 +1703,7 @@ impl<'a> Resolver<'a> {
17031703
}
17041704

17051705
ItemKind::DefaultImpl(_, ref trait_ref) => {
1706-
self.with_optional_trait_ref(Some(trait_ref), |_, _| {});
1706+
self.with_optional_trait_ref(Some(trait_ref), |_, _| {}, None);
17071707
}
17081708
ItemKind::Impl(.., ref generics, ref opt_trait_ref, ref self_type, ref impl_items) =>
17091709
self.resolve_implementation(generics,
@@ -1893,7 +1893,8 @@ impl<'a> Resolver<'a> {
18931893
fn resolve_trait_reference(&mut self,
18941894
id: NodeId,
18951895
trait_path: &Path,
1896-
path_depth: usize)
1896+
path_depth: usize,
1897+
generics: Option<&Generics>)
18971898
-> Result<PathResolution, ()> {
18981899
self.resolve_path(id, trait_path, path_depth, TypeNS).and_then(|path_res| {
18991900
match path_res.base_def {
@@ -1906,8 +1907,16 @@ impl<'a> Resolver<'a> {
19061907
}
19071908

19081909
let mut err = resolve_struct_error(self, trait_path.span, {
1909-
ResolutionError::IsNotATrait(&path_names_to_string(trait_path, path_depth))
1910+
ResolutionError::IsNotATrait(&path_names_to_string(trait_path, path_depth),
1911+
path_res.base_def.kind_name())
19101912
});
1913+
if let Some(generics) = generics {
1914+
if let Some(span) = generics.span_for_name(
1915+
&path_names_to_string(trait_path, path_depth)) {
1916+
1917+
err.span_label(span, &"type parameter defined here");
1918+
}
1919+
}
19111920

19121921
// If it's a typedef, give a note
19131922
if let Def::TyAlias(..) = path_res.base_def {
@@ -1952,15 +1961,20 @@ impl<'a> Resolver<'a> {
19521961
result
19531962
}
19541963

1955-
fn with_optional_trait_ref<T, F>(&mut self, opt_trait_ref: Option<&TraitRef>, f: F) -> T
1964+
fn with_optional_trait_ref<T, F>(&mut self,
1965+
opt_trait_ref: Option<&TraitRef>,
1966+
f: F,
1967+
generics: Option<&Generics>)
1968+
-> T
19561969
where F: FnOnce(&mut Resolver, Option<DefId>) -> T
19571970
{
19581971
let mut new_val = None;
19591972
let mut new_id = None;
19601973
if let Some(trait_ref) = opt_trait_ref {
19611974
if let Ok(path_res) = self.resolve_trait_reference(trait_ref.ref_id,
19621975
&trait_ref.path,
1963-
0) {
1976+
0,
1977+
generics) {
19641978
assert!(path_res.depth == 0);
19651979
self.record_def(trait_ref.ref_id, path_res);
19661980
new_val = Some((path_res.base_def.def_id(), trait_ref.clone()));
@@ -2048,7 +2062,7 @@ impl<'a> Resolver<'a> {
20482062
}
20492063
});
20502064
});
2051-
});
2065+
}, Some(&generics));
20522066
});
20532067
}
20542068

@@ -2492,7 +2506,7 @@ impl<'a> Resolver<'a> {
24922506
}
24932507
max_assoc_types = path.segments.len() - qself.position;
24942508
// Make sure the trait is valid.
2495-
let _ = self.resolve_trait_reference(id, path, max_assoc_types);
2509+
let _ = self.resolve_trait_reference(id, path, max_assoc_types, None);
24962510
}
24972511
None => {
24982512
max_assoc_types = path.segments.len();

src/libsyntax/ast.rs

+8
Original file line numberDiff line numberDiff line change
@@ -399,6 +399,14 @@ impl Generics {
399399
pub fn is_parameterized(&self) -> bool {
400400
self.is_lt_parameterized() || self.is_type_parameterized()
401401
}
402+
pub fn span_for_name(&self, name: &str) -> Option<Span> {
403+
for t in &self.ty_params {
404+
if t.ident.name.as_str() == name {
405+
return Some(t.span);
406+
}
407+
}
408+
None
409+
}
402410
}
403411

404412
impl Default for Generics {

src/test/compile-fail/issue-3907.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ struct S {
1818
}
1919

2020
impl Foo for S { //~ ERROR: `Foo` is not a trait
21-
//~| NOTE: not a trait
21+
//~| NOTE: expected trait, found type alias
2222
//~| NOTE: type aliases cannot be used for traits
2323
fn bar() { }
2424
}

src/test/compile-fail/issue-5035.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
trait I {}
1212
type K = I;
1313
impl K for isize {} //~ ERROR: `K` is not a trait
14-
//~| NOTE: not a trait
14+
//~| NOTE: expected trait, found type alias
1515
//~| NOTE: aliases cannot be used for traits
1616

1717
use ImportError; //~ ERROR unresolved import `ImportError` [E0432]

src/test/ui/codemap_tests/two_files.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ error[E0404]: `Bar` is not a trait
22
--> $DIR/two_files.rs:15:6
33
|
44
15 | impl Bar for Baz { }
5-
| ^^^ not a trait
5+
| ^^^ expected trait, found type alias
66
|
77
= note: type aliases cannot be used for traits
88

src/test/ui/span/issue-35987.rs

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
struct Foo<T: Clone>(T);
12+
13+
use std::ops::Add;
14+
15+
impl<T: Clone, Add> Add for Foo<T> {
16+
type Output = usize;
17+
18+
fn add(self, rhs: Self) -> Self::Output {
19+
unimplemented!();
20+
}
21+
}

src/test/ui/span/issue-35987.stderr

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
error[E0404]: `Add` is not a trait
2+
--> $DIR/issue-35987.rs:15:21
3+
|
4+
15 | impl<T: Clone, Add> Add for Foo<T> {
5+
| --- ^^^ expected trait, found type parameter
6+
| |
7+
| type parameter defined here
8+
9+
error: main function not found
10+
11+
error: cannot continue compilation due to previous error
12+

0 commit comments

Comments
 (0)