Skip to content

Commit

Permalink
Rollup merge of rust-lang#37428 - estebank:generic-type-error-span, r…
Browse files Browse the repository at this point in the history
…=sanxiyn

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
```

Fixes rust-lang#35987.
  • Loading branch information
eddyb authored Nov 9, 2016
2 parents 7f2853f + 3edb4fc commit bd9969f
Show file tree
Hide file tree
Showing 7 changed files with 69 additions and 14 deletions.
36 changes: 25 additions & 11 deletions src/librustc_resolve/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -223,13 +223,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) => {
Expand Down Expand Up @@ -555,7 +555,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
Expand Down Expand Up @@ -1699,7 +1699,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,
Expand Down Expand Up @@ -1889,7 +1889,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<PathResolution, ()> {
self.resolve_path(id, trait_path, path_depth, TypeNS).and_then(|path_res| {
match path_res.base_def {
Expand All @@ -1902,8 +1903,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 {
Expand Down Expand Up @@ -1948,15 +1957,20 @@ impl<'a> Resolver<'a> {
result
}

fn with_optional_trait_ref<T, F>(&mut self, opt_trait_ref: Option<&TraitRef>, f: F) -> T
fn with_optional_trait_ref<T, F>(&mut self,
opt_trait_ref: Option<&TraitRef>,
f: F,
generics: Option<&Generics>)
-> T
where F: FnOnce(&mut Resolver, Option<DefId>) -> T
{
let mut new_val = None;
let mut new_id = None;
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()));
Expand Down Expand Up @@ -2044,7 +2058,7 @@ impl<'a> Resolver<'a> {
}
});
});
});
}, Some(&generics));
});
}

Expand Down Expand Up @@ -2494,7 +2508,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();
Expand Down
8 changes: 8 additions & 0 deletions src/libsyntax/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Span> {
for t in &self.ty_params {
if t.ident.name.as_str() == name {
return Some(t.span);
}
}
None
}
}

impl Default for Generics {
Expand Down
2 changes: 1 addition & 1 deletion src/test/compile-fail/issue-3907.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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() { }
}
Expand Down
2 changes: 1 addition & 1 deletion src/test/compile-fail/issue-5035.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/codemap_tests/two_files.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
21 changes: 21 additions & 0 deletions src/test/ui/span/issue-35987.rs
Original file line number Diff line number Diff line change
@@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

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!();
}
}
12 changes: 12 additions & 0 deletions src/test/ui/span/issue-35987.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
error[E0404]: `Add` is not a trait
--> $DIR/issue-35987.rs:15:21
|
15 | impl<T: Clone, Add> Add for Foo<T> {
| --- ^^^ expected trait, found type parameter
| |
| type parameter defined here

error: main function not found

error: cannot continue compilation due to previous error

0 comments on commit bd9969f

Please sign in to comment.