diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index d3b70933e2cd..a10bb3e25df6 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -1139,32 +1139,4 @@ impl<'a> CrateLoader<'a> { cnum } - - pub fn process_use_extern( - &mut self, - name: Symbol, - span: Span, - id: ast::NodeId, - definitions: &Definitions, - ) -> CrateNum { - let cnum = self.resolve_crate( - &None, name, name, None, None, span, PathKind::Crate, DepKind::Explicit - ).0; - - let def_id = definitions.opt_local_def_id(id).unwrap(); - let path_len = definitions.def_path(def_id.index).data.len(); - - self.update_extern_crate( - cnum, - ExternCrate { - src: ExternCrateSource::Use, - span, - path_len, - direct: true, - }, - &mut FxHashSet(), - ); - - cnum - } } diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index bf87b00c1496..06bc41548b95 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -17,7 +17,7 @@ use macros::{InvocationData, LegacyScope}; use resolve_imports::ImportDirective; use resolve_imports::ImportDirectiveSubclass::{self, GlobImport, SingleImport}; use {Module, ModuleData, ModuleKind, NameBinding, NameBindingKind, ToNameBinding}; -use {PerNS, Resolver, ResolverArenas}; +use {ModuleOrUniformRoot, PerNS, Resolver, ResolverArenas}; use Namespace::{self, TypeNS, ValueNS, MacroNS}; use {resolve_error, resolve_struct_error, ResolutionError}; @@ -175,7 +175,12 @@ impl<'a, 'cl> Resolver<'a, 'cl> { ModuleKind::Def(_, name) => name, ModuleKind::Block(..) => unreachable!(), }; - source.name = crate_name; + // HACK(eddyb) unclear how good this is, but keeping `$crate` + // in `source` breaks `src/test/compile-fail/import-crate-var.rs`, + // while the current crate doesn't have a valid `crate_name`. + if crate_name != keywords::Invalid.name() { + source.name = crate_name; + } if rename.is_none() { ident.name = crate_name; } @@ -187,6 +192,12 @@ impl<'a, 'cl> Resolver<'a, 'cl> { } } + if ident.name == keywords::Crate.name() { + self.session.span_err(ident.span, + "crate root imports need to be explicitly named: \ + `use crate as name;`"); + } + let subclass = SingleImport { target: ident, source, @@ -299,7 +310,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> { root_id: item.id, id: item.id, parent, - imported_module: Cell::new(Some(module)), + imported_module: Cell::new(Some(ModuleOrUniformRoot::Module(module))), subclass: ImportDirectiveSubclass::ExternCrate(orig_name), root_span: item.span, span: item.span, @@ -701,7 +712,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> { root_id: item.id, id: item.id, parent: graph_root, - imported_module: Cell::new(Some(module)), + imported_module: Cell::new(Some(ModuleOrUniformRoot::Module(module))), subclass: ImportDirectiveSubclass::MacroUse, root_span: span, span, @@ -721,7 +732,13 @@ impl<'a, 'cl> Resolver<'a, 'cl> { } else { for (name, span) in legacy_imports.imports { let ident = Ident::with_empty_ctxt(name); - let result = self.resolve_ident_in_module(module, ident, MacroNS, false, span); + let result = self.resolve_ident_in_module( + ModuleOrUniformRoot::Module(module), + ident, + MacroNS, + false, + span, + ); if let Ok(binding) = result { let directive = macro_use_directive(span); self.potentially_unused_imports.push(directive); diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index e31e2cc1dff5..992ea12ffa2b 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -953,9 +953,20 @@ impl<'a> LexicalScopeBinding<'a> { } } +#[derive(Copy, Clone, Debug)] +pub enum ModuleOrUniformRoot<'a> { + /// Regular module. + Module(Module<'a>), + + /// The `{{root}}` (`CrateRoot` aka "global") / `extern` initial segment + /// in which external crates resolve, and also `crate` (only in `{{root}}`, + /// but *not* `extern`), in the Rust 2018 edition. + UniformRoot(Name), +} + #[derive(Clone, Debug)] enum PathResult<'a> { - Module(Module<'a>), + Module(ModuleOrUniformRoot<'a>), NonModule(PathResolution), Indeterminate, Failed(Span, String, bool /* is the error from the last segment? */), @@ -1583,11 +1594,13 @@ impl<'a, 'crateloader> Resolver<'a, 'crateloader> { let hir::Path { ref segments, span, ref mut def } = *path; let path: Vec<_> = segments.iter().map(|seg| seg.ident).collect(); // FIXME (Manishearth): Intra doc links won't get warned of epoch changes - match self.resolve_path(&path, Some(namespace), true, span, CrateLint::No) { - PathResult::Module(module) => *def = module.def().unwrap(), + match self.resolve_path(None, &path, Some(namespace), true, span, CrateLint::No) { + PathResult::Module(ModuleOrUniformRoot::Module(module)) => + *def = module.def().unwrap(), PathResult::NonModule(path_res) if path_res.unresolved_segments() == 0 => *def = path_res.base_def(), PathResult::NonModule(..) => match self.resolve_path( + None, &path, None, true, @@ -1599,6 +1612,7 @@ impl<'a, 'crateloader> Resolver<'a, 'crateloader> { } _ => {} }, + PathResult::Module(ModuleOrUniformRoot::UniformRoot(_)) | PathResult::Indeterminate => unreachable!(), PathResult::Failed(span, msg, _) => { error_callback(self, span, ResolutionError::FailedToResolve(&msg)); @@ -1881,7 +1895,12 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> { }; let item = self.resolve_ident_in_module_unadjusted( - module, ident, ns, false, record_used, path_span, + ModuleOrUniformRoot::Module(module), + ident, + ns, + false, + record_used, + path_span, ); if let Ok(binding) = item { // The ident resolves to an item. @@ -1906,7 +1925,12 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> { let orig_current_module = self.current_module; self.current_module = module; // Lexical resolutions can never be a privacy error. let result = self.resolve_ident_in_module_unadjusted( - module, ident, ns, false, record_used, path_span, + ModuleOrUniformRoot::Module(module), + ident, + ns, + false, + record_used, + path_span, ); self.current_module = orig_current_module; @@ -1954,8 +1978,14 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> { return Some(LexicalScopeBinding::Item(binding)); } if let Some(prelude) = self.prelude { - if let Ok(binding) = self.resolve_ident_in_module_unadjusted(prelude, ident, ns, - false, false, path_span) { + if let Ok(binding) = self.resolve_ident_in_module_unadjusted( + ModuleOrUniformRoot::Module(prelude), + ident, + ns, + false, + false, + path_span, + ) { return Some(LexicalScopeBinding::Item(binding)); } } @@ -2013,7 +2043,7 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> { } fn resolve_ident_in_module(&mut self, - module: Module<'a>, + module: ModuleOrUniformRoot<'a>, mut ident: Ident, ns: Namespace, record_used: bool, @@ -2021,8 +2051,10 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> { -> Result<&'a NameBinding<'a>, Determinacy> { ident.span = ident.span.modern(); let orig_current_module = self.current_module; - if let Some(def) = ident.span.adjust(module.expansion) { - self.current_module = self.macro_def_scope(def); + if let ModuleOrUniformRoot::Module(module) = module { + if let Some(def) = ident.span.adjust(module.expansion) { + self.current_module = self.macro_def_scope(def); + } } let result = self.resolve_ident_in_module_unadjusted( module, ident, ns, false, record_used, span, @@ -2410,13 +2442,16 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> { if def != Def::Err { new_id = Some(def.def_id()); let span = trait_ref.path.span; - if let PathResult::Module(module) = self.resolve_path( - &path, - None, - false, - span, - CrateLint::SimplePath(trait_ref.ref_id), - ) { + if let PathResult::Module(ModuleOrUniformRoot::Module(module)) = + self.resolve_path( + None, + &path, + None, + false, + span, + CrateLint::SimplePath(trait_ref.ref_id), + ) + { new_val = Some((module, trait_ref.clone())); } } @@ -2533,7 +2568,13 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> { // If there is a TraitRef in scope for an impl, then the method must be in the // trait. if let Some((module, _)) = self.current_trait_ref { - if self.resolve_ident_in_module(module, ident, ns, false, span).is_err() { + if self.resolve_ident_in_module( + ModuleOrUniformRoot::Module(module), + ident, + ns, + false, + span, + ).is_err() { let path = &self.current_trait_ref.as_ref().unwrap().1.path; resolve_error(self, span, err(ident.name, &path_names_to_string(path))); } @@ -2908,9 +2949,10 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> { (String::new(), "the crate root".to_string()) } else { let mod_path = &path[..path.len() - 1]; - let mod_prefix = match this.resolve_path(mod_path, Some(TypeNS), + let mod_prefix = match this.resolve_path(None, mod_path, Some(TypeNS), false, span, CrateLint::No) { - PathResult::Module(module) => module.def(), + PathResult::Module(ModuleOrUniformRoot::Module(module)) => + module.def(), _ => None, }.map_or(String::new(), |def| format!("{} ", def.kind_name())); (mod_prefix, format!("`{}`", names_to_string(mod_path))) @@ -3319,6 +3361,7 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> { } let result = match self.resolve_path( + None, &path, Some(ns), true, @@ -3326,7 +3369,7 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> { crate_lint, ) { PathResult::NonModule(path_res) => path_res, - PathResult::Module(module) if !module.is_normal() => { + PathResult::Module(ModuleOrUniformRoot::Module(module)) if !module.is_normal() => { PathResolution::new(module.def().unwrap()) } // In `a(::assoc_item)*` `a` cannot be a module. If `a` does resolve to a module we @@ -3341,18 +3384,21 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> { // // Such behavior is required for backward compatibility. // The same fallback is used when `a` resolves to nothing. - PathResult::Module(..) | PathResult::Failed(..) + PathResult::Module(ModuleOrUniformRoot::Module(_)) | + PathResult::Failed(..) if (ns == TypeNS || path.len() > 1) && self.primitive_type_table.primitive_types .contains_key(&path[0].name) => { let prim = self.primitive_type_table.primitive_types[&path[0].name]; PathResolution::with_unresolved_segments(Def::PrimTy(prim), path.len() - 1) } - PathResult::Module(module) => PathResolution::new(module.def().unwrap()), + PathResult::Module(ModuleOrUniformRoot::Module(module)) => + PathResolution::new(module.def().unwrap()), PathResult::Failed(span, msg, false) => { resolve_error(self, span, ResolutionError::FailedToResolve(&msg)); err_path_resolution() } + PathResult::Module(ModuleOrUniformRoot::UniformRoot(_)) | PathResult::Failed(..) => return None, PathResult::Indeterminate => bug!("indetermined path result in resolve_qpath"), }; @@ -3362,6 +3408,7 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> { path[0].name != keywords::DollarCrate.name() { let unqualified_result = { match self.resolve_path( + None, &[*path.last().unwrap()], Some(ns), false, @@ -3369,7 +3416,8 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> { CrateLint::No, ) { PathResult::NonModule(path_res) => path_res.base_def(), - PathResult::Module(module) => module.def().unwrap(), + PathResult::Module(ModuleOrUniformRoot::Module(module)) => + module.def().unwrap(), _ => return Some(result), } }; @@ -3384,13 +3432,14 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> { fn resolve_path( &mut self, + base_module: Option>, path: &[Ident], opt_ns: Option, // `None` indicates a module path record_used: bool, path_span: Span, crate_lint: CrateLint, ) -> PathResult<'a> { - let mut module = None; + let mut module = base_module; let mut allow_super = true; let mut second_binding = None; @@ -3412,49 +3461,48 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> { if i == 0 && ns == TypeNS && name == keywords::SelfValue.name() { let mut ctxt = ident.span.ctxt().modern(); - module = Some(self.resolve_self(&mut ctxt, self.current_module)); + module = Some(ModuleOrUniformRoot::Module( + self.resolve_self(&mut ctxt, self.current_module))); continue } else if allow_super && ns == TypeNS && name == keywords::Super.name() { let mut ctxt = ident.span.ctxt().modern(); - let self_module = match i { - 0 => self.resolve_self(&mut ctxt, self.current_module), - _ => module.unwrap(), + let self_module_parent = match i { + 0 => self.resolve_self(&mut ctxt, self.current_module).parent, + _ => match module { + Some(ModuleOrUniformRoot::Module(module)) => module.parent, + _ => None, + }, }; - if let Some(parent) = self_module.parent { - module = Some(self.resolve_self(&mut ctxt, parent)); + if let Some(parent) = self_module_parent { + module = Some(ModuleOrUniformRoot::Module( + self.resolve_self(&mut ctxt, parent))); continue } else { let msg = "There are too many initial `super`s.".to_string(); return PathResult::Failed(ident.span, msg, false); } - } else if i == 0 && ns == TypeNS && name == keywords::Extern.name() { - continue; } allow_super = false; if ns == TypeNS { + if i == 0 { + if name == keywords::Extern.name() || + name == keywords::CrateRoot.name() && + self.session.features_untracked().extern_absolute_paths && + self.session.rust_2018() { + module = Some(ModuleOrUniformRoot::UniformRoot(name)); + continue; + } + } if (i == 0 && name == keywords::CrateRoot.name()) || (i == 0 && name == keywords::Crate.name()) || (i == 0 && name == keywords::DollarCrate.name()) || (i == 1 && name == keywords::Crate.name() && path[0].name == keywords::CrateRoot.name()) { // `::a::b`, `crate::a::b`, `::crate::a::b` or `$crate::a::b` - module = Some(self.resolve_crate_root(ident)); + module = Some(ModuleOrUniformRoot::Module( + self.resolve_crate_root(ident))); continue - } else if i == 1 && !ident.is_path_segment_keyword() { - let prev_name = path[0].name; - if prev_name == keywords::Extern.name() || - prev_name == keywords::CrateRoot.name() && - self.session.features_untracked().extern_absolute_paths && - self.session.rust_2018() { - // `::extern_crate::a::b` - let crate_id = self.crate_loader.process_path_extern(name, ident.span); - let crate_root = - self.get_module(DefId { krate: crate_id, index: CRATE_DEF_INDEX }); - self.populate_module_if_necessary(crate_root); - module = Some(crate_root); - continue - } } } @@ -3513,7 +3561,7 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> { let def = binding.def(); let maybe_assoc = opt_ns != Some(MacroNS) && PathSource::Type.is_expected(def); if let Some(next_module) = binding.module() { - module = Some(next_module); + module = Some(ModuleOrUniformRoot::Module(next_module)); } else if def == Def::ToolMod && i + 1 != path.len() { let def = Def::NonMacroAttr(NonMacroAttrKind::Tool); return PathResult::NonModule(PathResolution::new(def)); @@ -3537,14 +3585,18 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> { } Err(Undetermined) => return PathResult::Indeterminate, Err(Determined) => { - if let Some(module) = module { + if let Some(ModuleOrUniformRoot::Module(module)) = module { if opt_ns.is_some() && !module.is_normal() { return PathResult::NonModule(PathResolution::with_unresolved_segments( module.def().unwrap(), path.len() - i )); } } - let msg = if module.and_then(ModuleData::def) == self.graph_root.def() { + let module_def = match module { + Some(ModuleOrUniformRoot::Module(module)) => module.def(), + _ => None, + }; + let msg = if module_def == self.graph_root.def() { let is_mod = |def| match def { Def::Mod(..) => true, _ => false }; let mut candidates = self.lookup_import_candidates(name, TypeNS, is_mod); @@ -3568,7 +3620,10 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> { self.lint_if_path_starts_with_module(crate_lint, path, path_span, second_binding); - PathResult::Module(module.unwrap_or(self.graph_root)) + PathResult::Module(module.unwrap_or_else(|| { + span_bug!(path_span, "resolve_path: empty(?) path {:?} has no module", path); + })) + } fn lint_if_path_starts_with_module( @@ -3578,6 +3633,17 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> { path_span: Span, second_binding: Option<&NameBinding>, ) { + // In the 2018 edition this lint is a hard error, so nothing to do + if self.session.rust_2018() { + return + } + + // In the 2015 edition there's no use in emitting lints unless the + // crate's already enabled the feature that we're going to suggest + if !self.session.features_untracked().crate_in_paths { + return + } + let (diag_id, diag_span) = match crate_lint { CrateLint::No => return, CrateLint::SimplePath(id) => (id, path_span), @@ -3620,24 +3686,11 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> { } } - self.lint_path_starts_with_module(diag_id, diag_span); - } - - fn lint_path_starts_with_module(&self, id: NodeId, span: Span) { - // In the 2018 edition this lint is a hard error, so nothing to do - if self.session.rust_2018() { - return - } - // In the 2015 edition there's no use in emitting lints unless the - // crate's already enabled the feature that we're going to suggest - if !self.session.features_untracked().crate_in_paths { - return - } let diag = lint::builtin::BuiltinLintDiagnostics - ::AbsPathWithModule(span); + ::AbsPathWithModule(diag_span); self.session.buffer_lint_with_diagnostic( lint::builtin::ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE, - id, span, + diag_id, diag_span, "absolute paths must start with `self`, `super`, \ `crate`, or an external crate name in the 2018 edition", diag); @@ -3782,8 +3835,13 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> { // Look for associated items in the current trait. if let Some((module, _)) = self.current_trait_ref { - if let Ok(binding) = - self.resolve_ident_in_module(module, ident, ns, false, module.span) { + if let Ok(binding) = self.resolve_ident_in_module( + ModuleOrUniformRoot::Module(module), + ident, + ns, + false, + module.span, + ) { let def = binding.def(); if filter_fn(def) { return Some(if self.has_self.contains(&def.def_id()) { @@ -3855,9 +3913,11 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> { } else { // Search in module. let mod_path = &path[..path.len() - 1]; - if let PathResult::Module(module) = self.resolve_path(mod_path, Some(TypeNS), + if let PathResult::Module(module) = self.resolve_path(None, mod_path, Some(TypeNS), false, span, CrateLint::No) { - add_module_candidates(module, &mut names); + if let ModuleOrUniformRoot::Module(module) = module { + add_module_candidates(module, &mut names); + } } } @@ -4096,7 +4156,13 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> { let mut found_traits = Vec::new(); // Look for the current trait. if let Some((module, _)) = self.current_trait_ref { - if self.resolve_ident_in_module(module, ident, ns, false, module.span).is_ok() { + if self.resolve_ident_in_module( + ModuleOrUniformRoot::Module(module), + ident, + ns, + false, + module.span, + ).is_ok() { let def_id = module.def_id().unwrap(); found_traits.push(TraitCandidate { def_id: def_id, import_id: None }); } @@ -4144,8 +4210,14 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> { if ident.span.glob_adjust(module.expansion, binding.span.ctxt().modern()).is_none() { continue } - if self.resolve_ident_in_module_unadjusted(module, ident, ns, false, false, module.span) - .is_ok() { + if self.resolve_ident_in_module_unadjusted( + ModuleOrUniformRoot::Module(module), + ident, + ns, + false, + false, + module.span, + ).is_ok() { let import_id = match binding.kind { NameBindingKind::Import { directive, .. } => { self.maybe_unused_trait_imports.insert(directive.id); diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index fe9d3c7eb998..44d0c888c5dd 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -10,6 +10,7 @@ use {AmbiguityError, CrateLint, Resolver, ResolutionError, is_known_tool, resolve_error}; use {Module, ModuleKind, NameBinding, NameBindingKind, PathResult, ToNameBinding}; +use ModuleOrUniformRoot; use Namespace::{self, TypeNS, MacroNS}; use build_reduced_graph::{BuildReducedGraphVisitor, IsMacroExport}; use resolve_imports::ImportResolver; @@ -538,7 +539,8 @@ impl<'a, 'cl> Resolver<'a, 'cl> { return Err(Determinacy::Determined); } - let def = match self.resolve_path(&path, Some(MacroNS), false, span, CrateLint::No) { + let res = self.resolve_path(None, &path, Some(MacroNS), false, span, CrateLint::No); + let def = match res { PathResult::NonModule(path_res) => match path_res.base_def() { Def::Err => Err(Determinacy::Determined), def @ _ => { @@ -655,7 +657,12 @@ impl<'a, 'cl> Resolver<'a, 'cl> { WhereToResolve::Module(module) => { let orig_current_module = mem::replace(&mut self.current_module, module); let binding = self.resolve_ident_in_module_unadjusted( - module, ident, ns, true, record_used, path_span, + ModuleOrUniformRoot::Module(module), + ident, + ns, + true, + record_used, + path_span, ); self.current_module = orig_current_module; binding.map(MacroBinding::Modern) @@ -715,9 +722,14 @@ impl<'a, 'cl> Resolver<'a, 'cl> { let mut result = Err(Determinacy::Determined); if use_prelude { if let Some(prelude) = self.prelude { - if let Ok(binding) = - self.resolve_ident_in_module_unadjusted(prelude, ident, ns, - false, false, path_span) { + if let Ok(binding) = self.resolve_ident_in_module_unadjusted( + ModuleOrUniformRoot::Module(prelude), + ident, + ns, + false, + false, + path_span, + ) { result = Ok(MacroBinding::Global(binding)); } } @@ -893,7 +905,7 @@ impl<'a, 'cl> Resolver<'a, 'cl> { pub fn finalize_current_module_macro_resolutions(&mut self) { let module = self.current_module; for &(ref path, span) in module.macro_resolutions.borrow().iter() { - match self.resolve_path(&path, Some(MacroNS), true, span, CrateLint::No) { + match self.resolve_path(None, &path, Some(MacroNS), true, span, CrateLint::No) { PathResult::NonModule(_) => {}, PathResult::Failed(span, msg, _) => { resolve_error(self, span, ResolutionError::FailedToResolve(&msg)); diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index 715292bc1162..58f7532adaf5 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -10,7 +10,7 @@ use self::ImportDirectiveSubclass::*; -use {AmbiguityError, CrateLint, Module, PerNS}; +use {AmbiguityError, CrateLint, Module, ModuleOrUniformRoot, PerNS}; use Namespace::{self, TypeNS, MacroNS}; use {NameBinding, NameBindingKind, ToNameBinding, PathResult, PrivacyError}; use Resolver; @@ -85,7 +85,8 @@ pub struct ImportDirective<'a> { pub parent: Module<'a>, pub module_path: Vec, - pub imported_module: Cell>>, // the resolution of `module_path` + /// The resolution of `module_path`. + pub imported_module: Cell>>, pub subclass: ImportDirectiveSubclass<'a>, pub vis: Cell, pub expansion: Mark, @@ -133,13 +134,38 @@ impl<'a, 'crateloader> Resolver<'a, 'crateloader> { /// Attempts to resolve `ident` in namespaces `ns` of `module`. /// Invariant: if `record_used` is `Some`, expansion and import resolution must be complete. pub fn resolve_ident_in_module_unadjusted(&mut self, - module: Module<'a>, + module: ModuleOrUniformRoot<'a>, ident: Ident, ns: Namespace, restricted_shadowing: bool, record_used: bool, path_span: Span) -> Result<&'a NameBinding<'a>, Determinacy> { + let module = match module { + ModuleOrUniformRoot::Module(module) => module, + ModuleOrUniformRoot::UniformRoot(root) => { + let crate_root = if + root != keywords::Extern.name() && + ( + ident.name == keywords::Crate.name() || + ident.name == keywords::DollarCrate.name() + ) + { + self.resolve_crate_root(ident) + } else if !ident.is_path_segment_keyword() { + let crate_id = + self.crate_loader.process_path_extern(ident.name, ident.span); + self.get_module(DefId { krate: crate_id, index: CRATE_DEF_INDEX }) + } else { + return Err(Determined); + }; + self.populate_module_if_necessary(crate_root); + let binding = (crate_root, ty::Visibility::Public, + ident.span, Mark::root()).to_name_binding(self.arenas); + return Ok(binding); + } + }; + self.populate_module_if_necessary(module); let resolution = self.resolution(module, ident, ns) @@ -260,7 +286,11 @@ impl<'a, 'crateloader> Resolver<'a, 'crateloader> { if !self.is_accessible(glob_import.vis.get()) { continue } - let module = unwrap_or!(glob_import.imported_module.get(), return Err(Undetermined)); + let module = match glob_import.imported_module.get() { + Some(ModuleOrUniformRoot::Module(module)) => module, + Some(ModuleOrUniformRoot::UniformRoot(_)) => continue, + None => return Err(Undetermined), + }; let (orig_current_module, mut ident) = (self.current_module, ident.modern()); match ident.span.glob_adjust(module.expansion, glob_import.span.ctxt().modern()) { Some(Some(def)) => self.current_module = self.macro_def_scope(def), @@ -268,7 +298,12 @@ impl<'a, 'crateloader> Resolver<'a, 'crateloader> { None => continue, }; let result = self.resolve_ident_in_module_unadjusted( - module, ident, ns, false, false, path_span, + ModuleOrUniformRoot::Module(module), + ident, + ns, + false, + false, + path_span, ); self.current_module = orig_current_module; match result { @@ -576,8 +611,14 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> { // For better failure detection, pretend that the import will not define any names // while resolving its module path. directive.vis.set(ty::Visibility::Invisible); - let result = self.resolve_path(&directive.module_path[..], None, false, - directive.span, directive.crate_lint()); + let result = self.resolve_path( + Some(ModuleOrUniformRoot::UniformRoot(keywords::Invalid.name())), + &directive.module_path[..], + None, + false, + directive.span, + directive.crate_lint(), + ); directive.vis.set(vis); match result { @@ -644,77 +685,9 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> { fn finalize_import(&mut self, directive: &'b ImportDirective<'b>) -> Option<(Span, String)> { self.current_module = directive.parent; let ImportDirective { ref module_path, span, .. } = *directive; - let mut warn_if_binding_comes_from_local_crate = false; - - // FIXME: Last path segment is treated specially in import resolution, so extern crate - // mode for absolute paths needs some special support for single-segment imports. - if module_path.len() == 1 && (module_path[0].name == keywords::CrateRoot.name() || - module_path[0].name == keywords::Extern.name()) { - let is_extern = module_path[0].name == keywords::Extern.name() || - (self.session.features_untracked().extern_absolute_paths && - self.session.rust_2018()); - match directive.subclass { - GlobImport { .. } if is_extern => { - return Some((directive.span, - "cannot glob-import all possible crates".to_string())); - } - GlobImport { .. } if self.session.features_untracked().extern_absolute_paths => { - self.lint_path_starts_with_module( - directive.root_id, - directive.root_span, - ); - } - SingleImport { source, target, .. } => { - let crate_root = if source.name == keywords::Crate.name() && - module_path[0].name != keywords::Extern.name() { - if target.name == keywords::Crate.name() { - return Some((directive.span, - "crate root imports need to be explicitly named: \ - `use crate as name;`".to_string())); - } else { - Some(self.resolve_crate_root(source)) - } - } else if is_extern && !source.is_path_segment_keyword() { - let crate_id = - self.resolver.crate_loader.process_use_extern( - source.name, - directive.span, - directive.id, - &self.resolver.definitions, - ); - let crate_root = - self.get_module(DefId { krate: crate_id, index: CRATE_DEF_INDEX }); - self.populate_module_if_necessary(crate_root); - Some(crate_root) - } else { - warn_if_binding_comes_from_local_crate = true; - None - }; - - if let Some(crate_root) = crate_root { - let binding = (crate_root, ty::Visibility::Public, directive.span, - directive.expansion).to_name_binding(self.arenas); - let binding = self.arenas.alloc_name_binding(NameBinding { - kind: NameBindingKind::Import { - binding, - directive, - used: Cell::new(false), - }, - vis: directive.vis.get(), - span: directive.span, - expansion: directive.expansion, - }); - let _ = self.try_define(directive.parent, target, TypeNS, binding); - let import = self.import_map.entry(directive.id).or_default(); - import[TypeNS] = Some(PathResolution::new(binding.def())); - return None; - } - } - _ => {} - } - } let module_result = self.resolve_path( + Some(ModuleOrUniformRoot::UniformRoot(keywords::Invalid.name())), &module_path, None, true, @@ -734,7 +707,7 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> { if !self_path.is_empty() && !is_special(self_path[0]) && !(self_path.len() > 1 && is_special(self_path[1])) { self_path[0].name = keywords::SelfValue.name(); - self_result = Some(self.resolve_path(&self_path, None, false, + self_result = Some(self.resolve_path(None, &self_path, None, false, span, CrateLint::No)); } return if let Some(PathResult::Module(..)) = self_result { @@ -748,12 +721,27 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> { let (ident, result, type_ns_only) = match directive.subclass { SingleImport { source, ref result, type_ns_only, .. } => (source, result, type_ns_only), - GlobImport { .. } if module.def_id() == directive.parent.def_id() => { - // Importing a module into itself is not allowed. - return Some((directive.span, - "Cannot glob-import a module into itself.".to_string())); - } GlobImport { is_prelude, ref max_vis } => { + if module_path.len() <= 1 { + // HACK(eddyb) `lint_if_path_starts_with_module` needs at least + // 2 segments, so the `resolve_path` above won't trigger it. + let mut full_path = module_path.clone(); + full_path.push(keywords::Invalid.ident()); + self.lint_if_path_starts_with_module( + directive.crate_lint(), + &full_path, + directive.span, + None, + ); + } + + if let ModuleOrUniformRoot::Module(module) = module { + if module.def_id() == directive.parent.def_id() { + // Importing a module into itself is not allowed. + return Some((directive.span, + "Cannot glob-import a module into itself.".to_string())); + } + } if !is_prelude && max_vis.get() != ty::Visibility::Invisible && // Allow empty globs. !max_vis.get().is_at_least(directive.vis.get(), &*self) { @@ -770,8 +758,10 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> { if let Ok(binding) = result[ns].get() { all_ns_err = false; if this.record_use(ident, ns, binding, directive.span) { - this.resolution(module, ident, ns).borrow_mut().binding = - Some(this.dummy_binding); + if let ModuleOrUniformRoot::Module(module) = module { + this.resolution(module, ident, ns).borrow_mut().binding = + Some(this.dummy_binding); + } } } }); @@ -786,8 +776,13 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> { }); return if all_ns_failed { - let resolutions = module.resolutions.borrow(); - let names = resolutions.iter().filter_map(|(&(ref i, _), resolution)| { + let resolutions = match module { + ModuleOrUniformRoot::Module(module) => + Some(module.resolutions.borrow()), + ModuleOrUniformRoot::UniformRoot(_) => None, + }; + let resolutions = resolutions.as_ref().into_iter().flat_map(|r| r.iter()); + let names = resolutions.filter_map(|(&(ref i, _), resolution)| { if *i == ident { return None; } // Never suggest the same name match *resolution.borrow() { NameResolution { binding: Some(name_binding), .. } => { @@ -813,11 +808,24 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> { Some(name) => format!(". Did you mean to use `{}`?", name), None => "".to_owned(), }; - let module_str = module_to_string(module); - let msg = if let Some(module_str) = module_str { - format!("no `{}` in `{}`{}", ident, module_str, lev_suggestion) - } else { - format!("no `{}` in the root{}", ident, lev_suggestion) + let msg = match module { + ModuleOrUniformRoot::Module(module) => { + let module_str = module_to_string(module); + if let Some(module_str) = module_str { + format!("no `{}` in `{}`{}", ident, module_str, lev_suggestion) + } else { + format!("no `{}` in the root{}", ident, lev_suggestion) + } + } + ModuleOrUniformRoot::UniformRoot(_) => { + if !ident.is_path_segment_keyword() { + format!("no `{}` external crate{}", ident, lev_suggestion) + } else { + // HACK(eddyb) this shows up for `self` & `super`, which + // should work instead - for now keep the same error message. + format!("no `{}` in the root{}", ident, lev_suggestion) + } + } }; Some((span, msg)) } else { @@ -868,26 +876,20 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> { } } - if warn_if_binding_comes_from_local_crate { - let mut warned = false; + if module_path.len() <= 1 { + // HACK(eddyb) `lint_if_path_starts_with_module` needs at least + // 2 segments, so the `resolve_path` above won't trigger it. + let mut full_path = module_path.clone(); + full_path.push(ident); self.per_ns(|this, ns| { - let binding = match result[ns].get().ok() { - Some(b) => b, - None => return - }; - if let NameBindingKind::Import { directive: d, .. } = binding.kind { - if let ImportDirectiveSubclass::ExternCrate(..) = d.subclass { - return - } + if let Ok(binding) = result[ns].get() { + this.lint_if_path_starts_with_module( + directive.crate_lint(), + &full_path, + directive.span, + Some(binding), + ); } - if warned { - return - } - warned = true; - this.lint_path_starts_with_module( - directive.root_id, - directive.root_span, - ); }); } @@ -904,7 +906,15 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> { } fn resolve_glob_import(&mut self, directive: &'b ImportDirective<'b>) { - let module = directive.imported_module.get().unwrap(); + let module = match directive.imported_module.get().unwrap() { + ModuleOrUniformRoot::Module(module) => module, + ModuleOrUniformRoot::UniformRoot(_) => { + self.session.span_err(directive.span, + "cannot glob-import all possible crates"); + return; + } + }; + self.populate_module_if_necessary(module); if let Some(Def::Trait(_)) = module.def() { @@ -1026,8 +1036,10 @@ impl<'a, 'b:'a, 'c: 'b> ImportResolver<'a, 'b, 'c> { }; let mut err = self.session.struct_span_err(binding.span, &msg); - let imported_module = directive.imported_module.get() - .expect("module should exist"); + let imported_module = match directive.imported_module.get() { + Some(ModuleOrUniformRoot::Module(module)) => module, + _ => bug!("module should exist"), + }; let resolutions = imported_module.parent.expect("parent should exist") .resolutions.borrow(); let enum_path_segment_index = directive.module_path.len() - 1; diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 6925ed2afb83..b66946affadb 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -101,7 +101,7 @@ impl Path { // or starts with something like `self`/`super`/`$crate`/etc. pub fn make_root(&self) -> Option { if let Some(ident) = self.segments.get(0).map(|seg| seg.ident) { - if ident.is_path_segment_keyword() && ident.name != keywords::Crate.name() { + if ident.is_path_segment_keyword() { return None; } } diff --git a/src/test/compile-fail/dollar-crate-is-keyword.rs b/src/test/compile-fail/dollar-crate-is-keyword.rs index 70597a230a88..4a667f020ad3 100644 --- a/src/test/compile-fail/dollar-crate-is-keyword.rs +++ b/src/test/compile-fail/dollar-crate-is-keyword.rs @@ -10,7 +10,11 @@ macro_rules! m { () => { - struct $crate {} //~ ERROR expected identifier, found reserved identifier `$crate` + // Avoid having more than one `$crate`-named item in the same module, + // as even though they error, they still parse as `$crate` and conflict. + mod foo { + struct $crate {} //~ ERROR expected identifier, found reserved identifier `$crate` + } use $crate; // OK //~^ WARN `$crate` may not be imported diff --git a/src/test/compile-fail/import-crate-var.rs b/src/test/compile-fail/import-crate-var.rs index e58ba2c88917..b09883d9adee 100644 --- a/src/test/compile-fail/import-crate-var.rs +++ b/src/test/compile-fail/import-crate-var.rs @@ -9,15 +9,14 @@ // except according to those terms. // aux-build:import_crate_var.rs -// error-pattern: `$crate` may not be imported -// error-pattern: `use $crate;` was erroneously allowed and will become a hard error -// error-pattern: compilation successful #![feature(rustc_attrs)] #[macro_use] extern crate import_crate_var; #[rustc_error] -fn main() { +fn main() { //~ ERROR compilation successful m!(); + //~^ WARN `$crate` may not be imported + //~| NOTE `use $crate;` was erroneously allowed and will become a hard error } diff --git a/src/test/compile-fail/keyword-extern-as-identifier.rs b/src/test/compile-fail/keyword-extern-as-identifier.rs index e5927d09b416..3e4458539578 100644 --- a/src/test/compile-fail/keyword-extern-as-identifier.rs +++ b/src/test/compile-fail/keyword-extern-as-identifier.rs @@ -11,5 +11,5 @@ #![feature(extern_in_paths)] fn main() { - let extern = 0; //~ ERROR expected unit struct/variant or constant, found module `extern` + let extern = 0; //~ ERROR cannot find unit struct/variant or constant `extern` in this scope } diff --git a/src/test/compile-fail/rfc-2126-extern-absolute-paths/single-segment.rs b/src/test/compile-fail/rfc-2126-extern-absolute-paths/single-segment.rs index e9de0f01b30d..69fc4b4f7f8f 100644 --- a/src/test/compile-fail/rfc-2126-extern-absolute-paths/single-segment.rs +++ b/src/test/compile-fail/rfc-2126-extern-absolute-paths/single-segment.rs @@ -11,10 +11,8 @@ // aux-build:xcrate.rs // edition:2018 -use crate; //~ ERROR unresolved import `crate` - //~^ NOTE crate root imports need to be explicitly named: `use crate as name;` -use *; //~ ERROR unresolved import `*` - //~^ NOTE cannot glob-import all possible crates +use crate; //~ ERROR crate root imports need to be explicitly named: `use crate as name;` +use *; //~ ERROR cannot glob-import all possible crates fn main() { let s = ::xcrate; //~ ERROR expected value, found module `xcrate` diff --git a/src/test/compile-fail/rfc-2126-extern-in-paths/single-segment.rs b/src/test/compile-fail/rfc-2126-extern-in-paths/single-segment.rs index ebc42aa9d449..017844a0252e 100644 --- a/src/test/compile-fail/rfc-2126-extern-in-paths/single-segment.rs +++ b/src/test/compile-fail/rfc-2126-extern-in-paths/single-segment.rs @@ -14,8 +14,7 @@ use extern; //~ ERROR unresolved import `extern` //~^ NOTE no `extern` in the root -use extern::*; //~ ERROR unresolved import `extern::*` - //~^ NOTE cannot glob-import all possible crates +use extern::*; //~ ERROR cannot glob-import all possible crates fn main() { let s = extern::xcrate; //~ ERROR expected value, found module `extern::xcrate` diff --git a/src/test/run-pass/issue-52140/auxiliary/some_crate.rs b/src/test/run-pass/issue-52140/auxiliary/some_crate.rs new file mode 100644 index 000000000000..bf8dee0863a1 --- /dev/null +++ b/src/test/run-pass/issue-52140/auxiliary/some_crate.rs @@ -0,0 +1,15 @@ +// Copyright 2018 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. + +#![crate_type = "lib"] + +pub fn hello() { + println!("Hello, world!"); +} diff --git a/src/test/run-pass/issue-52140/main.rs b/src/test/run-pass/issue-52140/main.rs new file mode 100644 index 000000000000..6fae6adc4424 --- /dev/null +++ b/src/test/run-pass/issue-52140/main.rs @@ -0,0 +1,21 @@ +// Copyright 2018 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. + +// aux-build:some_crate.rs +// edition:2018 + +mod foo { + pub use some_crate; +} + +fn main() { + ::some_crate::hello(); + foo::some_crate::hello(); +} diff --git a/src/test/run-pass/issue-52141/auxiliary/some_crate.rs b/src/test/run-pass/issue-52141/auxiliary/some_crate.rs new file mode 100644 index 000000000000..bf8dee0863a1 --- /dev/null +++ b/src/test/run-pass/issue-52141/auxiliary/some_crate.rs @@ -0,0 +1,15 @@ +// Copyright 2018 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. + +#![crate_type = "lib"] + +pub fn hello() { + println!("Hello, world!"); +} diff --git a/src/test/run-pass/issue-52141/main.rs b/src/test/run-pass/issue-52141/main.rs new file mode 100644 index 000000000000..8f3fc9f96989 --- /dev/null +++ b/src/test/run-pass/issue-52141/main.rs @@ -0,0 +1,24 @@ +// Copyright 2018 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. + +// aux-build:some_crate.rs +// edition:2018 + +use some_crate as some_name; + +mod foo { + pub use crate::some_name::*; +} + +fn main() { + ::some_crate::hello(); + some_name::hello(); + foo::hello(); +} diff --git a/src/test/run-pass/issue-52705/auxiliary/png.rs b/src/test/run-pass/issue-52705/auxiliary/png.rs new file mode 100644 index 000000000000..48d53a2cbac0 --- /dev/null +++ b/src/test/run-pass/issue-52705/auxiliary/png.rs @@ -0,0 +1,13 @@ +// Copyright 2018 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. + +#![crate_type = "lib"] + +pub struct DecodingError; diff --git a/src/test/run-pass/issue-52705/main.rs b/src/test/run-pass/issue-52705/main.rs new file mode 100644 index 000000000000..101f67e3e7b9 --- /dev/null +++ b/src/test/run-pass/issue-52705/main.rs @@ -0,0 +1,22 @@ +// Copyright 2018 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. + +// aux-build:png.rs +// edition:2018 + +mod png { + use png as png_ext; + + fn foo() -> png_ext::DecodingError { unimplemented!() } +} + +fn main() { + println!("Hello, world!"); +}