]> git.lizzy.rs Git - rust.git/blobdiff - src/librustc_resolve/lib.rs
Register new snapshots
[rust.git] / src / librustc_resolve / lib.rs
index c32acb7bb269f36f51c3c0aec8c4fec6dd0df251..5711807a6172f6f82928f79bf284ccb343bee3ff 100644 (file)
@@ -8,11 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// Do not remove on snapshot creation. Needed for bootstrap. (Issue #22364)
-#![cfg_attr(stage0, feature(custom_attribute))]
 #![crate_name = "rustc_resolve"]
 #![unstable(feature = "rustc_private", issue = "27812")]
-#![cfg_attr(stage0, staged_api)]
 #![crate_type = "dylib"]
 #![crate_type = "rlib"]
 #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
@@ -64,7 +61,7 @@
 use rustc::util::nodemap::{NodeMap, DefIdSet, FnvHashMap};
 
 use syntax::ast;
-use syntax::ast::{CRATE_NODE_ID, Ident, Name, NodeId, CrateNum, TyIs, TyI8, TyI16, TyI32, TyI64};
+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::attr::AttrMetaMethods;
 use syntax::parse::token::{self, special_names, special_idents};
@@ -179,7 +176,7 @@ pub enum ResolutionError<'a> {
     /// error E0424: `self` is not available in a static method
     SelfNotAvailableInStaticMethod,
     /// error E0425: unresolved name
-    UnresolvedName(&'a str, &'a str),
+    UnresolvedName(&'a str, &'a str, UnresolvedNameContext),
     /// error E0426: use of undeclared label
     UndeclaredLabel(&'a str),
     /// error E0427: cannot use `ref` binding mode with ...
@@ -202,6 +199,21 @@ pub enum ResolutionError<'a> {
     AttemptToUseNonConstantValueInConstant,
 }
 
+/// Context of where `ResolutionError::UnresolvedName` arose.
+#[derive(Clone, PartialEq, Eq, Debug)]
+pub enum UnresolvedNameContext {
+    /// `PathIsMod(id)` indicates that a given path, used in
+    /// expression context, actually resolved to a module rather than
+    /// a value. The `id` attached to the variant is the node id of
+    /// the erroneous path expression.
+    PathIsMod(ast::NodeId),
+
+    /// `Other` means we have no extra information about the context
+    /// of the unresolved name error. (Maybe we could eliminate all
+    /// such cases; but for now, this is an information-free default.)
+    Other,
+}
+
 fn resolve_error<'b, 'a: 'b, 'tcx: 'a>(resolver: &'b Resolver<'a, 'tcx>,
                                        span: syntax::codemap::Span,
                                        resolution_error: ResolutionError<'b>) {
@@ -402,13 +414,46 @@ fn resolve_error<'b, 'a: 'b, 'tcx: 'a>(resolver: &'b Resolver<'a, 'tcx>,
                       "`self` is not available in a static method. Maybe a `self` argument is \
                        missing?");
         }
-        ResolutionError::UnresolvedName(path, name) => {
+        ResolutionError::UnresolvedName(path, msg, context) => {
             span_err!(resolver.session,
                       span,
                       E0425,
                       "unresolved name `{}`{}",
                       path,
-                      name);
+                      msg);
+
+            match context {
+                UnresolvedNameContext::Other => {} // no help available
+                UnresolvedNameContext::PathIsMod(id) => {
+                    let mut help_msg = String::new();
+                    let parent_id = resolver.ast_map.get_parent_node(id);
+                    if let Some(hir_map::Node::NodeExpr(e)) = resolver.ast_map.find(parent_id) {
+                        match e.node {
+                            ExprField(_, ident) => {
+                                help_msg = format!("To reference an item from the \
+                                                    `{module}` module, use \
+                                                    `{module}::{ident}`",
+                                                   module = &*path,
+                                                   ident = ident.node);
+                            }
+
+                            ExprMethodCall(ident, _, _) => {
+                                help_msg = format!("To call a function from the \
+                                                    `{module}` module, use \
+                                                    `{module}::{ident}(..)`",
+                                                   module = &*path,
+                                                   ident = ident.node);
+                            }
+
+                            _ => {} // no help available
+                        }
+                    }
+
+                    if !help_msg.is_empty() {
+                        resolver.session.fileline_help(span, &help_msg);
+                    }
+                }
+            }
         }
         ResolutionError::UndeclaredLabel(name) => {
             span_err!(resolver.session,
@@ -566,6 +611,7 @@ fn visit_poly_trait_ref(&mut self, tref: &hir::PolyTraitRef, m: &hir::TraitBound
             Ok(def) => self.record_def(tref.trait_ref.ref_id, def),
             Err(_) => {
                 // error already reported
+                self.record_def(tref.trait_ref.ref_id, err_path_resolution())
             }
         }
         intravisit::walk_poly_trait_ref(self, tref, m);
@@ -904,8 +950,13 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
 bitflags! {
     #[derive(Debug)]
     flags DefModifiers: u8 {
+        // Enum variants are always considered `PUBLIC`, this is needed for `use Enum::Variant`
+        // or `use Enum::*` to work on private enums.
         const PUBLIC     = 1 << 0,
         const IMPORTABLE = 1 << 1,
+        // Variants are considered `PUBLIC`, but some of them live in private enums.
+        // We need to track them to prohibit reexports like `pub use PrivEnum::Variant`.
+        const PRIVATE_VARIANT = 1 << 2,
     }
 }
 
@@ -1462,7 +1513,8 @@ fn resolve_module_path(&mut self,
     fn resolve_item_in_lexical_scope(&mut self,
                                      module_: Rc<Module>,
                                      name: Name,
-                                     namespace: Namespace)
+                                     namespace: Namespace,
+                                     record_used: bool)
                                      -> ResolveResult<(Target, bool)> {
         debug!("(resolving item in lexical scope) resolving `{}` in namespace {:?} in `{}`",
                name,
@@ -1502,10 +1554,12 @@ fn resolve_item_in_lexical_scope(&mut self,
                     debug!("(resolving item in lexical scope) using import resolution");
                     // track used imports and extern crates as well
                     let id = import_resolution[namespace].id;
-                    self.used_imports.insert((id, namespace));
-                    self.record_import_use(id, name);
-                    if let Some(DefId{krate: kid, ..}) = target.target_module.def_id() {
-                        self.used_crates.insert(kid);
+                    if record_used {
+                        self.used_imports.insert((id, namespace));
+                        self.record_import_use(id, name);
+                        if let Some(DefId{krate: kid, ..}) = target.target_module.def_id() {
+                            self.used_crates.insert(kid);
+                        }
                     }
                     return Success((target, false));
                 }
@@ -1582,7 +1636,7 @@ fn resolve_module_in_lexical_scope(&mut self,
                                        -> ResolveResult<Rc<Module>> {
         // If this module is an anonymous module, resolve the item in the
         // lexical scope. Otherwise, resolve the item from the crate root.
-        let resolve_result = self.resolve_item_in_lexical_scope(module_, name, TypeNS);
+        let resolve_result = self.resolve_item_in_lexical_scope(module_, name, TypeNS, true);
         match resolve_result {
             Success((target, _)) => {
                 if let Some(module_def) = target.binding.module() {
@@ -2005,6 +2059,7 @@ fn resolve_item(&mut self, item: &Item) {
                                                   prefix.span,
                                                   ResolutionError::FailedToResolve(
                                                       &path_names_to_string(prefix, 0)));
+                                    self.record_def(item.id, err_path_resolution());
                                 }
                             }
                         }
@@ -2164,6 +2219,7 @@ fn resolve_generics(&mut self, generics: &Generics) {
                         resolve_error(self,
                                       eq_pred.span,
                                       ResolutionError::UndeclaredAssociatedType);
+                        self.record_def(eq_pred.id, err_path_resolution());
                     }
                 }
             }
@@ -2194,6 +2250,8 @@ fn with_optional_trait_ref<T, F>(&mut self, opt_trait_ref: Option<&TraitRef>, f:
                 self.record_def(trait_ref.ref_id, path_res);
                 new_val = Some((path_res.base_def.def_id(), trait_ref.clone()));
                 new_id = Some(path_res.base_def.def_id());
+            } else {
+                self.record_def(trait_ref.ref_id, err_path_resolution());
             }
             intravisit::walk_trait_ref(self, trait_ref);
         }
@@ -2463,6 +2521,8 @@ fn resolve_type(&mut self, ty: &Ty) {
                         self.record_def(ty.id, def);
                     }
                     None => {
+                        self.record_def(ty.id, err_path_resolution());
+
                         // Keep reporting some errors even if they're ignored above.
                         self.resolve_path(ty.id, path, 0, TypeNS, true);
 
@@ -2545,6 +2605,7 @@ fn resolve_pattern(&mut self,
                                 ResolutionError::DeclarationShadowsEnumVariantOrUnitLikeStruct(
                                     renamed)
                             );
+                            self.record_def(pattern.id, err_path_resolution());
                         }
                         FoundConst(def, lp, _) if const_ok => {
                             debug!("(resolving pattern) resolving `{}` to constant", renamed);
@@ -2564,6 +2625,7 @@ fn resolve_pattern(&mut self,
                                 ResolutionError::OnlyIrrefutablePatternsAllowedHere(def.def_id(),
                                                                                     name)
                             );
+                            self.record_def(pattern.id, err_path_resolution());
                         }
                         BareIdentifierPatternUnresolved => {
                             debug!("(resolving pattern) binding `{}`", renamed);
@@ -2647,6 +2709,7 @@ fn resolve_pattern(&mut self,
                                 resolve_error(&self,
                                               path.span,
                                               ResolutionError::StaticVariableReference);
+                                self.record_def(pattern.id, err_path_resolution());
                             }
                             _ => {
                                 // If anything ends up here entirely resolved,
@@ -2665,6 +2728,7 @@ fn resolve_pattern(&mut self,
                                                  .name
                                                  .as_str())
                                     );
+                                    self.record_def(pattern.id, err_path_resolution());
                                 } else {
                                     let const_name = path.segments
                                                          .last()
@@ -2684,6 +2748,7 @@ fn resolve_pattern(&mut self,
                             ResolutionError::UnresolvedEnumVariantStructOrConst(
                                 &path.segments.last().unwrap().identifier.name.as_str())
                         );
+                        self.record_def(pattern.id, err_path_resolution());
                     }
                     intravisit::walk_path(self, path);
                 }
@@ -2726,6 +2791,7 @@ fn resolve_pattern(&mut self,
                                         &path.segments.last().unwrap().identifier.name.as_str()
                                     )
                                 );
+                                self.record_def(pattern.id, err_path_resolution());
                             }
                         }
                     } else {
@@ -2737,6 +2803,7 @@ fn resolve_pattern(&mut self,
                                                                                       .identifier
                                                                                       .name
                                                                                       .as_str()));
+                        self.record_def(pattern.id, err_path_resolution());
                     }
                     intravisit::walk_pat(self, pattern);
                 }
@@ -2754,6 +2821,7 @@ fn resolve_pattern(&mut self,
                                 ResolutionError::DoesNotNameAStruct(
                                     &*path_names_to_string(path, 0))
                             );
+                            self.record_def(pattern.id, err_path_resolution());
                         }
                     }
                     intravisit::walk_path(self, path);
@@ -2776,7 +2844,7 @@ fn resolve_bare_identifier_pattern(&mut self,
                                        span: Span)
                                        -> BareIdentifierPatternResolution {
         let module = self.current_module.clone();
-        match self.resolve_item_in_lexical_scope(module, name, ValueNS) {
+        match self.resolve_item_in_lexical_scope(module, name, ValueNS, true) {
             Success((target, _)) => {
                 debug!("(resolve bare identifier pattern) succeeded in finding {} at {:?}",
                        name,
@@ -2884,17 +2952,16 @@ pub fn resolve_path(&mut self,
         }
 
         // Try to find a path to an item in a module.
-        let unqualified_def = self.resolve_identifier(segments.last().unwrap().identifier,
-                                                      namespace,
-                                                      check_ribs);
-
+        let last_ident = segments.last().unwrap().identifier;
         if segments.len() <= 1 {
+            let unqualified_def = self.resolve_identifier(last_ident, namespace, check_ribs, true);
             return unqualified_def.and_then(|def| self.adjust_local_def(def, span))
                                   .map(|def| {
                                       PathResolution::new(def, LastMod(AllPublic), path_depth)
                                   });
         }
 
+        let unqualified_def = self.resolve_identifier(last_ident, namespace, check_ribs, false);
         let def = self.resolve_module_relative_path(span, segments, namespace);
         match (def, unqualified_def) {
             (Some((ref d, _)), Some(ref ud)) if *d == ud.def => {
@@ -2914,7 +2981,8 @@ pub fn resolve_path(&mut self,
     fn resolve_identifier(&mut self,
                           identifier: hir::Ident,
                           namespace: Namespace,
-                          check_ribs: bool)
+                          check_ribs: bool,
+                          record_used: bool)
                           -> Option<LocalDef> {
         // First, check to see whether the name is a primitive type.
         if namespace == TypeNS {
@@ -2931,7 +2999,8 @@ fn resolve_identifier(&mut self,
             }
         }
 
-        self.resolve_item_by_name_in_lexical_scope(identifier.unhygienic_name, namespace)
+        let name = identifier.unhygienic_name;
+        self.resolve_item_by_name_in_lexical_scope(name, namespace, record_used)
             .map(LocalDef::from_def)
     }
 
@@ -3182,11 +3251,12 @@ fn resolve_identifier_in_local_ribs(&mut self,
 
     fn resolve_item_by_name_in_lexical_scope(&mut self,
                                              name: Name,
-                                             namespace: Namespace)
+                                             namespace: Namespace,
+                                             record_used: bool)
                                              -> Option<Def> {
         // Check the items.
         let module = self.current_module.clone();
-        match self.resolve_item_in_lexical_scope(module, name, namespace) {
+        match self.resolve_item_in_lexical_scope(module, name, namespace, record_used) {
             Success((target, _)) => {
                 match target.binding.def() {
                     None => {
@@ -3430,6 +3500,7 @@ fn resolve_expr(&mut self, expr: &Expr) {
                         } else {
                             self.session.span_help(expr.span, &msg);
                         }
+                        self.record_def(expr.id, err_path_resolution());
                     } else {
                         // Write the result into the def map.
                         debug!("(resolving expr) resolved `{}`",
@@ -3454,6 +3525,8 @@ fn resolve_expr(&mut self, expr: &Expr) {
                     let type_res = self.with_no_errors(|this| {
                         this.resolve_path(expr.id, path, 0, TypeNS, false)
                     });
+
+                    self.record_def(expr.id, err_path_resolution());
                     match type_res.map(|r| r.base_def) {
                         Some(DefTy(struct_id, _)) if self.structs.contains_key(&struct_id) => {
                             resolve_error(
@@ -3511,13 +3584,33 @@ fn resolve_expr(&mut self, expr: &Expr) {
                                         format!("to call `{}::{}`", path_str, path_name),
                                 };
 
+                                let mut context =  UnresolvedNameContext::Other;
                                 if !msg.is_empty() {
-                                    msg = format!(". Did you mean {}?", msg)
+                                    msg = format!(". Did you mean {}?", msg);
+                                } else {
+                                    // we check if this a module and if so, we display a help
+                                    // message
+                                    let name_path = path.segments.iter()
+                                                        .map(|seg| seg.identifier.name)
+                                                        .collect::<Vec<_>>();
+                                    let current_module = self.current_module.clone();
+
+                                    match self.resolve_module_path(current_module,
+                                                   &name_path[..],
+                                                   UseLexicalScope,
+                                                   expr.span,
+                                                   PathSearch) {
+                                        Success(_) => {
+                                            context = UnresolvedNameContext::PathIsMod(expr.id);
+                                        },
+                                        _ => {},
+                                    };
                                 }
 
                                 resolve_error(self,
                                               expr.span,
-                                              ResolutionError::UnresolvedName(&*path_name, &*msg));
+                                              ResolutionError::UnresolvedName(
+                                                  &*path_name, &*msg, context));
                             }
                         }
                     }
@@ -3540,6 +3633,7 @@ fn resolve_expr(&mut self, expr: &Expr) {
                                       ResolutionError::DoesNotNameAStruct(
                                                                 &*path_names_to_string(path, 0))
                                      );
+                        self.record_def(expr.id, err_path_resolution());
                     }
                 }
 
@@ -3562,6 +3656,7 @@ fn resolve_expr(&mut self, expr: &Expr) {
             ExprBreak(Some(label)) | ExprAgain(Some(label)) => {
                 match self.search_label(label.node.name) {
                     None => {
+                        self.record_def(expr.id, err_path_resolution());
                         resolve_error(self,
                                       label.span,
                                       ResolutionError::UndeclaredLabel(&label.node.name.as_str()))
@@ -3811,6 +3906,14 @@ fn collect_mod(names: &mut Vec<ast::Name>, module: &Module) {
     names_to_string(&names.into_iter().rev().collect::<Vec<ast::Name>>())
 }
 
+fn err_path_resolution() -> PathResolution {
+    PathResolution {
+        base_def: DefErr,
+        last_private: LastMod(AllPublic),
+        depth: 0,
+    }
+}
+
 
 pub struct CrateMap {
     pub def_map: RefCell<DefMap>,
@@ -3836,7 +3939,6 @@ pub fn resolve_crate<'a, 'tcx>(session: &'a Session,
     let mut resolver = create_resolver(session, ast_map, krate, make_glob_map, None);
 
     resolver.resolve_crate(krate);
-    session.abort_if_errors();
 
     check_unused::check_crate(&mut resolver, krate);