]> git.lizzy.rs Git - rust.git/commitdiff
Some tweaks to "type parameters from outer function" diagnostic
authorEsteban Küber <esteban@kuber.com.ar>
Wed, 14 Mar 2018 05:58:45 +0000 (22:58 -0700)
committerEsteban Küber <esteban@kuber.com.ar>
Wed, 14 Mar 2018 19:35:25 +0000 (12:35 -0700)
Follow up to #47574.

src/librustc_resolve/lib.rs
src/libsyntax/codemap.rs
src/test/ui/error-codes/E0401.rs
src/test/ui/error-codes/E0401.stderr

index a6b776125ae97491b25cd7545750ef99a5f911b5..c84caee13e82a0c4233f535661ed12dd35367912 100644 (file)
@@ -41,7 +41,7 @@
 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;
@@ -179,11 +179,12 @@ fn resolve_struct_error<'sess, 'a>(resolver: &'sess Resolver,
                                            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`");
                     }
@@ -206,12 +207,13 @@ fn resolve_struct_error<'sess, 'a>(resolver: &'sess Resolver,
             // 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");
             }
@@ -407,6 +409,15 @@ fn reduce_impl_span_to_impl_keyword(cm: &CodeMap, impl_span: Span) -> Span {
     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.
@@ -428,17 +439,12 @@ fn reduce_impl_span_to_impl_keyword(cm: &CodeMap, impl_span: Span) -> Span {
 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;
index c340f1b8c8ab328315409ce002537c2a9788571d..951f8a871ca66d2588f90f23a832ed154371453a 100644 (file)
@@ -622,13 +622,21 @@ pub fn span_extend_to_prev_char(&self, sp: Span, c: char) -> Span {
         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));
+                }
             }
         }
 
index 15b946625778c02a88d457ec0d94832f95b41c68..4fc74f5ef22192adca43160e514666937f407d06 100644 (file)
 trait Baz<T> {}
 
 fn foo<T>(x: T) {
-    fn bar<U, V: Baz<U>, W: Fn()>(y: T) { //~ ERROR E0401
+    fn bfnr<U, V: Baz<U>, W: Fn()>(y: T) { //~ ERROR E0401
     }
     fn baz<U,
            V: Baz<U>,
            W: Fn()>
            (y: T) { //~ ERROR E0401
     }
-    bar(x);
+    bfnr(x);
 }
 
 
index c306ff4a04f6a92f1d887026c08e4f1722fc5d54..e5a2be4dfb0263754f995bb8ad4a41305a16a4eb 100644 (file)
@@ -1,12 +1,12 @@
 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
@@ -14,10 +14,11 @@ error[E0401]: can't use type parameters from outer function
 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