use rustc::hir::{Freevar, FreevarMap, TraitCandidate, TraitMap, GlobMap};
use rustc::util::nodemap::{NodeMap, NodeSet, FxHashMap, FxHashSet, DefIdMap};
-use syntax::codemap::{dummy_spanned, respan, CodeMap};
+use syntax::codemap::{dummy_spanned, respan, BytePos, CodeMap};
use syntax::ext::hygiene::{Mark, MarkKind, SyntaxContext};
use syntax::ast::{self, Name, NodeId, Ident, SpannedIdent, FloatTy, IntTy, UintTy};
use syntax::ext::base::SyntaxExtension;
E0401,
"can't use type parameters from outer function");
err.span_label(span, "use of type variable from outer function");
+
+ let cm = resolver.session.codemap();
match outer_def {
Def::SelfTy(_, maybe_impl_defid) => {
if let Some(impl_span) = maybe_impl_defid.map_or(None,
|def_id| resolver.definitions.opt_span(def_id)) {
- let cm = resolver.session.codemap();
err.span_label(reduce_impl_span_to_impl_keyword(cm, impl_span),
"`Self` type implicitely declared here, on the `impl`");
}
// Try to retrieve the span of the function signature and generate a new message with
// a local type parameter
let sugg_msg = "try using a local type parameter instead";
- if let Some((sugg_span, new_snippet)) = generate_local_type_param_snippet(
- resolver.session.codemap(), span) {
+ if let Some((sugg_span, new_snippet)) = generate_local_type_param_snippet(cm, span) {
// Suggest the modification to the user
err.span_suggestion(sugg_span,
sugg_msg,
new_snippet);
+ } else if let Some(sp) = generate_fn_name_span(cm, span) {
+ err.span_label(sp, "try adding a local type parameter in this method instead");
} else {
err.help("try using a local type parameter instead");
}
impl_span
}
+fn generate_fn_name_span(cm: &CodeMap, span: Span) -> Option<Span> {
+ let prev_span = cm.span_extend_to_prev_str(span, "fn", true);
+ cm.span_to_snippet(prev_span).map(|snippet| {
+ let len = snippet.find(|c: char| !c.is_alphanumeric() && c != '_')
+ .expect("no label after fn");
+ prev_span.with_hi(BytePos(prev_span.lo().0 + len as u32))
+ }).ok()
+}
+
/// Take the span of a type parameter in a function signature and try to generate a span for the
/// function name (with generics) and a new snippet for this span with the pointed type parameter as
/// a new local type parameter.
fn generate_local_type_param_snippet(cm: &CodeMap, span: Span) -> Option<(Span, String)> {
// Try to extend the span to the previous "fn" keyword to retrieve the function
// signature
- let sugg_span = cm.span_extend_to_prev_str(span, "fn");
+ let sugg_span = cm.span_extend_to_prev_str(span, "fn", false);
if sugg_span != span {
if let Ok(snippet) = cm.span_to_snippet(sugg_span) {
- use syntax::codemap::BytePos;
-
// Consume the function name
- let mut offset = 0;
- for c in snippet.chars().take_while(|c| c.is_ascii_alphanumeric() ||
- *c == '_') {
- offset += c.len_utf8();
- }
+ let mut offset = snippet.find(|c: char| !c.is_alphanumeric() && c != '_')
+ .expect("no label after fn");
// Consume the generics part of the function signature
let mut bracket_counter = 0;
sp
}
- /// Extend the given `Span` to just after the previous occurrence of `pat`. Return the same span
- /// if no character could be found or if an error occurred while retrieving the code snippet.
- pub fn span_extend_to_prev_str(&self, sp: Span, pat: &str) -> Span {
- if let Ok(prev_source) = self.span_to_prev_source(sp) {
- let prev_source = prev_source.rsplit(pat).nth(0).unwrap_or("").trim_left();
- if !prev_source.is_empty() && !prev_source.contains('\n') {
- return sp.with_lo(BytePos(sp.lo().0 - prev_source.len() as u32));
+ /// Extend the given `Span` to just after the previous occurrence of `pat` when surrounded by
+ /// whitespace. Return the same span if no character could be found or if an error occurred
+ /// while retrieving the code snippet.
+ pub fn span_extend_to_prev_str(&self, sp: Span, pat: &str, accept_newlines: bool) -> Span {
+ // assure that the pattern is delimited, to avoid the following
+ // fn my_fn()
+ // ^^^^ returned span without the check
+ // ---------- correct span
+ for ws in &[" ", "\t", "\n"] {
+ let pat = pat.to_owned() + ws;
+ if let Ok(prev_source) = self.span_to_prev_source(sp) {
+ let prev_source = prev_source.rsplit(&pat).nth(0).unwrap_or("").trim_left();
+ if !prev_source.is_empty() && (!prev_source.contains('\n') || accept_newlines) {
+ return sp.with_lo(BytePos(sp.lo().0 - prev_source.len() as u32));
+ }
}
}
error[E0401]: can't use type parameters from outer function
- --> $DIR/E0401.rs:14:38
+ --> $DIR/E0401.rs:14:39
|
LL | fn foo<T>(x: T) {
| - type variable from outer function
-LL | fn bar<U, V: Baz<U>, W: Fn()>(y: T) { //~ ERROR E0401
- | -------------------------- ^ use of type variable from outer function
+LL | fn bfnr<U, V: Baz<U>, W: Fn()>(y: T) { //~ ERROR E0401
+ | --------------------------- ^ use of type variable from outer function
| |
- | help: try using a local type parameter instead: `bar<U, V: Baz<U>, W: Fn(), T>`
+ | help: try using a local type parameter instead: `bfnr<U, V: Baz<U>, W: Fn(), T>`
error[E0401]: can't use type parameters from outer function
--> $DIR/E0401.rs:19:16
LL | fn foo<T>(x: T) {
| - type variable from outer function
...
+LL | fn baz<U,
+ | --- try adding a local type parameter in this method instead
+...
LL | (y: T) { //~ ERROR E0401
| ^ use of type variable from outer function
- |
- = help: try using a local type parameter instead
error[E0401]: can't use type parameters from outer function
--> $DIR/E0401.rs:32:25