Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Point to type argument span when used as trait #37428

Merged
merged 1 commit into from
Nov 9, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -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) => {
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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<PathResolution, ()> {
self.resolve_path(id, trait_path, path_depth, TypeNS).and_then(|path_res| {
match path_res.base_def {
Expand All @@ -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 {
Expand Down Expand Up @@ -1952,15 +1961,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 @@ -2048,7 +2062,7 @@ impl<'a> Resolver<'a> {
}
});
});
});
}, Some(&generics));
});
}

Expand Down Expand Up @@ -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();
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> {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not convinced that this is the best way of getting the type argument's span. Does anyone have a pointer as to an alternative?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I remember doing such a thing but can't find the PR. From my point of view, this is correct. However I can totally overpass a better solution.

Anything in mind @eddyb?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems okay. If there are duplicate type parameter names, you'll get a different error for that.

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