X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=src%2Flibrustc_resolve%2Flib.rs;h=11c51522b6763e4ab9bc720353cf3e98f72e9cca;hb=2d14b39204e648a219a17335e712c3fb14666a07;hp=5fbe06a868f07f0d420fc5fb088f4e5b01a46673;hpb=b9732ed1471689976fc32fa6757fd29c5a587f5d;p=rust.git diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 5fbe06a868f..11c51522b67 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -18,7 +18,6 @@ #![cfg_attr(not(stage0), deny(warnings))] #![feature(associated_consts)] -#![feature(borrow_state)] #![feature(rustc_diagnostic_macros)] #![feature(rustc_private)] #![feature(staged_api)] @@ -60,9 +59,8 @@ use rustc::middle::ty::{Freevar, FreevarMap, TraitMap, GlobMap}; use rustc::util::nodemap::{NodeMap, DefIdSet, FnvHashMap}; -use syntax::ast; -use syntax::ast::{CRATE_NODE_ID, Name, NodeId, CrateNum, TyIs, TyI8, TyI16, TyI32, TyI64}; -use syntax::ast::{TyUs, TyU8, TyU16, TyU32, TyU64, TyF64, TyF32}; +use syntax::ast::{self, FloatTy}; +use syntax::ast::{CRATE_NODE_ID, Name, NodeId, CrateNum, IntTy, UintTy}; use syntax::attr::AttrMetaMethods; use syntax::codemap::{self, Span, Pos}; use syntax::errors::DiagnosticBuilder; @@ -81,8 +79,9 @@ use rustc_front::hir::{ItemFn, ItemForeignMod, ItemImpl, ItemMod, ItemStatic, ItemDefaultImpl}; use rustc_front::hir::{ItemStruct, ItemTrait, ItemTy, ItemUse}; use rustc_front::hir::Local; -use rustc_front::hir::{Pat, PatEnum, PatIdent, PatLit, PatQPath}; -use rustc_front::hir::{PatRange, PatStruct, Path, PrimTy}; +use rustc_front::hir::{Pat, PatKind, Path, PrimTy}; +use rustc_front::hir::{PathSegment, PathParameters}; +use rustc_front::hir::HirVec; use rustc_front::hir::{TraitRef, Ty, TyBool, TyChar, TyFloat, TyInt}; use rustc_front::hir::{TyRptr, TyStr, TyUint, TyPath, TyPtr}; use rustc_front::util::walk_pat; @@ -119,6 +118,12 @@ enum SuggestionType { NotFound, } +/// Candidates for a name resolution failure +pub struct SuggestedCandidates { + name: String, + candidates: Vec, +} + pub enum ResolutionError<'a> { /// error E0401: can't use type parameters from outer function TypeParametersFromOuterFunction, @@ -129,7 +134,7 @@ pub enum ResolutionError<'a> { /// error E0404: is not a trait IsNotATrait(&'a str), /// error E0405: use of undeclared trait name - UndeclaredTraitName(&'a str), + UndeclaredTraitName(&'a str, SuggestedCandidates), /// error E0406: undeclared associated type UndeclaredAssociatedType, /// error E0407: method is not a member of trait @@ -147,7 +152,7 @@ pub enum ResolutionError<'a> { /// error E0411: use of `Self` outside of an impl or trait SelfUsedOutsideImplOrTrait, /// error E0412: use of undeclared - UseOfUndeclared(&'a str, &'a str), + UseOfUndeclared(&'a str, &'a str, SuggestedCandidates), /// error E0413: declaration shadows an enum variant or unit-like struct in scope DeclarationShadowsEnumVariantOrUnitLikeStruct(Name), /// error E0414: only irrefutable patterns allowed here @@ -250,12 +255,14 @@ fn resolve_struct_error<'b, 'a: 'b, 'tcx: 'a>(resolver: &'b Resolver<'a, 'tcx>, ResolutionError::IsNotATrait(name) => { struct_span_err!(resolver.session, span, E0404, "`{}` is not a trait", name) } - ResolutionError::UndeclaredTraitName(name) => { - struct_span_err!(resolver.session, - span, - E0405, - "use of undeclared trait name `{}`", - name) + ResolutionError::UndeclaredTraitName(name, candidates) => { + let mut err = struct_span_err!(resolver.session, + span, + E0405, + "trait `{}` is not in scope", + name); + show_candidates(&mut err, span, &candidates); + err } ResolutionError::UndeclaredAssociatedType => { struct_span_err!(resolver.session, span, E0406, "undeclared associated type") @@ -315,13 +322,15 @@ fn resolve_struct_error<'b, 'a: 'b, 'tcx: 'a>(resolver: &'b Resolver<'a, 'tcx>, E0411, "use of `Self` outside of an impl or trait") } - ResolutionError::UseOfUndeclared(kind, name) => { - struct_span_err!(resolver.session, - span, - E0412, - "use of undeclared {} `{}`", - kind, - name) + ResolutionError::UseOfUndeclared(kind, name, candidates) => { + let mut err = struct_span_err!(resolver.session, + span, + E0412, + "{} `{}` is undefined or not in scope", + kind, + name); + show_candidates(&mut err, span, &candidates); + err } ResolutionError::DeclarationShadowsEnumVariantOrUnitLikeStruct(name) => { struct_span_err!(resolver.session, @@ -439,25 +448,25 @@ fn resolve_struct_error<'b, 'a: 'b, 'tcx: 'a>(resolver: &'b Resolver<'a, 'tcx>, help_msg = format!("To reference an item from the \ `{module}` module, use \ `{module}::{ident}`", - module = &*path, + module = path, ident = ident.node); } ExprMethodCall(ident, _, _) => { help_msg = format!("To call a function from the \ `{module}` module, use \ `{module}::{ident}(..)`", - module = &*path, + module = path, ident = ident.node); } ExprCall(_, _) => { help_msg = format!("No function corresponds to `{module}(..)`", - module = &*path); + module = path); } _ => { } // no help available } } else { help_msg = format!("Module `{module}` cannot be the value of an expression", - module = &*path); + module = path); } if !help_msg.is_empty() { @@ -578,7 +587,7 @@ fn visit_expr(&mut self, expr: &Expr) { self.resolve_expr(expr); } fn visit_local(&mut self, local: &Local) { - execute_callback!(hir_map::Node::NodeLocal(&*local.pat), self); + execute_callback!(hir_map::Node::NodeLocal(&local.pat), self); self.resolve_local(local); } fn visit_ty(&mut self, ty: &Ty) { @@ -799,12 +808,12 @@ pub struct ModuleS<'a> { is_public: bool, is_extern_crate: bool, - children: RefCell>>, - imports: RefCell>, + resolutions: RefCell>>, + unresolved_imports: RefCell>, - // The anonymous children of this node. Anonymous children are pseudo- - // modules that are implicitly created around items contained within - // blocks. + // The module children of this node, including normal modules and anonymous modules. + // Anonymous children are pseudo-modules that are implicitly created around items + // contained within blocks. // // For example, if we have this: // @@ -816,7 +825,7 @@ pub struct ModuleS<'a> { // // There will be an anonymous module created around `g` with the ID of the // entry block for `f`. - anonymous_children: RefCell>>, + module_children: RefCell>>, shadowed_traits: RefCell>>, @@ -829,9 +838,6 @@ pub struct ModuleS<'a> { // The number of unresolved pub glob imports in this module pub_glob_count: Cell, - // The index of the import we're resolving. - resolved_import_count: Cell, - // Whether this module is populated. If not populated, any attempt to // access the children must be preceded with a // `populate_module_if_necessary` call. @@ -841,20 +847,20 @@ pub struct ModuleS<'a> { pub type Module<'a> = &'a ModuleS<'a>; impl<'a> ModuleS<'a> { + fn new(parent_link: ParentLink<'a>, def: Option, external: bool, is_public: bool) -> Self { ModuleS { parent_link: parent_link, def: def, is_public: is_public, is_extern_crate: false, - children: RefCell::new(HashMap::new()), - imports: RefCell::new(Vec::new()), - anonymous_children: RefCell::new(NodeMap()), + resolutions: RefCell::new(HashMap::new()), + unresolved_imports: RefCell::new(Vec::new()), + module_children: RefCell::new(NodeMap()), shadowed_traits: RefCell::new(Vec::new()), glob_count: Cell::new(0), pub_count: Cell::new(0), pub_glob_count: Cell::new(0), - resolved_import_count: Cell::new(0), populated: Cell::new(!external), } } @@ -864,7 +870,7 @@ fn resolve_name(&self, name: Name, ns: Namespace, allow_private_imports: bool) let glob_count = if allow_private_imports { self.glob_count.get() } else { self.pub_glob_count.get() }; - self.children.borrow().get(&(name, ns)).cloned().unwrap_or_default().result(glob_count) + self.resolutions.borrow().get(&(name, ns)).cloned().unwrap_or_default().result(glob_count) .and_then(|binding| { let allowed = allow_private_imports || !binding.is_import() || binding.is_public(); if allowed { Success(binding) } else { Failed(None) } @@ -874,7 +880,7 @@ fn resolve_name(&self, name: Name, ns: Namespace, allow_private_imports: bool) // Define the name or return the existing binding if there is a collision. fn try_define_child(&self, name: Name, ns: Namespace, binding: &'a NameBinding<'a>) -> Result<(), &'a NameBinding<'a>> { - let mut children = self.children.borrow_mut(); + let mut children = self.resolutions.borrow_mut(); let resolution = children.entry((name, ns)).or_insert_with(Default::default); // FIXME #31379: We can use methods from imported traits shadowed by non-import items @@ -890,31 +896,23 @@ fn try_define_child(&self, name: Name, ns: Namespace, binding: &'a NameBinding<' } fn increment_outstanding_references_for(&self, name: Name, ns: Namespace) { - let mut children = self.children.borrow_mut(); + let mut children = self.resolutions.borrow_mut(); children.entry((name, ns)).or_insert_with(Default::default).outstanding_references += 1; } fn decrement_outstanding_references_for(&self, name: Name, ns: Namespace) { - match self.children.borrow_mut().get_mut(&(name, ns)).unwrap().outstanding_references { + match self.resolutions.borrow_mut().get_mut(&(name, ns)).unwrap().outstanding_references { 0 => panic!("No more outstanding references!"), ref mut outstanding_references => { *outstanding_references -= 1; } } } fn for_each_child)>(&self, mut f: F) { - for (&(name, ns), name_resolution) in self.children.borrow().iter() { + for (&(name, ns), name_resolution) in self.resolutions.borrow().iter() { name_resolution.binding.map(|binding| f(name, ns, binding)); } } - fn for_each_local_child)>(&self, mut f: F) { - self.for_each_child(|name, ns, name_binding| { - if !name_binding.is_import() && !name_binding.is_extern_crate() { - f(name, ns, name_binding) - } - }) - } - fn def_id(&self) -> Option { self.def.as_ref().map(Def::def_id) } @@ -933,15 +931,6 @@ fn is_trait(&self) -> bool { } } - fn all_imports_resolved(&self) -> bool { - if self.imports.borrow_state() == ::std::cell::BorrowState::Writing { - // it is currently being resolved ! so nope - false - } else { - self.imports.borrow().len() == self.resolved_import_count.get() - } - } - pub fn inc_glob_count(&self) { self.glob_count.set(self.glob_count.get() + 1); } @@ -1048,6 +1037,7 @@ fn is_public(&self) -> bool { fn def_and_lp(&self) -> (Def, LastPrivate) { let def = self.def().unwrap(); + if let Def::Err = def { return (def, LastMod(AllPublic)) } (def, LastMod(if self.is_public() { AllPublic } else { DependsOn(def.def_id()) })) } @@ -1074,19 +1064,19 @@ fn new() -> PrimitiveTypeTable { table.intern("bool", TyBool); table.intern("char", TyChar); - table.intern("f32", TyFloat(TyF32)); - table.intern("f64", TyFloat(TyF64)); - table.intern("isize", TyInt(TyIs)); - table.intern("i8", TyInt(TyI8)); - table.intern("i16", TyInt(TyI16)); - table.intern("i32", TyInt(TyI32)); - table.intern("i64", TyInt(TyI64)); + table.intern("f32", TyFloat(FloatTy::F32)); + table.intern("f64", TyFloat(FloatTy::F64)); + table.intern("isize", TyInt(IntTy::Is)); + table.intern("i8", TyInt(IntTy::I8)); + table.intern("i16", TyInt(IntTy::I16)); + table.intern("i32", TyInt(IntTy::I32)); + table.intern("i64", TyInt(IntTy::I64)); table.intern("str", TyStr); - table.intern("usize", TyUint(TyUs)); - table.intern("u8", TyUint(TyU8)); - table.intern("u16", TyUint(TyU16)); - table.intern("u32", TyUint(TyU32)); - table.intern("u64", TyUint(TyU64)); + table.intern("usize", TyUint(UintTy::Us)); + table.intern("u8", TyUint(UintTy::U8)); + table.intern("u16", TyUint(UintTy::U16)); + table.intern("u32", TyUint(UintTy::U32)); + table.intern("u64", TyUint(UintTy::U64)); table } @@ -1299,7 +1289,7 @@ fn resolve_module_path_from_root(&mut self, span: Span, lp: LastPrivate) -> ResolveResult<(Module<'a>, LastPrivate)> { - fn search_parent_externals<'a>(needle: Name, module: Module<'a>) -> Option> { + fn search_parent_externals(needle: Name, module: Module) -> Option { match module.resolve_name(needle, TypeNS, false) { Success(binding) if binding.is_extern_crate() => Some(module), _ => match module.parent_link { @@ -1332,8 +1322,8 @@ fn search_parent_externals<'a>(needle: Name, module: Module<'a>) -> Option { let path_str = names_to_string(module_path); - let target_mod_str = module_to_string(&*module); - let current_mod_str = module_to_string(&*self.current_module); + let target_mod_str = module_to_string(&module); + let current_mod_str = module_to_string(&self.current_module); let prefix = if target_mod_str == current_mod_str { "self::".to_string() @@ -1401,7 +1391,7 @@ fn resolve_module_path(&mut self, debug!("(resolving module path for import) processing `{}` rooted at `{}`", names_to_string(module_path), - module_to_string(&*module_)); + module_to_string(&module_)); // Resolve the module prefix, if any. let module_prefix_result = self.resolve_module_prefix(module_, module_path); @@ -1495,7 +1485,7 @@ fn resolve_item_in_lexical_scope(&mut self, debug!("(resolving item in lexical scope) resolving `{}` in namespace {:?} in `{}`", name, namespace, - module_to_string(&*module_)); + module_to_string(&module_)); // Proceed up the scope chain looking for parent modules. let mut search_module = module_; @@ -1503,7 +1493,7 @@ fn resolve_item_in_lexical_scope(&mut self, // Resolve the name in the parent module. match self.resolve_name_in_module(search_module, name, namespace, true, record_used) { Failed(Some((span, msg))) => { - resolve_error(self, span, ResolutionError::FailedToResolve(&*msg)); + resolve_error(self, span, ResolutionError::FailedToResolve(&msg)); } Failed(None) => (), // Continue up the search chain. Indeterminate => { @@ -1593,7 +1583,7 @@ fn resolve_module_prefix(&mut self, // Now loop through all the `super`s we find. while i < module_path.len() && "super" == module_path[i].as_str() { debug!("(resolving module prefix) resolving `super` at {}", - module_to_string(&*containing_module)); + module_to_string(&containing_module)); match self.get_nearest_normal_module_parent(containing_module) { None => return Failed(None), Some(new_module) => { @@ -1604,7 +1594,7 @@ fn resolve_module_prefix(&mut self, } debug!("(resolving module prefix) finished resolving prefix at {}", - module_to_string(&*containing_module)); + module_to_string(&containing_module)); return Success(PrefixFound(containing_module, i)); } @@ -1631,30 +1621,13 @@ fn resolve_name_in_module(&mut self, } fn report_unresolved_imports(&mut self, module_: Module<'a>) { - let index = module_.resolved_import_count.get(); - let imports = module_.imports.borrow(); - let import_count = imports.len(); - if index != import_count { - resolve_error(self, - (*imports)[index].span, - ResolutionError::UnresolvedImport(None)); + for import in module_.unresolved_imports.borrow().iter() { + resolve_error(self, import.span, ResolutionError::UnresolvedImport(None)); + break; } // Descend into children and anonymous children. - build_reduced_graph::populate_module_if_necessary(self, module_); - - module_.for_each_local_child(|_, _, child_node| { - match child_node.module() { - None => { - // Continue. - } - Some(child_module) => { - self.report_unresolved_imports(child_module); - } - } - }); - - for (_, module_) in module_.anonymous_children.borrow().iter() { + for (_, module_) in module_.module_children.borrow().iter() { self.report_unresolved_imports(module_); } } @@ -1677,32 +1650,14 @@ fn report_unresolved_imports(&mut self, module_: Module<'a>) { // generate a fake "implementation scope" containing all the // implementations thus found, for compatibility with old resolve pass. - fn with_scope(&mut self, name: Option, f: F) + fn with_scope(&mut self, id: NodeId, f: F) where F: FnOnce(&mut Resolver) { let orig_module = self.current_module; // Move down in the graph. - match name { - None => { - // Nothing to do. - } - Some(name) => { - build_reduced_graph::populate_module_if_necessary(self, &orig_module); - - if let Success(name_binding) = orig_module.resolve_name(name, TypeNS, false) { - match name_binding.module() { - None => { - debug!("!!! (with scope) didn't find module for `{}` in `{}`", - name, - module_to_string(orig_module)); - } - Some(module) => { - self.current_module = module; - } - } - } - } + if let Some(module) = orig_module.module_children.borrow().get(&id) { + self.current_module = module; } f(self); @@ -1771,7 +1726,7 @@ fn resolve_item(&mut self, item: &Item) { ItemImpl(_, _, ref generics, ref opt_trait_ref, ref self_type, ref impl_items) => { self.resolve_implementation(generics, opt_trait_ref, - &**self_type, + &self_type, item.id, impl_items); } @@ -1826,7 +1781,7 @@ fn resolve_item(&mut self, item: &Item) { } ItemMod(_) | ItemForeignMod(_) => { - self.with_scope(Some(name), |this| { + self.with_scope(item.id, |this| { intravisit::walk_item(this, item); }); } @@ -1966,9 +1921,9 @@ fn resolve_function(&mut self, rib_kind: RibKind<'a>, declaration: &FnDecl, bloc // Add each argument to the rib. let mut bindings_list = HashMap::new(); for argument in &declaration.inputs { - self.resolve_pattern(&*argument.pat, ArgumentIrrefutableMode, &mut bindings_list); + self.resolve_pattern(&argument.pat, ArgumentIrrefutableMode, &mut bindings_list); - self.visit_ty(&*argument.ty); + self.visit_ty(&argument.ty); debug!("(resolving function) recorded argument"); } @@ -1998,7 +1953,7 @@ fn resolve_trait_reference(&mut self, let mut err = resolve_struct_error(self, trait_path.span, - ResolutionError::IsNotATrait(&*path_names_to_string(trait_path, + ResolutionError::IsNotATrait(&path_names_to_string(trait_path, path_depth))); // If it's a typedef, give a note @@ -2010,10 +1965,28 @@ fn resolve_trait_reference(&mut self, Err(()) } } else { - resolve_error(self, - trait_path.span, - ResolutionError::UndeclaredTraitName(&*path_names_to_string(trait_path, - path_depth))); + + // find possible candidates + let trait_name = trait_path.segments.last().unwrap().identifier.name; + let candidates = + self.lookup_candidates( + trait_name, + TypeNS, + |def| match def { + Def::Trait(_) => true, + _ => false, + }, + ); + + // create error object + let name = &path_names_to_string(trait_path, path_depth); + let error = + ResolutionError::UndeclaredTraitName( + name, + candidates, + ); + + resolve_error(self, trait_path.span, error); Err(()) } } @@ -2166,7 +2139,7 @@ fn check_trait_item(&self, name: Name, span: Span, err: F) if let Some((did, ref trait_ref)) = self.current_trait_ref { if !self.trait_item_map.contains_key(&(name, did)) { let path_str = path_names_to_string(&trait_ref.path, 0); - resolve_error(self, span, err(name, &*path_str)); + resolve_error(self, span, err(name, &path_str)); } } } @@ -2179,7 +2152,7 @@ fn resolve_local(&mut self, local: &Local) { walk_list!(self, visit_expr, &local.init); // Resolve the pattern. - self.resolve_pattern(&*local.pat, LocalIrrefutableMode, &mut HashMap::new()); + self.resolve_pattern(&local.pat, LocalIrrefutableMode, &mut HashMap::new()); } // build a map from pattern identifiers to binding-info's. @@ -2205,9 +2178,9 @@ fn check_consistent_bindings(&mut self, arm: &Arm) { if arm.pats.is_empty() { return; } - let map_0 = self.binding_mode_map(&*arm.pats[0]); + let map_0 = self.binding_mode_map(&arm.pats[0]); for (i, p) in arm.pats.iter().enumerate() { - let map_i = self.binding_mode_map(&**p); + let map_i = self.binding_mode_map(&p); for (&key, &binding_0) in &map_0 { match map_i.get(&key) { @@ -2242,7 +2215,7 @@ fn resolve_arm(&mut self, arm: &Arm) { let mut bindings_list = HashMap::new(); for pattern in &arm.pats { - self.resolve_pattern(&**pattern, RefutableMode, &mut bindings_list); + self.resolve_pattern(&pattern, RefutableMode, &mut bindings_list); } // This has to happen *after* we determine which @@ -2250,7 +2223,7 @@ fn resolve_arm(&mut self, arm: &Arm) { self.check_consistent_bindings(arm); walk_list!(self, visit_expr, &arm.guard); - self.visit_expr(&*arm.body); + self.visit_expr(&arm.body); if !self.resolved { self.value_ribs.pop(); @@ -2262,7 +2235,7 @@ fn resolve_block(&mut self, block: &Block) { // Move down in the graph, if there's an anonymous module rooted here. let orig_module = self.current_module; let anonymous_module = - orig_module.anonymous_children.borrow().get(&block.id).map(|module| *module); + orig_module.module_children.borrow().get(&block.id).map(|module| *module); if let Some(anonymous_module) = anonymous_module { debug!("(resolving block) found anonymous module, moving down"); @@ -2337,13 +2310,33 @@ fn resolve_type(&mut self, ty: &Ty) { ty.span, ResolutionError::SelfUsedOutsideImplOrTrait); } else { - resolve_error(self, - ty.span, - ResolutionError::UseOfUndeclared( - kind, - &*path_names_to_string(path, - 0)) - ); + let segment = path.segments.last(); + let segment = segment.expect("missing name in path"); + let type_name = segment.identifier.name; + + let candidates = + self.lookup_candidates( + type_name, + TypeNS, + |def| match def { + Def::Trait(_) | + Def::Enum(_) | + Def::Struct(_) | + Def::TyAlias(_) => true, + _ => false, + }, + ); + + // create error object + let name = &path_names_to_string(path, 0); + let error = + ResolutionError::UseOfUndeclared( + kind, + name, + candidates, + ); + + resolve_error(self, ty.span, error); } } } @@ -2363,8 +2356,8 @@ fn resolve_pattern(&mut self, let pat_id = pattern.id; walk_pat(pattern, |pattern| { match pattern.node { - PatIdent(binding_mode, ref path1, ref at_rhs) => { - // The meaning of PatIdent with no type parameters + PatKind::Ident(binding_mode, ref path1, ref at_rhs) => { + // The meaning of PatKind::Ident with no type parameters // depends on whether an enum variant or unit-like struct // with that name is in scope. The probing lookup has to // be careful not to emit spurious errors. Only matching @@ -2475,7 +2468,7 @@ fn resolve_pattern(&mut self, } } - PatEnum(ref path, _) => { + PatKind::TupleStruct(ref path, _) | PatKind::Path(ref path) => { // This must be an enum variant, struct or const. let resolution = match self.resolve_possibly_assoc_item(pat_id, None, @@ -2483,16 +2476,13 @@ fn resolve_pattern(&mut self, ValueNS, false) { // The below shouldn't happen because all - // qualified paths should be in PatQPath. + // qualified paths should be in PatKind::QPath. TypecheckRequired => self.session.span_bug(path.span, - "resolve_possibly_assoc_item claimed - \ - that a path in PatEnum requires typecheck - \ - to resolve, but qualified paths should be - \ - PatQPath"), + "resolve_possibly_assoc_item claimed that a path \ + in PatKind::Path or PatKind::TupleStruct \ + requires typecheck to resolve, but qualified \ + paths should be PatKind::QPath"), ResolveAttempt(resolution) => resolution, }; if let Some(path_res) = resolution { @@ -2551,7 +2541,7 @@ fn resolve_pattern(&mut self, intravisit::walk_path(self, path); } - PatQPath(ref qself, ref path) => { + PatKind::QPath(ref qself, ref path) => { // Associated constants only. let resolution = match self.resolve_possibly_assoc_item(pat_id, Some(qself), @@ -2606,7 +2596,7 @@ fn resolve_pattern(&mut self, intravisit::walk_pat(self, pattern); } - PatStruct(ref path, _, _) => { + PatKind::Struct(ref path, _, _) => { match self.resolve_path(pat_id, path, 0, TypeNS, false) { Some(definition) => { self.record_def(pattern.id, definition); @@ -2617,7 +2607,7 @@ fn resolve_pattern(&mut self, self, path.span, ResolutionError::DoesNotNameAStruct( - &*path_names_to_string(path, 0)) + &path_names_to_string(path, 0)) ); self.record_def(pattern.id, err_path_resolution()); } @@ -2625,7 +2615,7 @@ fn resolve_pattern(&mut self, intravisit::walk_path(self, path); } - PatLit(_) | PatRange(..) => { + PatKind::Lit(_) | PatKind::Range(..) => { intravisit::walk_pat(self, pattern); } @@ -2673,7 +2663,7 @@ fn resolve_bare_identifier_pattern(&mut self, Failed(err) => { match err { Some((span, msg)) => { - resolve_error(self, span, ResolutionError::FailedToResolve(&*msg)); + resolve_error(self, span, ResolutionError::FailedToResolve(&msg)); } None => (), } @@ -2805,7 +2795,7 @@ fn resolve_identifier(&mut self, match self.resolve_item_in_lexical_scope(module, name, namespace, record_used) { Success(binding) => binding.def().map(LocalDef::from_def), Failed(Some((span, msg))) => { - resolve_error(self, span, ResolutionError::FailedToResolve(&*msg)); + resolve_error(self, span, ResolutionError::FailedToResolve(&msg)); None } _ => None, @@ -2928,7 +2918,7 @@ fn resolve_module_relative_path(&mut self, } }; - resolve_error(self, span, ResolutionError::FailedToResolve(&*msg)); + resolve_error(self, span, ResolutionError::FailedToResolve(&msg)); return None; } Indeterminate => return None, @@ -2983,7 +2973,7 @@ fn resolve_crate_relative_path(&mut self, } }; - resolve_error(self, span, ResolutionError::FailedToResolve(&*msg)); + resolve_error(self, span, ResolutionError::FailedToResolve(&msg)); return None; } @@ -3065,8 +3055,8 @@ fn extract_path_and_node_id(t: &Ty, -> Option<(Path, NodeId, FallbackChecks)> { match t.node { TyPath(None, ref path) => Some((path.clone(), t.id, allow)), - TyPtr(ref mut_ty) => extract_path_and_node_id(&*mut_ty.ty, OnlyTraitAndStatics), - TyRptr(_, ref mut_ty) => extract_path_and_node_id(&*mut_ty.ty, allow), + TyPtr(ref mut_ty) => extract_path_and_node_id(&mut_ty.ty, OnlyTraitAndStatics), + TyRptr(_, ref mut_ty) => extract_path_and_node_id(&mut_ty.ty, allow), // This doesn't handle the remaining `Ty` variants as they are not // that commonly the self_type, it might be interesting to provide // support for those in future. @@ -3184,7 +3174,7 @@ fn find_best_match(&mut self, name: &str) -> SuggestionType { .flat_map(|rib| rib.bindings.keys()); if let Some(found) = find_best_match_for_name(names, name, None) { - if name != &*found { + if name != found { return SuggestionType::Function(found); } } SuggestionType::NotFound @@ -3230,7 +3220,7 @@ fn resolve_expr(&mut self, expr: &Expr) { let mut err = resolve_struct_error(self, expr.span, - ResolutionError::StructVariantUsedAsFunction(&*path_name)); + ResolutionError::StructVariantUsedAsFunction(&path_name)); let msg = format!("did you mean to write: `{} {{ /* fields */ }}`?", path_name); @@ -3271,7 +3261,7 @@ fn resolve_expr(&mut self, expr: &Expr) { Some(Def::Struct(..)) => { let mut err = resolve_struct_error(self, expr.span, - ResolutionError::StructVariantUsedAsFunction(&*path_name)); + ResolutionError::StructVariantUsedAsFunction(&path_name)); let msg = format!("did you mean to write: `{} {{ /* fields */ }}`?", path_name); @@ -3347,7 +3337,7 @@ fn resolve_expr(&mut self, expr: &Expr) { resolve_error(self, expr.span, ResolutionError::UnresolvedName( - &*path_name, &*msg, context)); + &path_name, &msg, context)); } } } @@ -3368,7 +3358,7 @@ fn resolve_expr(&mut self, expr: &Expr) { resolve_error(self, path.span, ResolutionError::DoesNotNameAStruct( - &*path_names_to_string(path, 0)) + &path_names_to_string(path, 0)) ); self.record_def(expr.id, err_path_resolution()); } @@ -3501,6 +3491,99 @@ fn add_trait_info(found_traits: &mut Vec, trait_def_id: DefId, name: Name found_traits } + /// When name resolution fails, this method can be used to look up candidate + /// entities with the expected name. It allows filtering them using the + /// supplied predicate (which should be used to only accept the types of + /// definitions expected e.g. traits). The lookup spans across all crates. + /// + /// NOTE: The method does not look into imports, but this is not a problem, + /// since we report the definitions (thus, the de-aliased imports). + fn lookup_candidates(&mut self, + lookup_name: Name, + namespace: Namespace, + filter_fn: FilterFn) -> SuggestedCandidates + where FilterFn: Fn(Def) -> bool { + + let mut lookup_results = Vec::new(); + let mut worklist = Vec::new(); + worklist.push((self.graph_root, Vec::new(), false)); + + while let Some((in_module, + path_segments, + in_module_is_extern)) = worklist.pop() { + build_reduced_graph::populate_module_if_necessary(self, &in_module); + + in_module.for_each_child(|name, ns, name_binding| { + + // avoid imports entirely + if name_binding.is_import() { return; } + + // collect results based on the filter function + if let Some(def) = name_binding.def() { + if name == lookup_name && ns == namespace && filter_fn(def) { + // create the path + let ident = hir::Ident::from_name(name); + let params = PathParameters::none(); + let segment = PathSegment { + identifier: ident, + parameters: params, + }; + let span = name_binding.span.unwrap_or(syntax::codemap::DUMMY_SP); + let mut segms = path_segments.clone(); + segms.push(segment); + let segms = HirVec::from_vec(segms); + let path = Path { + span: span, + global: true, + segments: segms, + }; + // the entity is accessible in the following cases: + // 1. if it's defined in the same crate, it's always + // accessible (since private entities can be made public) + // 2. if it's defined in another crate, it's accessible + // only if both the module is public and the entity is + // declared as public (due to pruning, we don't explore + // outside crate private modules => no need to check this) + if !in_module_is_extern || name_binding.is_public() { + lookup_results.push(path); + } + } + } + + // collect submodules to explore + if let Some(module) = name_binding.module() { + // form the path + let path_segments = match module.parent_link { + NoParentLink => path_segments.clone(), + ModuleParentLink(_, name) => { + let mut paths = path_segments.clone(); + let ident = hir::Ident::from_name(name); + let params = PathParameters::none(); + let segm = PathSegment { + identifier: ident, + parameters: params, + }; + paths.push(segm); + paths + } + _ => unreachable!(), + }; + + if !in_module_is_extern || name_binding.is_public() { + // add the module to the lookup + let is_extern = in_module_is_extern || module.is_extern_crate; + worklist.push((module, path_segments, is_extern)); + } + } + }) + } + + SuggestedCandidates { + name: lookup_name.as_str().to_string(), + candidates: lookup_results, + } + } + fn record_def(&mut self, node_id: NodeId, resolution: PathResolution) { debug!("(recording def) recording {:?} for {}", resolution, node_id); assert!(match resolution.last_private { @@ -3556,11 +3639,72 @@ fn path_names_to_string(path: &Path, depth: usize) -> String { names_to_string(&names[..]) } +/// When an entity with a given name is not available in scope, we search for +/// entities with that name in all crates. This method allows outputting the +/// results of this search in a programmer-friendly way +fn show_candidates(session: &mut DiagnosticBuilder, + span: syntax::codemap::Span, + candidates: &SuggestedCandidates) { + + let paths = &candidates.candidates; + + if paths.len() > 0 { + // don't show more than MAX_CANDIDATES results, so + // we're consistent with the trait suggestions + const MAX_CANDIDATES: usize = 5; + + // we want consistent results across executions, but candidates are produced + // by iterating through a hash map, so make sure they are ordered: + let mut path_strings: Vec<_> = paths.into_iter() + .map(|p| path_names_to_string(&p, 0)) + .collect(); + path_strings.sort(); + + // behave differently based on how many candidates we have: + if !paths.is_empty() { + if paths.len() == 1 { + session.fileline_help( + span, + &format!("you can to import it into scope: `use {};`.", + &path_strings[0]), + ); + } else { + session.fileline_help(span, "you can import several candidates \ + into scope (`use ...;`):"); + let count = path_strings.len() as isize - MAX_CANDIDATES as isize + 1; + + for (idx, path_string) in path_strings.iter().enumerate() { + if idx == MAX_CANDIDATES - 1 && count > 1 { + session.fileline_help( + span, + &format!(" and {} other candidates", count).to_string(), + ); + break; + } else { + session.fileline_help( + span, + &format!(" `{}`", path_string).to_string(), + ); + } + } + } + } + } else { + // nothing found: + session.fileline_help( + span, + &format!("no candidates by the name of `{}` found in your \ + project; maybe you misspelled the name or forgot to import \ + an external crate?", candidates.name.to_string()), + ); + }; +} + /// A somewhat inefficient routine to obtain the name of a module. -fn module_to_string<'a>(module: Module<'a>) -> String { +fn module_to_string(module: Module) -> String { let mut names = Vec::new(); - fn collect_mod<'a>(names: &mut Vec, module: Module<'a>) { + fn collect_mod(names: &mut Vec, module: Module) { match module.parent_link { NoParentLink => {} ModuleParentLink(ref module, name) => {