about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAlexander Regueiro <alexreg@me.com>2019-02-02 02:18:32 +0000
committerAlexander Regueiro <alexreg@me.com>2019-02-07 22:28:16 +0100
commit14b674ab9d1f0b71763a168bd764eb7d53154008 (patch)
treef505ffd3bbfe22c371fc90ca9395fcba48132ddb
parent0e2d96e88c660c574723dfc6cf8aab084917cb8c (diff)
downloadrust-14b674ab9d1f0b71763a168bd764eb7d53154008.tar.gz
rust-14b674ab9d1f0b71763a168bd764eb7d53154008.zip
Factored out context-dependent help for error reporting.
-rw-r--r--src/librustc_resolve/lib.rs378
1 files changed, 195 insertions, 183 deletions
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index 30772cd0d45..1a5fce14fa8 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -3124,6 +3124,193 @@ impl<'a> Resolver<'a> {
         )
     }
 
+    /// Provides context-dependent help for errors reported by the `smart_resolve_path_fragment`
+    /// function.
+    /// Returns `true` if able to provide context-dependent help.
+    fn smart_resolve_context_dep_help(
+        &mut self,
+        err: &mut DiagnosticBuilder<'a>,
+        span: Span,
+        source: PathSource,
+        def: Def,
+        path_str: &str,
+        fallback_label: &str,
+    ) -> bool {
+        let ns = source.namespace();
+        let is_expected = &|def| source.is_expected(def);
+
+        match (def, source) {
+            (Def::Macro(..), _) => {
+                err.span_suggestion(
+                    span,
+                    "use `!` to invoke the macro",
+                    format!("{}!", path_str),
+                    Applicability::MaybeIncorrect,
+                );
+            }
+            (Def::TyAlias(..), PathSource::Trait(_)) => {
+                err.span_label(span, "type aliases cannot be used as traits");
+                if nightly_options::is_nightly_build() {
+                    err.note("did you mean to use a trait alias?");
+                }
+            }
+            (Def::Mod(..), PathSource::Expr(Some(parent))) => match parent.node {
+                ExprKind::Field(_, ident) => {
+                    err.span_suggestion(
+                        parent.span,
+                        "use the path separator to refer to an item",
+                        format!("{}::{}", path_str, ident),
+                        Applicability::MaybeIncorrect,
+                    );
+                }
+                ExprKind::MethodCall(ref segment, ..) => {
+                    let span = parent.span.with_hi(segment.ident.span.hi());
+                    err.span_suggestion(
+                        span,
+                        "use the path separator to refer to an item",
+                        format!("{}::{}", path_str, segment.ident),
+                        Applicability::MaybeIncorrect,
+                    );
+                }
+                _ => return false,
+            },
+            (Def::Enum(..), PathSource::TupleStruct)
+                | (Def::Enum(..), PathSource::Expr(..))  => {
+                if let Some(variants) = self.collect_enum_variants(def) {
+                    err.note(&format!("did you mean to use one \
+                                        of the following variants?\n{}",
+                        variants.iter()
+                            .map(|suggestion| path_names_to_string(suggestion))
+                            .map(|suggestion| format!("- `{}`", suggestion))
+                            .collect::<Vec<_>>()
+                            .join("\n")));
+                } else {
+                    err.note("did you mean to use one of the enum's variants?");
+                }
+            },
+            (Def::Struct(def_id), _) if ns == ValueNS => {
+                if let Some((ctor_def, ctor_vis))
+                        = self.struct_constructors.get(&def_id).cloned() {
+                    let accessible_ctor = self.is_accessible(ctor_vis);
+                    if is_expected(ctor_def) && !accessible_ctor {
+                        err.span_label(span, format!("constructor is not visible \
+                                                      here due to private fields"));
+                    }
+                } else {
+                    // HACK(estebank): find a better way to figure out that this was a
+                    // parser issue where a struct literal is being used on an expression
+                    // where a brace being opened means a block is being started. Look
+                    // ahead for the next text to see if `span` is followed by a `{`.
+                    let sm = self.session.source_map();
+                    let mut sp = span;
+                    loop {
+                        sp = sm.next_point(sp);
+                        match sm.span_to_snippet(sp) {
+                            Ok(ref snippet) => {
+                                if snippet.chars().any(|c| { !c.is_whitespace() }) {
+                                    break;
+                                }
+                            }
+                            _ => break,
+                        }
+                    }
+                    let followed_by_brace = match sm.span_to_snippet(sp) {
+                        Ok(ref snippet) if snippet == "{" => true,
+                        _ => false,
+                    };
+                    // In case this could be a struct literal that needs to be surrounded
+                    // by parenthesis, find the appropriate span.
+                    let mut i = 0;
+                    let mut closing_brace = None;
+                    loop {
+                        sp = sm.next_point(sp);
+                        match sm.span_to_snippet(sp) {
+                            Ok(ref snippet) => {
+                                if snippet == "}" {
+                                    let sp = span.to(sp);
+                                    if let Ok(snippet) = sm.span_to_snippet(sp) {
+                                        closing_brace = Some((sp, snippet));
+                                    }
+                                    break;
+                                }
+                            }
+                            _ => break,
+                        }
+                        i += 1;
+                        // The bigger the span, the more likely we're incorrect --
+                        // bound it to 100 chars long.
+                        if i > 100 {
+                            break;
+                        }
+                    }
+                    match source {
+                        PathSource::Expr(Some(parent)) => {
+                            match parent.node {
+                                ExprKind::MethodCall(ref path_assignment, _)  => {
+                                    err.span_suggestion(
+                                        sm.start_point(parent.span)
+                                            .to(path_assignment.ident.span),
+                                        "use `::` to access an associated function",
+                                        format!("{}::{}",
+                                                path_str,
+                                                path_assignment.ident),
+                                        Applicability::MaybeIncorrect
+                                    );
+                                },
+                                _ => {
+                                    err.span_label(
+                                        span,
+                                        format!("did you mean `{} {{ /* fields */ }}`?",
+                                                path_str),
+                                    );
+                                },
+                            }
+                        },
+                        PathSource::Expr(None) if followed_by_brace == true => {
+                            if let Some((sp, snippet)) = closing_brace {
+                                err.span_suggestion(
+                                    sp,
+                                    "surround the struct literal with parenthesis",
+                                    format!("({})", snippet),
+                                    Applicability::MaybeIncorrect,
+                                );
+                            } else {
+                                err.span_label(
+                                    span,
+                                    format!("did you mean `({} {{ /* fields */ }})`?",
+                                            path_str),
+                                );
+                            }
+                        },
+                        _ => {
+                            err.span_label(
+                                span,
+                                format!("did you mean `{} {{ /* fields */ }}`?",
+                                        path_str),
+                            );
+                        },
+                    }
+                }
+            }
+            (Def::Union(..), _) |
+            (Def::Variant(..), _) |
+            (Def::VariantCtor(_, CtorKind::Fictive), _) if ns == ValueNS => {
+                err.span_label(span, format!("did you mean `{} {{ /* fields */ }}`?",
+                                             path_str));
+            }
+            (Def::SelfTy(..), _) if ns == ValueNS => {
+                err.span_label(span, fallback_label);
+                err.note("can't use `Self` as a constructor, you must use the \
+                          implemented struct");
+            }
+            (Def::TyAlias(_), _) | (Def::AssociatedTy(..), _) if ns == ValueNS => {
+                err.note("can't use a type alias as a constructor");
+            }
+            _ => return false,
+        }
+        true
+    }
+
     /// Handles error reporting for `smart_resolve_path_fragment` function.
     /// Creates base error and amends it with one short label and possibly some longer helps/notes.
     fn smart_resolve_report_errors(
@@ -3137,7 +3324,7 @@ impl<'a> Resolver<'a> {
         let ns = source.namespace();
         let is_expected = &|def| source.is_expected(def);
         let is_enum_variant = &|def| if let Def::Variant(..) = def { true } else { false };
-        
+
         // Make the base error.
         let expected = source.descr_expected();
         let path_str = Segment::names_to_string(path);
@@ -3317,188 +3504,13 @@ impl<'a> Resolver<'a> {
 
         // Try context-dependent help if relaxed lookup didn't work.
         if let Some(def) = def {
-            match (def, source) {
-                (Def::Macro(..), _) => {
-                    err.span_suggestion(
-                        span,
-                        "use `!` to invoke the macro",
-                        format!("{}!", path_str),
-                        Applicability::MaybeIncorrect,
-                    );
-                    return (err, candidates);
-                }
-                (Def::TyAlias(..), PathSource::Trait(_)) => {
-                    err.span_label(span, "type aliases cannot be used as traits");
-                    if nightly_options::is_nightly_build() {
-                        err.note("did you mean to use a trait alias?");
-                    }
-                    return (err, candidates);
-                }
-                (Def::Mod(..), PathSource::Expr(Some(parent))) => match parent.node {
-                    ExprKind::Field(_, ident) => {
-                        err.span_suggestion(
-                            parent.span,
-                            "use the path separator to refer to an item",
-                            format!("{}::{}", path_str, ident),
-                            Applicability::MaybeIncorrect,
-                        );
-                        return (err, candidates);
-                    }
-                    ExprKind::MethodCall(ref segment, ..) => {
-                        let span = parent.span.with_hi(segment.ident.span.hi());
-                        err.span_suggestion(
-                            span,
-                            "use the path separator to refer to an item",
-                            format!("{}::{}", path_str, segment.ident),
-                            Applicability::MaybeIncorrect,
-                        );
-                        return (err, candidates);
-                    }
-                    _ => {}
-                },
-                (Def::Enum(..), PathSource::TupleStruct)
-                    | (Def::Enum(..), PathSource::Expr(..))  => {
-                    if let Some(variants) = self.collect_enum_variants(def) {
-                        err.note(&format!("did you mean to use one \
-                                           of the following variants?\n{}",
-                            variants.iter()
-                                .map(|suggestion| path_names_to_string(suggestion))
-                                .map(|suggestion| format!("- `{}`", suggestion))
-                                .collect::<Vec<_>>()
-                                .join("\n")));
-
-                    } else {
-                        err.note("did you mean to use one of the enum's variants?");
-                    }
-                    return (err, candidates);
-                },
-                (Def::Struct(def_id), _) if ns == ValueNS => {
-                    if let Some((ctor_def, ctor_vis))
-                            = self.struct_constructors.get(&def_id).cloned() {
-                        let accessible_ctor = self.is_accessible(ctor_vis);
-                        if is_expected(ctor_def) && !accessible_ctor {
-                            err.span_label(span, format!("constructor is not visible \
-                                                          here due to private fields"));
-                        }
-                    } else {
-                        // HACK(estebank): find a better way to figure out that this was a
-                        // parser issue where a struct literal is being used on an expression
-                        // where a brace being opened means a block is being started. Look
-                        // ahead for the next text to see if `span` is followed by a `{`.
-                        let sm = self.session.source_map();
-                        let mut sp = span;
-                        loop {
-                            sp = sm.next_point(sp);
-                            match sm.span_to_snippet(sp) {
-                                Ok(ref snippet) => {
-                                    if snippet.chars().any(|c| { !c.is_whitespace() }) {
-                                        break;
-                                    }
-                                }
-                                _ => break,
-                            }
-                        }
-                        let followed_by_brace = match sm.span_to_snippet(sp) {
-                            Ok(ref snippet) if snippet == "{" => true,
-                            _ => false,
-                        };
-                        // In case this could be a struct literal that needs to be surrounded
-                        // by parenthesis, find the appropriate span.
-                        let mut i = 0;
-                        let mut closing_brace = None;
-                        loop {
-                            sp = sm.next_point(sp);
-                            match sm.span_to_snippet(sp) {
-                                Ok(ref snippet) => {
-                                    if snippet == "}" {
-                                        let sp = span.to(sp);
-                                        if let Ok(snippet) = sm.span_to_snippet(sp) {
-                                            closing_brace = Some((sp, snippet));
-                                        }
-                                        break;
-                                    }
-                                }
-                                _ => break,
-                            }
-                            i += 1;
-                            // The bigger the span, the more likely we're
-                            // incorrect. Bound it to 100 chars long.
-                            if i > 100 {
-                                break;
-                            }
-                        }
-                        match source {
-                            PathSource::Expr(Some(parent)) => {
-                                match parent.node {
-                                    ExprKind::MethodCall(ref path_assignment, _)  => {
-                                        err.span_suggestion(
-                                            sm.start_point(parent.span)
-                                                .to(path_assignment.ident.span),
-                                            "use `::` to access an associated function",
-                                            format!("{}::{}",
-                                                    path_str,
-                                                    path_assignment.ident),
-                                            Applicability::MaybeIncorrect
-                                        );
-                                        return (err, candidates);
-                                    },
-                                    _ => {
-                                        err.span_label(
-                                            span,
-                                            format!("did you mean `{} {{ /* fields */ }}`?",
-                                                    path_str),
-                                        );
-                                        return (err, candidates);
-                                    },
-                                }
-                            },
-                            PathSource::Expr(None) if followed_by_brace == true => {
-                                if let Some((sp, snippet)) = closing_brace {
-                                    err.span_suggestion(
-                                        sp,
-                                        "surround the struct literal with parenthesis",
-                                        format!("({})", snippet),
-                                        Applicability::MaybeIncorrect,
-                                    );
-                                } else {
-                                    err.span_label(
-                                        span,
-                                        format!("did you mean `({} {{ /* fields */ }})`?",
-                                                path_str),
-                                    );
-                                }
-                                return (err, candidates);
-                            },
-                            _ => {
-                                err.span_label(
-                                    span,
-                                    format!("did you mean `{} {{ /* fields */ }}`?",
-                                            path_str),
-                                );
-                                return (err, candidates);
-                            },
-                        }
-                    }
-                    return (err, candidates);
-                }
-                (Def::Union(..), _) |
-                (Def::Variant(..), _) |
-                (Def::VariantCtor(_, CtorKind::Fictive), _) if ns == ValueNS => {
-                    err.span_label(span, format!("did you mean `{} {{ /* fields */ }}`?",
-                                                 path_str));
-                    return (err, candidates);
-                }
-                (Def::SelfTy(..), _) if ns == ValueNS => {
-                    err.span_label(span, fallback_label);
-                    err.note("can't use `Self` as a constructor, you must use the \
-                              implemented struct");
-                    return (err, candidates);
-                }
-                (Def::TyAlias(_), _) | (Def::AssociatedTy(..), _) if ns == ValueNS => {
-                    err.note("can't use a type alias as a constructor");
-                    return (err, candidates);
-                }
-                _ => {}
+            if self.smart_resolve_context_dep_help(&mut err,
+                                                   span,
+                                                   source,
+                                                   def,
+                                                   &path_str,
+                                                   &fallback_label) {
+                return (err, candidates);
             }
         }