diff --git a/compiler/rustc_hir/src/def.rs b/compiler/rustc_hir/src/def.rs index 3959ee7f94128..76bab70e5c0df 100644 --- a/compiler/rustc_hir/src/def.rs +++ b/compiler/rustc_hir/src/def.rs @@ -590,6 +590,13 @@ pub enum Res { /// **Belongs to the type namespace.** ToolMod, + /// The resolution for an open module in a namespaced crate. E.g. `my_api` + /// in the namespaced crate `my_api::utils` when `my_api` isn't part of the + /// extern prelude. + /// + /// **Belongs to the type namespace.** + OpenMod(Symbol), + // Macro namespace /// An attribute that is *not* implemented via macro. /// E.g., `#[inline]` and `#[rustfmt::skip]`, which are essentially directives, @@ -838,6 +845,7 @@ impl Res { | Res::SelfTyAlias { .. } | Res::SelfCtor(..) | Res::ToolMod + | Res::OpenMod(..) | Res::NonMacroAttr(..) | Res::Err => None, } @@ -869,6 +877,7 @@ impl Res { Res::Local(..) => "local variable", Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } => "self type", Res::ToolMod => "tool module", + Res::OpenMod(..) => "namespaced crate", Res::NonMacroAttr(attr_kind) => attr_kind.descr(), Res::Err => "unresolved item", } @@ -895,6 +904,7 @@ impl Res { Res::SelfTyAlias { alias_to, is_trait_impl } } Res::ToolMod => Res::ToolMod, + Res::OpenMod(sym) => Res::OpenMod(sym), Res::NonMacroAttr(attr_kind) => Res::NonMacroAttr(attr_kind), Res::Err => Res::Err, } @@ -911,6 +921,7 @@ impl Res { Res::SelfTyAlias { alias_to, is_trait_impl } } Res::ToolMod => Res::ToolMod, + Res::OpenMod(sym) => Res::OpenMod(sym), Res::NonMacroAttr(attr_kind) => Res::NonMacroAttr(attr_kind), Res::Err => Res::Err, }) @@ -936,9 +947,11 @@ impl Res { pub fn ns(&self) -> Option { match self { Res::Def(kind, ..) => kind.ns(), - Res::PrimTy(..) | Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } | Res::ToolMod => { - Some(Namespace::TypeNS) - } + Res::PrimTy(..) + | Res::SelfTyParam { .. } + | Res::SelfTyAlias { .. } + | Res::ToolMod + | Res::OpenMod(..) => Some(Namespace::TypeNS), Res::SelfCtor(..) | Res::Local(..) => Some(Namespace::ValueNS), Res::NonMacroAttr(..) => Some(Namespace::MacroNS), Res::Err => None, diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index 8b1dad9a65471..c6829a941bbec 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -2786,6 +2786,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { | Res::SelfCtor(_) | Res::Local(_) | Res::ToolMod + | Res::OpenMod(..) | Res::NonMacroAttr(_) | Res::Err) => Const::new_error_with_message( tcx, diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index 15c91deef247d..30634c800e819 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -157,7 +157,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { Res::Def(_, def_id) => self.check_def_id(def_id), Res::SelfTyParam { trait_: t } => self.check_def_id(t), Res::SelfTyAlias { alias_to: i, .. } => self.check_def_id(i), - Res::ToolMod | Res::NonMacroAttr(..) | Res::Err => {} + Res::ToolMod | Res::NonMacroAttr(..) | Res::OpenMod(..) | Res::Err => {} } } diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index a280acc0d51df..af9680ac8888d 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -357,6 +357,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { | Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } | Res::SelfCtor(..) + | Res::OpenMod(..) | Res::Err => bug!("unexpected resolution: {:?}", res), } } diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index c776020c21274..fd5bf2da5fc6f 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -1,3 +1,4 @@ +// ignore-tidy-filelength use std::ops::ControlFlow; use itertools::Itertools as _; @@ -1735,8 +1736,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { Res::Def(DefKind::Macro(kinds), _) => { format!("{} {}", kinds.article(), kinds.descr()) } - Res::ToolMod => { - // Don't confuse the user with tool modules. + Res::ToolMod | Res::OpenMod(..) => { + // Don't confuse the user with tool modules or open modules. continue; } Res::Def(DefKind::Trait, _) if macro_kind == MacroKind::Derive => { @@ -1973,7 +1974,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let (built_in, from) = match scope { Scope::StdLibPrelude | Scope::MacroUsePrelude => ("", " from prelude"), Scope::ExternPreludeFlags - if self.tcx.sess.opts.externs.get(ident.as_str()).is_some() => + if self.tcx.sess.opts.externs.get(ident.as_str()).is_some() + || matches!(res, Res::OpenMod(..)) => { ("", " passed with `--extern`") } diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index 7cfd5b5f861a4..cd3f63304f02d 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -26,7 +26,7 @@ use crate::{ AmbiguityError, AmbiguityKind, AmbiguityWarning, BindingKey, CmResolver, Decl, DeclKind, Determinacy, Finalize, IdentKey, ImportKind, LateDecl, Module, ModuleKind, ModuleOrUniformRoot, ParentScope, PathResult, PrivacyError, Res, ResolutionError, Resolver, Scope, ScopeSet, - Segment, Stage, Used, errors, + Segment, Stage, Symbol, Used, errors, }; #[derive(Copy, Clone)] @@ -386,7 +386,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } /// Resolve an identifier in the specified set of scopes. - #[instrument(level = "debug", skip(self))] pub(crate) fn resolve_ident_in_scope_set<'r>( self: CmResolver<'r, 'ra, 'tcx>, orig_ident: Ident, @@ -976,6 +975,14 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ignore_import, ) } + ModuleOrUniformRoot::OpenModule(sym) => { + let open_ns_name = format!("{}::{}", sym.as_str(), ident.name); + let ns_ident = IdentKey::with_root_ctxt(Symbol::intern(&open_ns_name)); + match self.extern_prelude_get_flag(ns_ident, ident.span, finalize.is_some()) { + Some(decl) => Ok(decl), + None => Err(Determinacy::Determined), + } + } ModuleOrUniformRoot::ModuleAndExternPrelude(module) => self.resolve_ident_in_scope_set( ident, ScopeSet::ModuleAndExternPrelude(ns, module), @@ -1962,7 +1969,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } let maybe_assoc = opt_ns != Some(MacroNS) && PathSource::Type.is_expected(res); - if let Some(def_id) = binding.res().module_like_def_id() { + if let Res::OpenMod(sym) = binding.res() { + module = Some(ModuleOrUniformRoot::OpenModule(sym)); + record_segment_res(self.reborrow(), finalize, res, id); + } else if let Some(def_id) = binding.res().module_like_def_id() { if self.mods_with_parse_errors.contains(&def_id) { module_had_parse_errors = true; } diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 7696b4b220d6c..8f534de0f76dd 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -41,7 +41,7 @@ type Res = def::Res; /// A potential import declaration in the process of being planted into a module. /// Also used for lazily planting names from `--extern` flags to extern prelude. -#[derive(Clone, Copy, Default, PartialEq)] +#[derive(Clone, Copy, Default, PartialEq, Debug)] pub(crate) enum PendingDecl<'ra> { Ready(Option>), #[default] diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 6b3b5e2ec45f0..9aa96ce27e084 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -64,6 +64,7 @@ use rustc_hir::definitions::DisambiguatorState; use rustc_hir::{PrimTy, TraitCandidate, find_attr}; use rustc_index::bit_set::DenseBitSet; use rustc_metadata::creader::CStore; +use rustc_middle::bug; use rustc_middle::metadata::{AmbigModChild, ModChild, Reexport}; use rustc_middle::middle::privacy::EffectiveVisibilities; use rustc_middle::query::Providers; @@ -448,6 +449,11 @@ enum ModuleOrUniformRoot<'ra> { /// Used only for resolving single-segment imports. The reason it exists is that import paths /// are always split into two parts, the first of which should be some kind of module. CurrentScope, + + /// Virtual module for the resolution of base names of namespaced crates, + /// where the base name doesn't correspond to a module in the extern prelude. + /// E.g. `my_api::utils` is in the prelude, but `my_api` is not. + OpenModule(Symbol), } #[derive(Debug)] @@ -1108,13 +1114,20 @@ impl<'ra> DeclData<'ra> { } } +#[derive(Debug)] struct ExternPreludeEntry<'ra> { /// Name declaration from an `extern crate` item. /// The boolean flag is true is `item_decl` is non-redundant, happens either when /// `flag_decl` is `None`, or when `extern crate` introducing `item_decl` used renaming. item_decl: Option<(Decl<'ra>, Span, /* introduced by item */ bool)>, /// Name declaration from an `--extern` flag, lazily populated on first use. - flag_decl: Option, /* finalized */ bool)>>, + flag_decl: Option< + CacheCell<( + PendingDecl<'ra>, + /* finalized */ bool, + /* open flag (namespaced crate) */ bool, + )>, + >, } impl ExternPreludeEntry<'_> { @@ -1125,7 +1138,14 @@ impl ExternPreludeEntry<'_> { fn flag() -> Self { ExternPreludeEntry { item_decl: None, - flag_decl: Some(CacheCell::new((PendingDecl::Pending, false))), + flag_decl: Some(CacheCell::new((PendingDecl::Pending, false, false))), + } + } + + fn open_flag() -> Self { + ExternPreludeEntry { + item_decl: None, + flag_decl: Some(CacheCell::new((PendingDecl::Pending, false, true))), } } @@ -1637,35 +1657,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let mut invocation_parents = FxHashMap::default(); invocation_parents.insert(LocalExpnId::ROOT, InvocationParent::ROOT); - let mut extern_prelude: FxIndexMap<_, _> = tcx - .sess - .opts - .externs - .iter() - .filter_map(|(name, entry)| { - // Make sure `self`, `super`, `_` etc do not get into extern prelude. - // FIXME: reject `--extern self` and similar in option parsing instead. - if entry.add_prelude - && let name = Symbol::intern(name) - && name.can_be_raw() - { - let ident = IdentKey::with_root_ctxt(name); - Some((ident, ExternPreludeEntry::flag())) - } else { - None - } - }) - .collect(); - - if !attr::contains_name(attrs, sym::no_core) { - let ident = IdentKey::with_root_ctxt(sym::core); - extern_prelude.insert(ident, ExternPreludeEntry::flag()); - if !attr::contains_name(attrs, sym::no_std) { - let ident = IdentKey::with_root_ctxt(sym::std); - extern_prelude.insert(ident, ExternPreludeEntry::flag()); - } - } - + let extern_prelude = build_extern_prelude(tcx, attrs); let registered_tools = tcx.registered_tools(()); let edition = tcx.sess.edition(); @@ -2320,10 +2312,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ) -> Option> { let entry = self.extern_prelude.get(&ident); entry.and_then(|entry| entry.flag_decl.as_ref()).and_then(|flag_decl| { - let (pending_decl, finalized) = flag_decl.get(); + let (pending_decl, finalized, is_open) = flag_decl.get(); let decl = match pending_decl { PendingDecl::Ready(decl) => { - if finalize && !finalized { + if finalize && !finalized && !is_open { self.cstore_mut().process_path_extern( self.tcx, ident.name, @@ -2334,18 +2326,28 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } PendingDecl::Pending => { debug_assert!(!finalized); - let crate_id = if finalize { - self.cstore_mut().process_path_extern(self.tcx, ident.name, orig_ident_span) + if is_open { + let res = Res::OpenMod(ident.name); + Some(self.arenas.new_pub_def_decl(res, DUMMY_SP, LocalExpnId::ROOT)) } else { - self.cstore_mut().maybe_process_path_extern(self.tcx, ident.name) - }; - crate_id.map(|crate_id| { - let res = Res::Def(DefKind::Mod, crate_id.as_def_id()); - self.arenas.new_pub_def_decl(res, DUMMY_SP, LocalExpnId::ROOT) - }) + let crate_id = if finalize { + self.cstore_mut().process_path_extern( + self.tcx, + ident.name, + orig_ident_span, + ) + } else { + self.cstore_mut().maybe_process_path_extern(self.tcx, ident.name) + }; + crate_id.map(|crate_id| { + let def_id = crate_id.as_def_id(); + let res = Res::Def(DefKind::Mod, def_id); + self.arenas.new_pub_def_decl(res, DUMMY_SP, LocalExpnId::ROOT) + }) + } } }; - flag_decl.set((PendingDecl::Ready(decl), finalize || finalized)); + flag_decl.set((PendingDecl::Ready(decl), finalize || finalized, is_open)); decl.or_else(|| finalize.then_some(self.dummy_decl)) }) } @@ -2387,7 +2389,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { PathResult::Module(ModuleOrUniformRoot::ExternPrelude) | PathResult::Failed { .. } => { None } - PathResult::Module(..) | PathResult::Indeterminate => unreachable!(), + path_result @ (PathResult::Module(..) | PathResult::Indeterminate) => { + bug!("got invalid path_result: {path_result:?}") + } } } @@ -2505,6 +2509,60 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } } +fn build_extern_prelude<'tcx, 'ra>( + tcx: TyCtxt<'tcx>, + attrs: &[ast::Attribute], +) -> FxIndexMap> { + let mut extern_prelude: FxIndexMap> = tcx + .sess + .opts + .externs + .iter() + .filter_map(|(name, entry)| { + // Make sure `self`, `super`, `_` etc do not get into extern prelude. + // FIXME: reject `--extern self` and similar in option parsing instead. + if entry.add_prelude + && let sym = Symbol::intern(name) + && sym.can_be_raw() + { + Some((IdentKey::with_root_ctxt(sym), ExternPreludeEntry::flag())) + } else { + None + } + }) + .collect(); + + // Add open base entries for namespaced crates whose base segment + // is missing from the prelude (e.g. `foo::bar` without `foo`). + // These are necessary in order to resolve the open modules, whereas + // the namespaced names are necessary in `extern_prelude` for actually + // resolving the namespaced crates. + let missing_open_bases: Vec = extern_prelude + .keys() + .filter_map(|ident| { + let (base, _) = ident.name.as_str().split_once("::")?; + let base_sym = Symbol::intern(base); + base_sym.can_be_raw().then(|| IdentKey::with_root_ctxt(base_sym)) + }) + .filter(|base_ident| !extern_prelude.contains_key(base_ident)) + .collect(); + + extern_prelude.extend( + missing_open_bases.into_iter().map(|ident| (ident, ExternPreludeEntry::open_flag())), + ); + + // Inject `core` / `std` unless suppressed by attributes. + if !attr::contains_name(attrs, sym::no_core) { + extern_prelude.insert(IdentKey::with_root_ctxt(sym::core), ExternPreludeEntry::flag()); + + if !attr::contains_name(attrs, sym::no_std) { + extern_prelude.insert(IdentKey::with_root_ctxt(sym::std), ExternPreludeEntry::flag()); + } + } + + extern_prelude +} + fn names_to_string(names: impl Iterator) -> String { let mut result = String::new(); for (i, name) in names.enumerate().filter(|(_, name)| *name != kw::PathRoot) { diff --git a/compiler/rustc_session/src/config/externs.rs b/compiler/rustc_session/src/config/externs.rs index d668d8b4203db..ff76eaaeaf4fc 100644 --- a/compiler/rustc_session/src/config/externs.rs +++ b/compiler/rustc_session/src/config/externs.rs @@ -43,6 +43,13 @@ pub(crate) fn split_extern_opt<'a>( } }; + // Reject paths with more than two segments. + if unstable_opts.namespaced_crates && crate_name.split("::").count() > 2 { + return Err(early_dcx.early_struct_fatal(format!( + "crate name `{crate_name}` passed to `--extern` can have at most two segments." + ))); + } + if !valid_crate_name(&crate_name, unstable_opts) { let mut error = early_dcx.early_struct_fatal(format!( "crate name `{crate_name}` passed to `--extern` is not a valid ASCII identifier" diff --git a/tests/ui/resolve/auxiliary/open-ns-mod-my_api.rs b/tests/ui/resolve/auxiliary/open-ns-mod-my_api.rs new file mode 100644 index 0000000000000..dc8b5720c0c10 --- /dev/null +++ b/tests/ui/resolve/auxiliary/open-ns-mod-my_api.rs @@ -0,0 +1,9 @@ +pub mod utils { + pub fn root_helper() { + println!("root_helper"); + } +} + +pub fn root_function() -> String { + "my_api root!".to_string() +} diff --git a/tests/ui/resolve/auxiliary/open-ns-my_api.rs b/tests/ui/resolve/auxiliary/open-ns-my_api.rs new file mode 100644 index 0000000000000..be4bf31f0fbcd --- /dev/null +++ b/tests/ui/resolve/auxiliary/open-ns-my_api.rs @@ -0,0 +1,3 @@ +pub fn root_function() -> String { + "my_api root!".to_string() +} diff --git a/tests/ui/resolve/auxiliary/open-ns-my_api_core.rs b/tests/ui/resolve/auxiliary/open-ns-my_api_core.rs new file mode 100644 index 0000000000000..41418f1516f60 --- /dev/null +++ b/tests/ui/resolve/auxiliary/open-ns-my_api_core.rs @@ -0,0 +1,15 @@ +// #![crate_name = "my_api::core"] + +pub mod util { + pub fn core_mod_fn() -> String { + format!("core_fn from my_api::core::util",) + } +} + +pub fn core_fn() -> String { + format!("core_fn from my_api::core!",) +} + +pub fn core_fn2() -> String { + format!("core_fn2 from my_api::core!",) +} diff --git a/tests/ui/resolve/auxiliary/open-ns-my_api_utils.rs b/tests/ui/resolve/auxiliary/open-ns-my_api_utils.rs new file mode 100644 index 0000000000000..d2af20728bd5e --- /dev/null +++ b/tests/ui/resolve/auxiliary/open-ns-my_api_utils.rs @@ -0,0 +1,13 @@ +pub mod util { + pub fn util_mod_helper() -> String { + format!("Helper from my_api::utils::util",) + } +} + +pub fn utils_helper() -> String { + format!("Helper from my_api::utils!",) +} + +pub fn get_u32() -> u32 { + 1 +} diff --git a/tests/ui/resolve/open-ns-1.rs b/tests/ui/resolve/open-ns-1.rs new file mode 100644 index 0000000000000..e77ddbe58122d --- /dev/null +++ b/tests/ui/resolve/open-ns-1.rs @@ -0,0 +1,19 @@ +//@ aux-crate:my_api=open-ns-my_api.rs +//@ aux-crate:my_api::utils=open-ns-my_api_utils.rs +//@ aux-crate:my_api::core=open-ns-my_api_core.rs +//@ compile-flags: -Z namespaced-crates +//@ edition: 2024 + +use my_api::root_function; +use my_api::utils::util; +//~^ ERROR unresolved import `my_api::utils` + +fn main() { + let _ = root_function(); + let _ = my_api::root_function(); + let _ = my_api::utils::utils_helper(); + //~^ ERROR cannot find `utils` in `my_api` [E0433] + let _ = util::util_mod_helper(); + let _ = my_api::core::core_fn(); + //~^ ERROR cannot find `core` in `my_api` [E0433] +} diff --git a/tests/ui/resolve/open-ns-1.stderr b/tests/ui/resolve/open-ns-1.stderr new file mode 100644 index 0000000000000..65b9c6a355ce0 --- /dev/null +++ b/tests/ui/resolve/open-ns-1.stderr @@ -0,0 +1,22 @@ +error[E0432]: unresolved import `my_api::utils` + --> $DIR/open-ns-1.rs:8:13 + | +LL | use my_api::utils::util; + | ^^^^^ could not find `utils` in `my_api` + +error[E0433]: cannot find `utils` in `my_api` + --> $DIR/open-ns-1.rs:14:21 + | +LL | let _ = my_api::utils::utils_helper(); + | ^^^^^ could not find `utils` in `my_api` + +error[E0433]: cannot find `core` in `my_api` + --> $DIR/open-ns-1.rs:17:21 + | +LL | let _ = my_api::core::core_fn(); + | ^^^^ could not find `core` in `my_api` + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0432, E0433. +For more information about an error, try `rustc --explain E0432`. diff --git a/tests/ui/resolve/open-ns-10.rs b/tests/ui/resolve/open-ns-10.rs new file mode 100644 index 0000000000000..b05a0ab270df0 --- /dev/null +++ b/tests/ui/resolve/open-ns-10.rs @@ -0,0 +1,8 @@ +// Tests that namespaced crate names are limited to two segments + +//@ aux-crate: nscrate::three::segments=open-ns-my_api_utils.rs +//@ compile-flags: -Z namespaced-crates +//@ edition: 2024 +//~? ERROR crate name `nscrate::three::segments` passed to `--extern` can have at most two segments. + +fn main() {} diff --git a/tests/ui/resolve/open-ns-10.stderr b/tests/ui/resolve/open-ns-10.stderr new file mode 100644 index 0000000000000..fdef748c6fa7d --- /dev/null +++ b/tests/ui/resolve/open-ns-10.stderr @@ -0,0 +1,2 @@ +error: crate name `nscrate::three::segments` passed to `--extern` can have at most two segments. + diff --git a/tests/ui/resolve/open-ns-11.rs b/tests/ui/resolve/open-ns-11.rs new file mode 100644 index 0000000000000..90e85a9ffc043 --- /dev/null +++ b/tests/ui/resolve/open-ns-11.rs @@ -0,0 +1,12 @@ +// Tests that std has higher precedence than an open module with the same name. + +//@ aux-crate: std::utils=open-ns-my_api_utils.rs +//@ compile-flags: -Z namespaced-crates +//@ edition: 2024 + +use std::utils::get_u32; +//~^ ERROR unresolved import `std::utils` + +fn main() { + let _ = get_u32(); +} diff --git a/tests/ui/resolve/open-ns-11.stderr b/tests/ui/resolve/open-ns-11.stderr new file mode 100644 index 0000000000000..cb073bc985a9e --- /dev/null +++ b/tests/ui/resolve/open-ns-11.stderr @@ -0,0 +1,9 @@ +error[E0432]: unresolved import `std::utils` + --> $DIR/open-ns-11.rs:7:10 + | +LL | use std::utils::get_u32; + | ^^^^^ could not find `utils` in `std` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0432`. diff --git a/tests/ui/resolve/open-ns-2.rs b/tests/ui/resolve/open-ns-2.rs new file mode 100644 index 0000000000000..6165a4102be07 --- /dev/null +++ b/tests/ui/resolve/open-ns-2.rs @@ -0,0 +1,18 @@ +//@ aux-crate: my_api=open-ns-my_api.rs +//@ aux-crate: my_api::utils=open-ns-my_api_utils.rs +//@ aux-crate: my_api::core=open-ns-my_api_core.rs +//@ compile-flags: -Z namespaced-crates +//@ edition: 2024 + +use my_api::core::{core_fn, core_fn2}; +//~^ ERROR unresolved import `my_api::core` [E0432] +use my_api::utils::*; +//~^ ERROR unresolved import `my_api::utils` [E0432] +use my_api::*; + +fn main() { + let _ = root_function(); + let _ = utils_helper(); + let _ = core_fn(); + let _ = core_fn2(); +} diff --git a/tests/ui/resolve/open-ns-2.stderr b/tests/ui/resolve/open-ns-2.stderr new file mode 100644 index 0000000000000..0e221234c5179 --- /dev/null +++ b/tests/ui/resolve/open-ns-2.stderr @@ -0,0 +1,15 @@ +error[E0432]: unresolved import `my_api::core` + --> $DIR/open-ns-2.rs:7:13 + | +LL | use my_api::core::{core_fn, core_fn2}; + | ^^^^ could not find `core` in `my_api` + +error[E0432]: unresolved import `my_api::utils` + --> $DIR/open-ns-2.rs:9:13 + | +LL | use my_api::utils::*; + | ^^^^^ could not find `utils` in `my_api` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0432`. diff --git a/tests/ui/resolve/open-ns-3.rs b/tests/ui/resolve/open-ns-3.rs new file mode 100644 index 0000000000000..9c78999fe3687 --- /dev/null +++ b/tests/ui/resolve/open-ns-3.rs @@ -0,0 +1,14 @@ +// This test should fail with `utils_helper` being unresolvable in `my_api::utils`. +// If a crate contains a module that overlaps with a namespaced crate name, then +// the namespaced crate will not be used in name resolution. + +//@ aux-crate: my_api::utils=open-ns-my_api_utils.rs +//@ aux-crate: my_api=open-ns-mod-my_api.rs +//@ compile-flags: -Z namespaced-crates +//@ edition: 2024 + +fn main() { + let _ = my_api::utils::root_helper(); + let _ = my_api::utils::utils_helper(); + //~^ ERROR cannot find function `utils_helper` in module `my_api::utils` [E0425] +} diff --git a/tests/ui/resolve/open-ns-3.stderr b/tests/ui/resolve/open-ns-3.stderr new file mode 100644 index 0000000000000..8ae261af01429 --- /dev/null +++ b/tests/ui/resolve/open-ns-3.stderr @@ -0,0 +1,19 @@ +error[E0425]: cannot find function `utils_helper` in module `my_api::utils` + --> $DIR/open-ns-3.rs:12:28 + | +LL | let _ = my_api::utils::utils_helper(); + | ^^^^^^^^^^^^ not found in `my_api::utils` + | +help: consider importing this function + | +LL + use my_api::utils::utils_helper; + | +help: if you import `utils_helper`, refer to it directly + | +LL - let _ = my_api::utils::utils_helper(); +LL + let _ = utils_helper(); + | + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/resolve/open-ns-4.rs b/tests/ui/resolve/open-ns-4.rs new file mode 100644 index 0000000000000..4db3ad4c80a1d --- /dev/null +++ b/tests/ui/resolve/open-ns-4.rs @@ -0,0 +1,12 @@ +// This tests that namespaced crates are shadowed. + +//@ aux-crate: my_api=open-ns-my_api.rs +//@ aux-crate: my_api::utils=open-ns-my_api_utils.rs +//@ compile-flags: -Z namespaced-crates +//@ edition: 2024 + +fn main() { + let _ = my_api::root_function(); + let _ = my_api::utils::utils_helper(); + //~^ ERROR cannot find `utils` in `my_api` [E0433] +} diff --git a/tests/ui/resolve/open-ns-4.stderr b/tests/ui/resolve/open-ns-4.stderr new file mode 100644 index 0000000000000..2e6872c57986f --- /dev/null +++ b/tests/ui/resolve/open-ns-4.stderr @@ -0,0 +1,9 @@ +error[E0433]: cannot find `utils` in `my_api` + --> $DIR/open-ns-4.rs:10:21 + | +LL | let _ = my_api::utils::utils_helper(); + | ^^^^^ could not find `utils` in `my_api` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0433`. diff --git a/tests/ui/resolve/open-ns-5.rs b/tests/ui/resolve/open-ns-5.rs new file mode 100644 index 0000000000000..8776da3106cf8 --- /dev/null +++ b/tests/ui/resolve/open-ns-5.rs @@ -0,0 +1,18 @@ +// Tests that namespaced crate names work inside macros. + +//@ aux-crate: my_api::utils=open-ns-my_api_utils.rs +//@ compile-flags: -Z namespaced-crates +//@ edition: 2024 +//@ check-pass + +macro_rules! import_and_call { + ($import_path:path, $fn_name:ident) => {{ + use $import_path; + $fn_name(); + }}; +} + +fn main() { + import_and_call!(my_api::utils::utils_helper, utils_helper); + let _x = 4 + 5; +} diff --git a/tests/ui/resolve/open-ns-6.rs b/tests/ui/resolve/open-ns-6.rs new file mode 100644 index 0000000000000..856858aac43a5 --- /dev/null +++ b/tests/ui/resolve/open-ns-6.rs @@ -0,0 +1,13 @@ +// Tests that open modules are resolvable. + +//@ aux-crate: my_api::utils=open-ns-my_api_utils.rs +//@ compile-flags: -Z namespaced-crates +//@ edition: 2024 +//@ check-pass + +use my_api; +use my_api::utils::utils_helper; + +fn main() { + let _ = utils_helper(); +} diff --git a/tests/ui/resolve/open-ns-7.rs b/tests/ui/resolve/open-ns-7.rs new file mode 100644 index 0000000000000..cf16c594fa40b --- /dev/null +++ b/tests/ui/resolve/open-ns-7.rs @@ -0,0 +1,14 @@ +// Tests that namespaced crates cannot be resolved if shadowed. + +//@ aux-crate: my_api=open-ns-my_api.rs +//@ aux-crate: my_api::utils=open-ns-my_api_utils.rs +//@ compile-flags: -Z namespaced-crates +//@ edition: 2024 + +use my_api::utils::utils_helper; +//~^ ERROR unresolved import `my_api::utils` [E0432] + +fn main() { + let _ = my_api::utils::utils_helper(); + //~^ ERROR cannot find `utils` in `my_api` [E0433] +} diff --git a/tests/ui/resolve/open-ns-7.stderr b/tests/ui/resolve/open-ns-7.stderr new file mode 100644 index 0000000000000..b008547539831 --- /dev/null +++ b/tests/ui/resolve/open-ns-7.stderr @@ -0,0 +1,16 @@ +error[E0432]: unresolved import `my_api::utils` + --> $DIR/open-ns-7.rs:8:13 + | +LL | use my_api::utils::utils_helper; + | ^^^^^ could not find `utils` in `my_api` + +error[E0433]: cannot find `utils` in `my_api` + --> $DIR/open-ns-7.rs:12:21 + | +LL | let _ = my_api::utils::utils_helper(); + | ^^^^^ could not find `utils` in `my_api` + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0432, E0433. +For more information about an error, try `rustc --explain E0432`. diff --git a/tests/ui/resolve/open-ns-8.rs b/tests/ui/resolve/open-ns-8.rs new file mode 100644 index 0000000000000..46aafb66e63a6 --- /dev/null +++ b/tests/ui/resolve/open-ns-8.rs @@ -0,0 +1,23 @@ +// Tests that a macro-generated item has higher precendence than a namespaced crate +//@ aux-crate: my_api::utils=open-ns-my_api_utils.rs +//@ compile-flags: -Z namespaced-crates +//@ edition: 2024 +//@ check-pass + +macro_rules! define { + () => { + pub mod my_api { + pub mod utils { + pub fn get_u32() -> u32 { + 2 + } + } + } + }; +} + +fn main() { + define!(); + let res = my_api::utils::get_u32(); + assert_eq!(res, 2); +} diff --git a/tests/ui/resolve/open-ns-9.rs b/tests/ui/resolve/open-ns-9.rs new file mode 100644 index 0000000000000..7ded0b383d8d4 --- /dev/null +++ b/tests/ui/resolve/open-ns-9.rs @@ -0,0 +1,25 @@ +//@ aux-crate: my_api::utils=open-ns-my_api_utils.rs +//@ compile-flags: -Z namespaced-crates +//@ edition: 2024 + +use my_api::utils::get_u32; +//~^ ERROR `my_api` is ambiguous [E0659] + +macro_rules! define { + () => { + pub mod my_api { + pub mod utils { + pub fn get_u32() -> u32 { + 2 + } + } + } + }; +} + +define!(); + +fn main() { + let val = get_u32(); + assert_eq!(val, 2); +} diff --git a/tests/ui/resolve/open-ns-9.stderr b/tests/ui/resolve/open-ns-9.stderr new file mode 100644 index 0000000000000..675f487823e55 --- /dev/null +++ b/tests/ui/resolve/open-ns-9.stderr @@ -0,0 +1,27 @@ +error[E0659]: `my_api` is ambiguous + --> $DIR/open-ns-9.rs:5:5 + | +LL | use my_api::utils::get_u32; + | ^^^^^^ ambiguous name + | + = note: ambiguous because of a conflict between a macro-expanded name and a less macro-expanded name from outer scope during import or macro resolution + = note: `my_api` could refer to a namespaced crate passed with `--extern` +note: `my_api` could also refer to the module defined here + --> $DIR/open-ns-9.rs:10:9 + | +LL | / pub mod my_api { +LL | | pub mod utils { +LL | | pub fn get_u32() -> u32 { +LL | | 2 +... | +LL | | } + | |_________^ +... +LL | define!(); + | --------- in this macro invocation + = help: use `crate::my_api` to refer to this module unambiguously + = note: this error originates in the macro `define` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0659`.