}
}
+enum FallbackSuggestion {
+ NoSuggestion,
+ Field,
+ Method,
+ TraitMethod,
+ StaticMethod(StrBuf),
+ StaticTraitMethod(StrBuf),
+}
+
enum TypeParameters<'a> {
NoTypeParameters, //< No type parameters.
HasTypeParameters(&'a Generics, //< Type parameters.
graph_root: graph_root,
method_map: RefCell::new(FnvHashMap::new()),
- structs: HashSet::new(),
+ structs: FnvHashMap::new(),
unresolved_imports: 0,
type_ribs: RefCell::new(Vec::new()),
label_ribs: RefCell::new(Vec::new()),
- current_trait_refs: None,
+ current_trait_ref: None,
+ current_self_type: None,
self_ident: special_idents::self_,
type_self_ident: special_idents::type_self,
graph_root: NameBindings,
method_map: RefCell<FnvHashMap<(Name, DefId), ast::ExplicitSelf_>>,
- structs: HashSet<DefId>,
+ structs: FnvHashMap<DefId, Vec<Name>>,
// The number of imports that are currently unresolved.
unresolved_imports: uint,
label_ribs: RefCell<Vec<Rib>>,
// The trait that the current context can refer to.
- current_trait_refs: Option<Vec<DefId> >,
+ current_trait_ref: Option<(DefId, TraitRef)>,
+
+ // The current self type if inside an impl (used for better errors).
+ current_self_type: Option<Ty>,
// The ident for the keyword "self".
self_ident: Ident,
None
});
- // Record the def ID of this struct.
- self.structs.insert(local_def(item.id));
+ // Record the def ID and fields of this struct.
+ let named_fields = struct_def.fields.iter().filter_map(|f| {
+ match f.node.kind {
+ NamedField(ident, _) => Some(ident.name),
+ UnnamedField(_) => None
+ }
+ }).collect();
+ self.structs.insert(local_def(item.id), named_fields);
parent
}
child.define_type(DefVariant(item_id,
local_def(variant.node.id), true),
variant.span, is_public);
- self.structs.insert(local_def(variant.node.id));
+
+ // Not adding fields for variants as they are not accessed with a self receiver
+ self.structs.insert(local_def(variant.node.id), Vec::new());
}
}
}
self.external_exports.contains(&enum_did);
if is_struct {
child_name_bindings.define_type(def, DUMMY_SP, is_exported);
- self.structs.insert(variant_id);
+ // Not adding fields for variants as they are not accessed with a self receiver
+ self.structs.insert(variant_id, Vec::new());
} else {
child_name_bindings.define_value(def, DUMMY_SP, is_exported);
}
crate) building type and value for {}",
final_ident);
child_name_bindings.define_type(def, DUMMY_SP, is_public);
- if csearch::get_struct_fields(&self.session.cstore, def_id).len() == 0 {
+ let fields = csearch::get_struct_fields(&self.session.cstore, def_id).iter().map(|f| {
+ f.name
+ }).collect::<Vec<_>>();
+
+ if fields.len() == 0 {
child_name_bindings.define_value(def, DUMMY_SP, is_public);
}
- self.structs.insert(def_id);
+
+ // Record the def ID and fields of this struct.
+ self.structs.insert(def_id, fields);
}
DefMethod(..) => {
debug!("(building reduced graph for external crate) \
}
}
- fn idents_to_str(&mut self, idents: &[Ident]) -> StrBuf {
+ fn idents_to_str(&self, idents: &[Ident]) -> StrBuf {
let mut first = true;
let mut result = StrBuf::new();
for ident in idents.iter() {
result
}
- fn path_idents_to_str(&mut self, path: &Path) -> StrBuf {
+ fn path_idents_to_str(&self, path: &Path) -> StrBuf {
let identifiers: Vec<ast::Ident> = path.segments
.iter()
.map(|seg| seg.identifier)
while index < module_path_len {
let name = module_path[index];
match self.resolve_name_in_module(search_module.clone(),
- name,
+ name.name,
TypeNS,
name_search_type,
false) {
// Resolve the name in the parent module.
match self.resolve_name_in_module(search_module.clone(),
- name,
+ name.name,
namespace,
PathSearch,
true) {
/// passed through a public re-export proxy.
fn resolve_name_in_module(&mut self,
module_: Rc<Module>,
- name: Ident,
+ name: Name,
namespace: Namespace,
name_search_type: NameSearchType,
allow_private_imports: bool)
-> ResolveResult<(Target, bool)> {
debug!("(resolving name in module) resolving `{}` in `{}`",
- token::get_ident(name),
+ token::get_name(name).get(),
self.module_to_str(&*module_));
// First, check the direct children of the module.
self.populate_module_if_necessary(&module_);
- match module_.children.borrow().find(&name.name) {
+ match module_.children.borrow().find(&name) {
Some(name_bindings)
if name_bindings.defined_in_namespace(namespace) => {
debug!("(resolving name in module) found node as child");
}
// Check the list of resolved imports.
- match module_.import_resolutions.borrow().find(&name.name) {
+ match module_.import_resolutions.borrow().find(&name) {
Some(import_resolution) if allow_private_imports ||
import_resolution.is_public => {
// Finally, search through external children.
if namespace == TypeNS {
- match module_.external_module_children.borrow().find_copy(&name.name) {
+ match module_.external_module_children.borrow().find_copy(&name) {
None => {}
Some(module) => {
let name_bindings =
// We're out of luck.
debug!("(resolving name in module) failed to resolve `{}`",
- token::get_ident(name));
+ token::get_name(name).get());
return Failed;
}
Some(t) => match t.node {
TyPath(ref path, None, path_id) => {
match this.resolve_path(id, path, TypeNS, true) {
- Some((DefTy(def_id), lp)) if this.structs.contains(&def_id) => {
+ Some((DefTy(def_id), lp)) if this.structs.contains_key(&def_id) => {
let def = DefStruct(def_id);
debug!("(resolving struct) resolved `{}` to type {:?}",
token::get_ident(path.segments
self.resolve_function(rib_kind, Some(method.decl), type_parameters, method.body);
}
+ fn with_current_self_type<T>(&mut self, self_type: &Ty, f: |&mut Resolver| -> T) -> T {
+ // Handle nested impls (inside fn bodies)
+ let previous_value = replace(&mut self.current_self_type, Some(self_type.clone()));
+ let result = f(self);
+ self.current_self_type = previous_value;
+ result
+ }
+
+ fn with_optional_trait_ref<T>(&mut self, id: NodeId,
+ opt_trait_ref: &Option<TraitRef>,
+ f: |&mut Resolver| -> T) -> T {
+ let new_val = match *opt_trait_ref {
+ Some(ref trait_ref) => {
+ self.resolve_trait_reference(id, trait_ref, TraitImplementation);
+
+ match self.def_map.borrow().find(&trait_ref.ref_id) {
+ Some(def) => {
+ let did = def_id_of_def(*def);
+ Some((did, trait_ref.clone()))
+ }
+ None => None
+ }
+ }
+ None => None
+ };
+ let original_trait_ref = replace(&mut self.current_trait_ref, new_val);
+ let result = f(self);
+ self.current_trait_ref = original_trait_ref;
+ result
+ }
+
fn resolve_implementation(&mut self,
id: NodeId,
generics: &Generics,
this.resolve_type_parameters(&generics.ty_params);
// Resolve the trait reference, if necessary.
- let original_trait_refs;
- match opt_trait_reference {
- &Some(ref trait_reference) => {
- this.resolve_trait_reference(id, trait_reference,
- TraitImplementation);
-
- // Record the current set of trait references.
- let mut new_trait_refs = Vec::new();
- for &def in this.def_map.borrow()
- .find(&trait_reference.ref_id).iter() {
- new_trait_refs.push(def_id_of_def(*def));
+ this.with_optional_trait_ref(id, opt_trait_reference, |this| {
+ // Resolve the self type.
+ this.resolve_type(self_type);
+
+ this.with_current_self_type(self_type, |this| {
+ for method in methods.iter() {
+ // We also need a new scope for the method-specific type parameters.
+ this.resolve_method(MethodRibKind(id, Provided(method.id)),
+ *method,
+ outer_type_parameter_count);
}
- original_trait_refs = Some(replace(
- &mut this.current_trait_refs,
- Some(new_trait_refs)));
- }
- &None => {
- original_trait_refs = None;
- }
- }
-
- // Resolve the self type.
- this.resolve_type(self_type);
-
- for method in methods.iter() {
- // We also need a new scope for the method-specific
- // type parameters.
- this.resolve_method(MethodRibKind(
- id,
- Provided(method.id)),
- *method,
- outer_type_parameter_count);
-/*
- let borrowed_type_parameters = &method.tps;
- self.resolve_function(MethodRibKind(
- id,
- Provided(method.id)),
- Some(method.decl),
- HasTypeParameters
- (borrowed_type_parameters,
- method.id,
- outer_type_parameter_count,
- NormalRibKind),
- method.body);
-*/
- }
-
- // Restore the original trait references.
- match original_trait_refs {
- Some(r) => { this.current_trait_refs = r; }
- None => ()
- }
+ });
+ });
});
}
PatStruct(ref path, _, _) => {
match self.resolve_path(pat_id, path, TypeNS, false) {
Some((DefTy(class_id), lp))
- if self.structs.contains(&class_id) => {
+ if self.structs.contains_key(&class_id) => {
let class_def = DefStruct(class_id);
self.record_def(pattern.id, (class_def, lp));
}
Some(definition @ (DefStruct(class_id), _)) => {
- assert!(self.structs.contains(&class_id));
+ assert!(self.structs.contains_key(&class_id));
self.record_def(pattern.id, definition);
}
Some(definition @ (DefVariant(_, variant_id, _), _))
- if self.structs.contains(&variant_id) => {
+ if self.structs.contains_key(&variant_id) => {
self.record_def(pattern.id, definition);
}
result => {
// FIXME #4952: Merge me with resolve_name_in_module?
fn resolve_definition_of_name_in_module(&mut self,
containing_module: Rc<Module>,
- name: Ident,
+ name: Name,
namespace: Namespace)
-> NameDefinition {
// First, search children.
self.populate_module_if_necessary(&containing_module);
- match containing_module.children.borrow().find(&name.name) {
+ match containing_module.children.borrow().find(&name) {
Some(child_name_bindings) => {
match child_name_bindings.def_for_namespace(namespace) {
Some(def) => {
}
// Next, search import resolutions.
- match containing_module.import_resolutions.borrow().find(&name.name) {
+ match containing_module.import_resolutions.borrow().find(&name) {
Some(import_resolution) if import_resolution.is_public => {
match (*import_resolution).target_for_namespace(namespace) {
Some(target) => {
// Finally, search through external children.
if namespace == TypeNS {
match containing_module.external_module_children.borrow()
- .find_copy(&name.name) {
+ .find_copy(&name) {
None => {}
Some(module) => {
match module.def_id.get() {
let ident = path.segments.last().unwrap().identifier;
let def = match self.resolve_definition_of_name_in_module(containing_module.clone(),
- ident,
+ ident.name,
namespace) {
NoNameDefinition => {
// We failed to resolve the name. Report an error.
}
}
- let name = path.segments.last().unwrap().identifier;
+ let name = path.segments.last().unwrap().identifier.name;
match self.resolve_definition_of_name_in_module(containing_module,
name,
namespace) {
}
}
+ fn find_fallback_in_self_type(&mut self, name: Name) -> FallbackSuggestion {
+ fn get_module(this: &mut Resolver, span: Span, ident_path: &[ast::Ident])
+ -> Option<Rc<Module>> {
+ let root = this.current_module.clone();
+ let last_name = ident_path.last().unwrap().name;
+
+ if ident_path.len() == 1 {
+ match this.primitive_type_table.primitive_types.find(&last_name) {
+ Some(_) => None,
+ None => {
+ match this.current_module.children.borrow().find(&last_name) {
+ Some(child) => child.get_module_if_available(),
+ None => None
+ }
+ }
+ }
+ } else {
+ match this.resolve_module_path(root,
+ ident_path.as_slice(),
+ UseLexicalScope,
+ span,
+ PathSearch) {
+ Success((module, _)) => Some(module),
+ _ => None
+ }
+ }
+ }
+
+ let (path, node_id) = match self.current_self_type {
+ Some(ref ty) => match ty.node {
+ TyPath(ref path, _, node_id) => (path.clone(), node_id),
+ _ => unreachable!(),
+ },
+ None => return NoSuggestion,
+ };
+
+ // Look for a field with the same name in the current self_type.
+ match self.def_map.borrow().find(&node_id) {
+ Some(&DefTy(did))
+ | Some(&DefStruct(did))
+ | Some(&DefVariant(_, did, _)) => match self.structs.find(&did) {
+ None => {}
+ Some(fields) => {
+ if fields.iter().any(|&field_name| name == field_name) {
+ return Field;
+ }
+ }
+ },
+ _ => {} // Self type didn't resolve properly
+ }
+
+ let ident_path = path.segments.iter().map(|seg| seg.identifier).collect::<Vec<_>>();
+
+ // Look for a method in the current self type's impl module.
+ match get_module(self, path.span, ident_path.as_slice()) {
+ Some(module) => match module.children.borrow().find(&name) {
+ Some(binding) => {
+ let p_str = self.path_idents_to_str(&path);
+ match binding.def_for_namespace(ValueNS) {
+ Some(DefStaticMethod(_, provenance, _)) => {
+ match provenance {
+ FromImpl(_) => return StaticMethod(p_str),
+ FromTrait(_) => unreachable!()
+ }
+ }
+ Some(DefMethod(_, None)) => return Method,
+ Some(DefMethod(_, _)) => return TraitMethod,
+ _ => ()
+ }
+ }
+ None => {}
+ },
+ None => {}
+ }
+
+ // Look for a method in the current trait.
+ let method_map = self.method_map.borrow();
+ match self.current_trait_ref {
+ Some((did, ref trait_ref)) => {
+ let path_str = self.path_idents_to_str(&trait_ref.path);
+
+ match method_map.find(&(name, did)) {
+ Some(&SelfStatic) => return StaticTraitMethod(path_str),
+ Some(_) => return TraitMethod,
+ None => {}
+ }
+ }
+ None => {}
+ }
+
+ NoSuggestion
+ }
+
fn find_best_match_for_name(&mut self, name: &str, max_distance: uint)
-> Option<StrBuf> {
let this = &mut *self;
match self.with_no_errors(|this|
this.resolve_path(expr.id, path, TypeNS, false)) {
Some((DefTy(struct_id), _))
- if self.structs.contains(&struct_id) => {
+ if self.structs.contains_key(&struct_id) => {
self.resolve_error(expr.span,
format!("`{}` is a structure name, but \
this expression \
wrong_name));
}
- _ =>
- // limit search to 5 to reduce the number
- // of stupid suggestions
- match self.find_best_match_for_name(
- wrong_name.as_slice(),
- 5) {
- Some(m) => {
- self.resolve_error(expr.span,
- format!("unresolved name `{}`. \
- Did you mean `{}`?",
- wrong_name,
- m));
- }
- None => {
- self.resolve_error(expr.span,
- format!("unresolved name `{}`.",
- wrong_name.as_slice()));
- }
- }
+ _ => {
+ let mut method_scope = false;
+ self.value_ribs.borrow().iter().rev().advance(|rib| {
+ let res = match *rib {
+ Rib { bindings: _, kind: MethodRibKind(_, _) } => true,
+ Rib { bindings: _, kind: OpaqueFunctionRibKind } => false,
+ _ => return true, // Keep advancing
+ };
+
+ method_scope = res;
+ false // Stop advancing
+ });
+
+ if method_scope && token::get_name(self.self_ident.name).get()
+ == wrong_name.as_slice() {
+ self.resolve_error(expr.span,
+ format!("`self` is not available in a \
+ static method. Maybe a `self` \
+ argument is missing?"));
+ } else {
+ let name = path_to_ident(path).name;
+ let mut msg = match self.find_fallback_in_self_type(name) {
+ NoSuggestion => {
+ // limit search to 5 to reduce the number
+ // of stupid suggestions
+ self.find_best_match_for_name(wrong_name.as_slice(), 5)
+ .map_or("".into_owned(),
+ |x| format!("`{}`", x))
+ }
+ Field =>
+ format!("`self.{}`", wrong_name),
+ Method
+ | TraitMethod =>
+ format!("to call `self.{}`", wrong_name),
+ StaticTraitMethod(path_str)
+ | StaticMethod(path_str) =>
+ format!("to call `{}::{}`", path_str, wrong_name)
+ };
+
+ if msg.len() > 0 {
+ msg = format!(" Did you mean {}?", msg)
+ }
+
+ self.resolve_error(expr.span, format!("unresolved name `{}`.{}",
+ wrong_name, msg));
+ }
+ }
}
}
}
// Resolve the path to the structure it goes to.
match self.resolve_path(expr.id, path, TypeNS, false) {
Some((DefTy(class_id), lp)) | Some((DefStruct(class_id), lp))
- if self.structs.contains(&class_id) => {
+ if self.structs.contains_key(&class_id) => {
let class_def = DefStruct(class_id);
self.record_def(expr.id, (class_def, lp));
}
Some(definition @ (DefVariant(_, class_id, _), _))
- if self.structs.contains(&class_id) => {
+ if self.structs.contains_key(&class_id) => {
self.record_def(expr.id, definition);
}
result => {
let mut search_module = self.current_module.clone();
loop {
// Look for the current trait.
- match self.current_trait_refs {
- Some(ref trait_def_ids) => {
+ match self.current_trait_ref {
+ Some((trait_def_id, _)) => {
let method_map = self.method_map.borrow();
- for &trait_def_id in trait_def_ids.iter() {
- if method_map.contains_key(&(name, trait_def_id)) {
- add_trait_info(&mut found_traits, trait_def_id, name);
- }
+
+ if method_map.contains_key(&(name, trait_def_id)) {
+ add_trait_info(&mut found_traits, trait_def_id, name);
}
}
- None => {
- // Nothing to do.
- }
+ None => {} // Nothing to do.
}
// Look for trait children.