about summary refs log tree commit diff
diff options
context:
space:
mode:
authorJeffrey Seyfried <jeffrey.seyfried@gmail.com>2016-04-24 21:10:54 +0000
committerJeffrey Seyfried <jeffrey.seyfried@gmail.com>2016-04-29 18:34:49 +0000
commita70e42a953d71e356e170de8b6bd525d4a32dc4d (patch)
tree5e96247c033020600e3bc18a483663676f8de60d
parent5a4e0b14e39989f327f9f8103cf38ec43cd22131 (diff)
downloadrust-a70e42a953d71e356e170de8b6bd525d4a32dc4d.tar.gz
rust-a70e42a953d71e356e170de8b6bd525d4a32dc4d.zip
Remove use of `ast_map.expect_item()` and improve diagnostics (fixes #33186)
-rw-r--r--src/librustc_resolve/lib.rs83
-rw-r--r--src/test/compile-fail/suggest-path-instead-of-mod-dot-item.rs12
2 files changed, 49 insertions, 46 deletions
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index c0a22151a59..b83d6e9363e 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -68,7 +68,7 @@ use rustc::hir::intravisit::{self, FnKind, Visitor};
 use rustc::hir;
 use rustc::hir::{Arm, BindByRef, BindByValue, BindingMode, Block};
 use rustc::hir::Crate;
-use rustc::hir::{Expr, ExprAgain, ExprBreak, ExprCall, ExprField};
+use rustc::hir::{Expr, ExprAgain, ExprBreak, ExprField};
 use rustc::hir::{ExprLoop, ExprWhile, ExprMethodCall};
 use rustc::hir::{ExprPath, ExprStruct, FnDecl};
 use rustc::hir::{ForeignItemFn, ForeignItemStatic, Generics};
@@ -163,7 +163,7 @@ enum ResolutionError<'a> {
     /// error E0424: `self` is not available in a static method
     SelfNotAvailableInStaticMethod,
     /// error E0425: unresolved name
-    UnresolvedName(&'a str, &'a str, UnresolvedNameContext),
+    UnresolvedName(&'a str, &'a str, UnresolvedNameContext<'a>),
     /// error E0426: use of undeclared label
     UndeclaredLabel(&'a str),
     /// error E0427: cannot use `ref` binding mode with ...
@@ -186,12 +186,12 @@ enum ResolutionError<'a> {
 
 /// Context of where `ResolutionError::UnresolvedName` arose.
 #[derive(Clone, PartialEq, Eq, Debug)]
-enum UnresolvedNameContext {
-    /// `PathIsMod(id)` indicates that a given path, used in
+enum UnresolvedNameContext<'a> {
+    /// `PathIsMod(parent)` indicates that a given path, used in
     /// expression context, actually resolved to a module rather than
-    /// a value. The `id` attached to the variant is the node id of
-    /// the erroneous path expression.
-    PathIsMod(ast::NodeId),
+    /// a value. The optional expression attached to the variant is the
+    /// the parent of the erroneous path expression.
+    PathIsMod(Option<&'a Expr>),
 
     /// `Other` means we have no extra information about the context
     /// of the unresolved name error. (Maybe we could eliminate all
@@ -419,39 +419,25 @@ fn resolve_struct_error<'b, 'a: 'b, 'tcx: 'a>(resolver: &'b Resolver<'a, 'tcx>,
 
             match context {
                 UnresolvedNameContext::Other => { } // no help available
-                UnresolvedNameContext::PathIsMod(id) => {
-                    let mut help_msg = String::new();
-                    let parent_id = resolver.ast_map.get_parent_node(id);
-                    if let Some(hir_map::Node::NodeExpr(e)) = resolver.ast_map.find(parent_id) {
-                        match e.node {
-                            ExprField(_, ident) => {
-                                help_msg = format!("To reference an item from the \
-                                                    `{module}` module, use \
-                                                    `{module}::{ident}`",
-                                                   module = path,
-                                                   ident = ident.node);
-                            }
-                            ExprMethodCall(ident, _, _) => {
-                                help_msg = format!("To call a function from the \
-                                                    `{module}` module, use \
-                                                    `{module}::{ident}(..)`",
-                                                   module = path,
-                                                   ident = ident.node);
-                            }
-                            ExprCall(_, _) => {
-                                help_msg = format!("No function corresponds to `{module}(..)`",
-                                                   module = path);
-                            }
-                            _ => { } // no help available
+                UnresolvedNameContext::PathIsMod(parent) => {
+                    err.fileline_help(span, &match parent.map(|parent| &parent.node) {
+                        Some(&ExprField(_, ident)) => {
+                            format!("To reference an item from the `{module}` module, \
+                                     use `{module}::{ident}`",
+                                    module = path,
+                                    ident = ident.node)
                         }
-                    } else {
-                        help_msg = format!("Module `{module}` cannot be the value of an expression",
-                                           module = path);
-                    }
-
-                    if !help_msg.is_empty() {
-                        err.fileline_help(span, &help_msg);
-                    }
+                        Some(&ExprMethodCall(ident, _, _)) => {
+                            format!("To call a function from the `{module}` module, \
+                                     use `{module}::{ident}(..)`",
+                                    module = path,
+                                    ident = ident.node)
+                        }
+                        _ => {
+                            format!("Module `{module}` cannot be used as an expression",
+                                    module = path)
+                        }
+                    });
                 }
             }
             err
@@ -553,7 +539,7 @@ impl<'a, 'v, 'tcx> Visitor<'v> for Resolver<'a, 'tcx> {
         self.resolve_block(block);
     }
     fn visit_expr(&mut self, expr: &Expr) {
-        self.resolve_expr(expr);
+        self.resolve_expr(expr, None);
     }
     fn visit_local(&mut self, local: &Local) {
         self.resolve_local(local);
@@ -2850,7 +2836,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         } SuggestionType::NotFound
     }
 
-    fn resolve_expr(&mut self, expr: &Expr) {
+    fn resolve_expr(&mut self, expr: &Expr, parent: Option<&Expr>) {
         // First, record candidate traits for this expression if it could
         // result in the invocation of a method call.
 
@@ -2995,7 +2981,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                                                                    UseLexicalScope,
                                                                    expr.span) {
                                         Success(_) => {
-                                            context = UnresolvedNameContext::PathIsMod(expr.id);
+                                            context = UnresolvedNameContext::PathIsMod(parent);
                                         },
                                         _ => {},
                                     };
@@ -3069,6 +3055,19 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                     }
                 }
             }
+            ExprField(ref subexpression, _) => {
+                self.resolve_expr(subexpression, Some(expr));
+            }
+            ExprMethodCall(_, ref types, ref arguments) => {
+                let mut arguments = arguments.iter();
+                self.resolve_expr(arguments.next().unwrap(), Some(expr));
+                for argument in arguments {
+                    self.resolve_expr(argument, None);
+                }
+                for ty in types.iter() {
+                    self.visit_ty(ty);
+                }
+            }
 
             _ => {
                 intravisit::walk_expr(self, expr);
diff --git a/src/test/compile-fail/suggest-path-instead-of-mod-dot-item.rs b/src/test/compile-fail/suggest-path-instead-of-mod-dot-item.rs
index 1d04679fd11..412c90fd214 100644
--- a/src/test/compile-fail/suggest-path-instead-of-mod-dot-item.rs
+++ b/src/test/compile-fail/suggest-path-instead-of-mod-dot-item.rs
@@ -47,10 +47,14 @@ fn h4() -> i32 {
         //~| HELP To reference an item from the `a::b` module, use `a::b::J`
 }
 
-fn h5() -> i32 {
-    a.b.f()
+fn h5() {
+    a.b.f();
         //~^ ERROR E0425
         //~| HELP To reference an item from the `a` module, use `a::b`
+    let v = Vec::new();
+    v.push(a::b);
+        //~^ ERROR E0425
+        //~| HELP Module `a::b` cannot be used as an expression
 }
 
 fn h6() -> i32 {
@@ -62,11 +66,11 @@ fn h6() -> i32 {
 fn h7() {
     a::b
         //~^ ERROR E0425
-        //~| HELP Module `a::b` cannot be the value of an expression
+        //~| HELP Module `a::b` cannot be used as an expression
 }
 
 fn h8() -> i32 {
     a::b()
         //~^ ERROR E0425
-        //~| HELP No function corresponds to `a::b(..)`
+        //~| HELP Module `a::b` cannot be used as an expression
 }