]> git.lizzy.rs Git - rust.git/commitdiff
Don't suggest using fields in a static method
authorggomez <guillaume1.gomez@gmail.com>
Fri, 13 May 2016 15:17:10 +0000 (17:17 +0200)
committerGuillaume Gomez <guillaume1.gomez@gmail.com>
Sun, 22 May 2016 23:18:06 +0000 (01:18 +0200)
src/librustc_resolve/lib.rs
src/test/compile-fail/issue-2356.rs
src/test/compile-fail/unresolved_static_type_field.rs [new file with mode: 0644]

index 5b447a1690f6c8daa585f4d19b0b1bfe93313a8c..a7188f46ca12b7f674d0beca387fae47b040cd49 100644 (file)
@@ -67,7 +67,7 @@
 use syntax::ast::{FnDecl, ForeignItem, ForeignItemKind, Generics};
 use syntax::ast::{Item, ItemKind, ImplItem, ImplItemKind};
 use syntax::ast::{Local, Pat, PatKind, Path};
-use syntax::ast::{PathSegment, PathParameters, TraitItemKind, TraitRef, Ty, TyKind};
+use syntax::ast::{PathSegment, PathParameters, SelfKind, TraitItemKind, TraitRef, Ty, TyKind};
 
 use std::collections::{HashMap, HashSet};
 use std::cell::{Cell, RefCell};
@@ -148,7 +148,13 @@ enum ResolutionError<'a> {
     /// error E0424: `self` is not available in a static method
     SelfNotAvailableInStaticMethod,
     /// error E0425: unresolved name
-    UnresolvedName(&'a str, &'a str, UnresolvedNameContext<'a>),
+    UnresolvedName {
+        path: &'a str,
+        message: &'a str,
+        context: UnresolvedNameContext<'a>,
+        is_static_method: bool,
+        is_field: bool
+    },
     /// error E0426: use of undeclared label
     UndeclaredLabel(&'a str),
     /// error E0427: cannot use `ref` binding mode with ...
@@ -406,16 +412,21 @@ fn resolve_struct_error<'b, 'a: 'b, 'c>(resolver: &'b Resolver<'a>,
                              "`self` is not available in a static method. Maybe a `self` \
                              argument is missing?")
         }
-        ResolutionError::UnresolvedName(path, msg, context) => {
+        ResolutionError::UnresolvedName { path, message: msg, context, is_static_method,
+                                          is_field } => {
             let mut err = struct_span_err!(resolver.session,
                                            span,
                                            E0425,
                                            "unresolved name `{}`{}",
                                            path,
                                            msg);
-
             match context {
-                UnresolvedNameContext::Other => { } // no help available
+                UnresolvedNameContext::Other => {
+                    if msg.is_empty() && is_static_method && is_field {
+                        err.help("this is an associated function, you don't have access to \
+                                  this type's fields or methods");
+                    }
+                }
                 UnresolvedNameContext::PathIsMod(parent) => {
                     err.help(&match parent.map(|parent| &parent.node) {
                         Some(&ExprKind::Field(_, ident)) => {
@@ -596,7 +607,7 @@ fn visit_fn(&mut self,
             }
             FnKind::Method(_, sig, _) => {
                 self.visit_generics(&sig.generics);
-                MethodRibKind
+                MethodRibKind(sig.explicit_self.node == SelfKind::Static)
             }
             FnKind::Closure => ClosureRibKind(node_id),
         };
@@ -666,7 +677,9 @@ enum RibKind<'a> {
     // methods. Allow references to ty params that impl or trait
     // binds. Disallow any other upvars (including other ty params that are
     // upvars).
-    MethodRibKind,
+    //
+    // The boolean value represents the fact that this method is static or not.
+    MethodRibKind(bool),
 
     // We passed through an item scope. Disallow upvars.
     ItemRibKind,
@@ -1095,7 +1108,13 @@ fn resolve_generated_global_path(&mut self, path: &hir::Path, is_value: bool) ->
             Err(false) => {
                 let path_name = &format!("{}", path);
                 let error =
-                    ResolutionError::UnresolvedName(path_name, "", UnresolvedNameContext::Other);
+                    ResolutionError::UnresolvedName {
+                        path: path_name,
+                        message: "",
+                        context: UnresolvedNameContext::Other,
+                        is_static_method: false,
+                        is_field: false
+                    };
                 resolve_error(self, path.span, error);
                 Def::Err
             }
@@ -1653,7 +1672,9 @@ fn resolve_item(&mut self, item: &Item) {
                                     let type_parameters =
                                         HasTypeParameters(&sig.generics,
                                                           FnSpace,
-                                                          MethodRibKind);
+                                                          MethodRibKind(
+                                                             sig.explicit_self.node ==
+                                                             SelfKind::Static));
                                     this.with_type_parameter_rib(type_parameters, |this| {
                                         visit::walk_trait_item(this, trait_item)
                                     });
@@ -1772,7 +1793,10 @@ fn with_constant_rib<F>(&mut self, f: F)
         self.value_ribs.pop();
     }
 
-    fn resolve_function(&mut self, rib_kind: RibKind<'a>, declaration: &FnDecl, block: &Block) {
+    fn resolve_function(&mut self,
+                        rib_kind: RibKind<'a>,
+                        declaration: &FnDecl,
+                        block: &Block) {
         // Create a value rib for the function.
         self.value_ribs.push(Rib::new(rib_kind));
 
@@ -1979,7 +2003,9 @@ fn resolve_implementation(&mut self,
                                     let type_parameters =
                                         HasTypeParameters(&sig.generics,
                                                           FnSpace,
-                                                          MethodRibKind);
+                                                          MethodRibKind(
+                                                            sig.explicit_self.node ==
+                                                            SelfKind::Static));
                                     this.with_type_parameter_rib(type_parameters, |this| {
                                         visit::walk_impl_item(this, impl_item);
                                     });
@@ -2673,7 +2699,7 @@ fn adjust_local_def(&mut self, local_def: LocalDef, span: Span) -> Option<Def> {
                             def = Def::Upvar(node_def_id, node_id, depth, function_id);
                             seen.insert(node_id, depth);
                         }
-                        ItemRibKind | MethodRibKind => {
+                        ItemRibKind | MethodRibKind(_) => {
                             // This was an attempt to access an upvar inside a
                             // named function item. This is not allowed, so we
                             // report an error.
@@ -2695,7 +2721,7 @@ fn adjust_local_def(&mut self, local_def: LocalDef, span: Span) -> Option<Def> {
             Def::TyParam(..) | Def::SelfTy(..) => {
                 for rib in ribs {
                     match rib.kind {
-                        NormalRibKind | MethodRibKind | ClosureRibKind(..) |
+                        NormalRibKind | MethodRibKind(_) | ClosureRibKind(..) |
                         ModuleRibKind(..) => {
                             // Nothing to do. Continue.
                         }
@@ -2988,9 +3014,13 @@ fn resolve_expr(&mut self, expr: &Expr, parent: Option<&Expr>) {
                             // `resolve_path` already reported the error
                         } else {
                             let mut method_scope = false;
+                            let mut is_static = false;
                             self.value_ribs.iter().rev().all(|rib| {
                                 method_scope = match rib.kind {
-                                    MethodRibKind => true,
+                                    MethodRibKind(is_static_) => {
+                                        is_static = is_static_;
+                                        true
+                                    }
                                     ItemRibKind | ConstantItemRibKind => false,
                                     _ => return true, // Keep advancing
                                 };
@@ -3004,22 +3034,29 @@ fn resolve_expr(&mut self, expr: &Expr, parent: Option<&Expr>) {
                                               ResolutionError::SelfNotAvailableInStaticMethod);
                             } else {
                                 let last_name = path.segments.last().unwrap().identifier.name;
-                                let mut msg = match self.find_fallback_in_self_type(last_name) {
+                                let (mut msg, is_field) =
+                                    match self.find_fallback_in_self_type(last_name) {
                                     NoSuggestion => {
                                         // limit search to 5 to reduce the number
                                         // of stupid suggestions
-                                        match self.find_best_match(&path_name) {
+                                        (match self.find_best_match(&path_name) {
                                             SuggestionType::Macro(s) => {
                                                 format!("the macro `{}`", s)
                                             }
                                             SuggestionType::Function(s) => format!("`{}`", s),
                                             SuggestionType::NotFound => "".to_string(),
-                                        }
+                                        }, false)
+                                    }
+                                    Field => {
+                                        (if is_static && method_scope {
+                                            "".to_string()
+                                        } else {
+                                            format!("`self.{}`", path_name)
+                                        }, true)
                                     }
-                                    Field => format!("`self.{}`", path_name),
-                                    TraitItem => format!("to call `self.{}`", path_name),
+                                    TraitItem => (format!("to call `self.{}`", path_name), false),
                                     TraitMethod(path_str) =>
-                                        format!("to call `{}::{}`", path_str, path_name),
+                                        (format!("to call `{}::{}`", path_str, path_name), false),
                                 };
 
                                 let mut context =  UnresolvedNameContext::Other;
@@ -3044,8 +3081,13 @@ fn resolve_expr(&mut self, expr: &Expr, parent: Option<&Expr>) {
 
                                 resolve_error(self,
                                               expr.span,
-                                              ResolutionError::UnresolvedName(
-                                                  &path_name, &msg, context));
+                                              ResolutionError::UnresolvedName {
+                                                  path: &path_name,
+                                                  message: &msg,
+                                                  context: context,
+                                                  is_static_method: method_scope && is_static,
+                                                  is_field: is_field,
+                                              });
                             }
                         }
                     }
index 6b81afe13c671d5fca639f058b7c8fdc4ada1e03..5e816bcfa61e44493aa733db8782595ea55a13c6 100644 (file)
@@ -32,7 +32,8 @@ fn bark() {
 impl Groom for cat {
   fn shave(other: usize) {
     whiskers -= other;
-    //~^ ERROR: unresolved name `whiskers`. Did you mean `self.whiskers`?
+    //~^ ERROR: unresolved name `whiskers`
+    //~| HELP this is an associated function
     shave(4);
     //~^ ERROR: unresolved name `shave`. Did you mean to call `Groom::shave`?
     purr();
@@ -77,7 +78,8 @@ fn burn_whiskers(&mut self) {
 
   pub fn grow_older(other:usize) {
     whiskers = 4;
-    //~^ ERROR: unresolved name `whiskers`. Did you mean `self.whiskers`?
+    //~^ ERROR: unresolved name `whiskers`
+    //~| HELP this is an associated function
     purr_louder();
     //~^ ERROR: unresolved name `purr_louder`
   }
@@ -86,5 +88,6 @@ pub fn grow_older(other:usize) {
 fn main() {
     self += 1;
     //~^ ERROR: unresolved name `self`
+    //~| HELP: Module
     // it's a bug if this suggests a missing `self` as we're not in a method
 }
diff --git a/src/test/compile-fail/unresolved_static_type_field.rs b/src/test/compile-fail/unresolved_static_type_field.rs
new file mode 100644 (file)
index 0000000..80f6108
--- /dev/null
@@ -0,0 +1,24 @@
+// 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.
+
+fn f(_: bool) {}
+
+struct Foo {
+    cx: bool,
+}
+
+impl Foo {
+    fn bar() {
+        f(cx); //~ ERROR E0425
+               //~| HELP this is an associated function
+    }
+}
+
+fn main() {}