From 145747ebfc5518a20bf7ccddebc20c49bb4203ba Mon Sep 17 00:00:00 2001 From: ggomez Date: Fri, 13 May 2016 17:17:10 +0200 Subject: [PATCH] Don't suggest using fields in a static method --- src/librustc_resolve/lib.rs | 86 ++++++++++++++----- src/test/compile-fail/issue-2356.rs | 7 +- .../unresolved_static_type_field.rs | 24 ++++++ 3 files changed, 93 insertions(+), 24 deletions(-) create mode 100644 src/test/compile-fail/unresolved_static_type_field.rs diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 5b447a1690f..a7188f46ca1 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -67,7 +67,7 @@ use syntax::ast::{Arm, BindingMode, Block, Crate, Expr, ExprKind}; 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 @@ impl<'a, 'v> Visitor<'v> for Resolver<'a> { } 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 @@ impl<'a> hir::lowering::Resolver for Resolver<'a> { 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 @@ impl<'a> Resolver<'a> { 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 @@ impl<'a> Resolver<'a> { 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 @@ impl<'a> Resolver<'a> { 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 @@ impl<'a> Resolver<'a> { 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 @@ impl<'a> Resolver<'a> { 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 @@ impl<'a> Resolver<'a> { // `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 @@ impl<'a> Resolver<'a> { 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 => format!("`self.{}`", path_name), - TraitItem => format!("to call `self.{}`", path_name), + Field => { + (if is_static && method_scope { + "".to_string() + } else { + format!("`self.{}`", path_name) + }, true) + } + 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 @@ impl<'a> Resolver<'a> { 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, + }); } } } diff --git a/src/test/compile-fail/issue-2356.rs b/src/test/compile-fail/issue-2356.rs index 6b81afe13c6..5e816bcfa61 100644 --- a/src/test/compile-fail/issue-2356.rs +++ b/src/test/compile-fail/issue-2356.rs @@ -32,7 +32,8 @@ impl MaybeDog { 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 @@ impl cat { 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 @@ impl cat { 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 index 00000000000..80f6108f02d --- /dev/null +++ b/src/test/compile-fail/unresolved_static_type_field.rs @@ -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 or the MIT license +// , 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() {}