Skip to content

Commit 145747e

Browse files
Don't suggest using fields in a static method
1 parent e87cd7e commit 145747e

File tree

3 files changed

+93
-24
lines changed

3 files changed

+93
-24
lines changed

src/librustc_resolve/lib.rs

+64-22
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ use syntax::ast::{Arm, BindingMode, Block, Crate, Expr, ExprKind};
6767
use syntax::ast::{FnDecl, ForeignItem, ForeignItemKind, Generics};
6868
use syntax::ast::{Item, ItemKind, ImplItem, ImplItemKind};
6969
use syntax::ast::{Local, Pat, PatKind, Path};
70-
use syntax::ast::{PathSegment, PathParameters, TraitItemKind, TraitRef, Ty, TyKind};
70+
use syntax::ast::{PathSegment, PathParameters, SelfKind, TraitItemKind, TraitRef, Ty, TyKind};
7171

7272
use std::collections::{HashMap, HashSet};
7373
use std::cell::{Cell, RefCell};
@@ -148,7 +148,13 @@ enum ResolutionError<'a> {
148148
/// error E0424: `self` is not available in a static method
149149
SelfNotAvailableInStaticMethod,
150150
/// error E0425: unresolved name
151-
UnresolvedName(&'a str, &'a str, UnresolvedNameContext<'a>),
151+
UnresolvedName {
152+
path: &'a str,
153+
message: &'a str,
154+
context: UnresolvedNameContext<'a>,
155+
is_static_method: bool,
156+
is_field: bool
157+
},
152158
/// error E0426: use of undeclared label
153159
UndeclaredLabel(&'a str),
154160
/// error E0427: cannot use `ref` binding mode with ...
@@ -406,16 +412,21 @@ fn resolve_struct_error<'b, 'a: 'b, 'c>(resolver: &'b Resolver<'a>,
406412
"`self` is not available in a static method. Maybe a `self` \
407413
argument is missing?")
408414
}
409-
ResolutionError::UnresolvedName(path, msg, context) => {
415+
ResolutionError::UnresolvedName { path, message: msg, context, is_static_method,
416+
is_field } => {
410417
let mut err = struct_span_err!(resolver.session,
411418
span,
412419
E0425,
413420
"unresolved name `{}`{}",
414421
path,
415422
msg);
416-
417423
match context {
418-
UnresolvedNameContext::Other => { } // no help available
424+
UnresolvedNameContext::Other => {
425+
if msg.is_empty() && is_static_method && is_field {
426+
err.help("this is an associated function, you don't have access to \
427+
this type's fields or methods");
428+
}
429+
}
419430
UnresolvedNameContext::PathIsMod(parent) => {
420431
err.help(&match parent.map(|parent| &parent.node) {
421432
Some(&ExprKind::Field(_, ident)) => {
@@ -596,7 +607,7 @@ impl<'a, 'v> Visitor<'v> for Resolver<'a> {
596607
}
597608
FnKind::Method(_, sig, _) => {
598609
self.visit_generics(&sig.generics);
599-
MethodRibKind
610+
MethodRibKind(sig.explicit_self.node == SelfKind::Static)
600611
}
601612
FnKind::Closure => ClosureRibKind(node_id),
602613
};
@@ -666,7 +677,9 @@ enum RibKind<'a> {
666677
// methods. Allow references to ty params that impl or trait
667678
// binds. Disallow any other upvars (including other ty params that are
668679
// upvars).
669-
MethodRibKind,
680+
//
681+
// The boolean value represents the fact that this method is static or not.
682+
MethodRibKind(bool),
670683

671684
// We passed through an item scope. Disallow upvars.
672685
ItemRibKind,
@@ -1095,7 +1108,13 @@ impl<'a> hir::lowering::Resolver for Resolver<'a> {
10951108
Err(false) => {
10961109
let path_name = &format!("{}", path);
10971110
let error =
1098-
ResolutionError::UnresolvedName(path_name, "", UnresolvedNameContext::Other);
1111+
ResolutionError::UnresolvedName {
1112+
path: path_name,
1113+
message: "",
1114+
context: UnresolvedNameContext::Other,
1115+
is_static_method: false,
1116+
is_field: false
1117+
};
10991118
resolve_error(self, path.span, error);
11001119
Def::Err
11011120
}
@@ -1653,7 +1672,9 @@ impl<'a> Resolver<'a> {
16531672
let type_parameters =
16541673
HasTypeParameters(&sig.generics,
16551674
FnSpace,
1656-
MethodRibKind);
1675+
MethodRibKind(
1676+
sig.explicit_self.node ==
1677+
SelfKind::Static));
16571678
this.with_type_parameter_rib(type_parameters, |this| {
16581679
visit::walk_trait_item(this, trait_item)
16591680
});
@@ -1772,7 +1793,10 @@ impl<'a> Resolver<'a> {
17721793
self.value_ribs.pop();
17731794
}
17741795

1775-
fn resolve_function(&mut self, rib_kind: RibKind<'a>, declaration: &FnDecl, block: &Block) {
1796+
fn resolve_function(&mut self,
1797+
rib_kind: RibKind<'a>,
1798+
declaration: &FnDecl,
1799+
block: &Block) {
17761800
// Create a value rib for the function.
17771801
self.value_ribs.push(Rib::new(rib_kind));
17781802

@@ -1979,7 +2003,9 @@ impl<'a> Resolver<'a> {
19792003
let type_parameters =
19802004
HasTypeParameters(&sig.generics,
19812005
FnSpace,
1982-
MethodRibKind);
2006+
MethodRibKind(
2007+
sig.explicit_self.node ==
2008+
SelfKind::Static));
19832009
this.with_type_parameter_rib(type_parameters, |this| {
19842010
visit::walk_impl_item(this, impl_item);
19852011
});
@@ -2673,7 +2699,7 @@ impl<'a> Resolver<'a> {
26732699
def = Def::Upvar(node_def_id, node_id, depth, function_id);
26742700
seen.insert(node_id, depth);
26752701
}
2676-
ItemRibKind | MethodRibKind => {
2702+
ItemRibKind | MethodRibKind(_) => {
26772703
// This was an attempt to access an upvar inside a
26782704
// named function item. This is not allowed, so we
26792705
// report an error.
@@ -2695,7 +2721,7 @@ impl<'a> Resolver<'a> {
26952721
Def::TyParam(..) | Def::SelfTy(..) => {
26962722
for rib in ribs {
26972723
match rib.kind {
2698-
NormalRibKind | MethodRibKind | ClosureRibKind(..) |
2724+
NormalRibKind | MethodRibKind(_) | ClosureRibKind(..) |
26992725
ModuleRibKind(..) => {
27002726
// Nothing to do. Continue.
27012727
}
@@ -2988,9 +3014,13 @@ impl<'a> Resolver<'a> {
29883014
// `resolve_path` already reported the error
29893015
} else {
29903016
let mut method_scope = false;
3017+
let mut is_static = false;
29913018
self.value_ribs.iter().rev().all(|rib| {
29923019
method_scope = match rib.kind {
2993-
MethodRibKind => true,
3020+
MethodRibKind(is_static_) => {
3021+
is_static = is_static_;
3022+
true
3023+
}
29943024
ItemRibKind | ConstantItemRibKind => false,
29953025
_ => return true, // Keep advancing
29963026
};
@@ -3004,22 +3034,29 @@ impl<'a> Resolver<'a> {
30043034
ResolutionError::SelfNotAvailableInStaticMethod);
30053035
} else {
30063036
let last_name = path.segments.last().unwrap().identifier.name;
3007-
let mut msg = match self.find_fallback_in_self_type(last_name) {
3037+
let (mut msg, is_field) =
3038+
match self.find_fallback_in_self_type(last_name) {
30083039
NoSuggestion => {
30093040
// limit search to 5 to reduce the number
30103041
// of stupid suggestions
3011-
match self.find_best_match(&path_name) {
3042+
(match self.find_best_match(&path_name) {
30123043
SuggestionType::Macro(s) => {
30133044
format!("the macro `{}`", s)
30143045
}
30153046
SuggestionType::Function(s) => format!("`{}`", s),
30163047
SuggestionType::NotFound => "".to_string(),
3017-
}
3048+
}, false)
3049+
}
3050+
Field => {
3051+
(if is_static && method_scope {
3052+
"".to_string()
3053+
} else {
3054+
format!("`self.{}`", path_name)
3055+
}, true)
30183056
}
3019-
Field => format!("`self.{}`", path_name),
3020-
TraitItem => format!("to call `self.{}`", path_name),
3057+
TraitItem => (format!("to call `self.{}`", path_name), false),
30213058
TraitMethod(path_str) =>
3022-
format!("to call `{}::{}`", path_str, path_name),
3059+
(format!("to call `{}::{}`", path_str, path_name), false),
30233060
};
30243061

30253062
let mut context = UnresolvedNameContext::Other;
@@ -3044,8 +3081,13 @@ impl<'a> Resolver<'a> {
30443081

30453082
resolve_error(self,
30463083
expr.span,
3047-
ResolutionError::UnresolvedName(
3048-
&path_name, &msg, context));
3084+
ResolutionError::UnresolvedName {
3085+
path: &path_name,
3086+
message: &msg,
3087+
context: context,
3088+
is_static_method: method_scope && is_static,
3089+
is_field: is_field,
3090+
});
30493091
}
30503092
}
30513093
}

src/test/compile-fail/issue-2356.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,8 @@ impl MaybeDog {
3232
impl Groom for cat {
3333
fn shave(other: usize) {
3434
whiskers -= other;
35-
//~^ ERROR: unresolved name `whiskers`. Did you mean `self.whiskers`?
35+
//~^ ERROR: unresolved name `whiskers`
36+
//~| HELP this is an associated function
3637
shave(4);
3738
//~^ ERROR: unresolved name `shave`. Did you mean to call `Groom::shave`?
3839
purr();
@@ -77,7 +78,8 @@ impl cat {
7778

7879
pub fn grow_older(other:usize) {
7980
whiskers = 4;
80-
//~^ ERROR: unresolved name `whiskers`. Did you mean `self.whiskers`?
81+
//~^ ERROR: unresolved name `whiskers`
82+
//~| HELP this is an associated function
8183
purr_louder();
8284
//~^ ERROR: unresolved name `purr_louder`
8385
}
@@ -86,5 +88,6 @@ impl cat {
8688
fn main() {
8789
self += 1;
8890
//~^ ERROR: unresolved name `self`
91+
//~| HELP: Module
8992
// it's a bug if this suggests a missing `self` as we're not in a method
9093
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
fn f(_: bool) {}
12+
13+
struct Foo {
14+
cx: bool,
15+
}
16+
17+
impl Foo {
18+
fn bar() {
19+
f(cx); //~ ERROR E0425
20+
//~| HELP this is an associated function
21+
}
22+
}
23+
24+
fn main() {}

0 commit comments

Comments
 (0)