2019-08-13 02:46:42 +03:00
|
|
|
//! A bunch of methods and structures more or less related to resolving imports.
|
|
|
|
|
2022-12-27 05:09:33 +00:00
|
|
|
use crate::diagnostics::{import_candidates, DiagnosticMode, Suggestion};
|
2019-12-24 17:38:22 -05:00
|
|
|
use crate::Determinacy::{self, *};
|
2022-10-19 17:56:41 +04:00
|
|
|
use crate::Namespace::*;
|
2022-10-10 11:14:32 +08:00
|
|
|
use crate::{module_to_string, names_to_string, ImportSuggestion};
|
2022-12-03 21:18:37 +08:00
|
|
|
use crate::{
|
|
|
|
AmbiguityError, AmbiguityErrorMisc, AmbiguityKind, BindingKey, ModuleKind, ResolutionError,
|
|
|
|
Resolver, Segment,
|
|
|
|
};
|
2022-03-26 20:59:09 +01:00
|
|
|
use crate::{Finalize, Module, ModuleOrUniformRoot, ParentScope, PerNS, ScopeSet};
|
|
|
|
use crate::{NameBinding, NameBindingKind, PathResult};
|
2015-03-16 10:44:19 +13:00
|
|
|
|
2020-04-27 23:26:11 +05:30
|
|
|
use rustc_ast::NodeId;
|
2019-12-24 05:02:53 +01:00
|
|
|
use rustc_data_structures::fx::FxHashSet;
|
2022-02-04 14:26:29 +11:00
|
|
|
use rustc_data_structures::intern::Interned;
|
2022-03-24 02:03:04 +00:00
|
|
|
use rustc_errors::{pluralize, struct_span_err, Applicability, MultiSpan};
|
2022-06-14 14:58:46 +09:00
|
|
|
use rustc_hir::def::{self, DefKind, PartialRes};
|
2021-12-21 11:24:43 +08:00
|
|
|
use rustc_middle::metadata::ModChild;
|
2021-01-06 18:07:47 +03:00
|
|
|
use rustc_middle::span_bug;
|
2020-03-29 17:19:48 +02:00
|
|
|
use rustc_middle::ty;
|
2020-03-11 12:49:08 +01:00
|
|
|
use rustc_session::lint::builtin::{PUB_USE_OF_PRIVATE_EXTERN_CRATE, UNUSED_IMPORTS};
|
2020-01-05 13:05:49 +01:00
|
|
|
use rustc_session::lint::BuiltinLintDiagnostics;
|
2021-06-25 20:43:04 +02:00
|
|
|
use rustc_span::hygiene::LocalExpnId;
|
Move lev_distance to rustc_ast, make non-generic
rustc_ast currently has a few dependencies on rustc_lexer. Ideally, an AST
would not have any dependency its lexer, for minimizing unnecessarily
design-time dependencies. Breaking this dependency would also have practical
benefits, since modifying rustc_lexer would not trigger a rebuild of rustc_ast.
This commit does not remove the rustc_ast --> rustc_lexer dependency,
but it does remove one of the sources of this dependency, which is the
code that handles fuzzy matching between symbol names for making suggestions
in diagnostics. Since that code depends only on Symbol, it is easy to move
it to rustc_span. It might even be best to move it to a separate crate,
since other tools such as Cargo use the same algorithm, and have simply
contain a duplicate of the code.
This changes the signature of find_best_match_for_name so that it is no
longer generic over its input. I checked the optimized binaries, and this
function was duplicated at nearly every call site, because most call sites
used short-lived iterator chains, generic over Map and such. But there's
no good reason for a function like this to be generic, since all it does
is immediately convert the generic input (the Iterator impl) to a concrete
Vec<Symbol>. This has all of the costs of generics (duplicated method bodies)
with no benefit.
Changing find_best_match_for_name to be non-generic removed about 10KB of
code from the optimized binary. I know it's a drop in the bucket, but we have
to start reducing binary size, and beginning to tame over-use of generics
is part of that.
2020-11-12 11:24:10 -08:00
|
|
|
use rustc_span::lev_distance::find_best_match_for_name;
|
2020-04-19 13:00:18 +02:00
|
|
|
use rustc_span::symbol::{kw, Ident, Symbol};
|
2022-03-24 02:03:04 +00:00
|
|
|
use rustc_span::Span;
|
2015-03-16 10:44:19 +13:00
|
|
|
|
2019-08-16 01:18:14 +03:00
|
|
|
use std::cell::Cell;
|
2018-07-18 21:53:54 +03:00
|
|
|
use std::{mem, ptr};
|
2015-03-16 10:44:19 +13:00
|
|
|
|
2019-04-20 19:36:05 +03:00
|
|
|
type Res = def::Res<NodeId>;
|
2019-04-03 09:07:45 +02:00
|
|
|
|
2020-03-07 19:02:32 +03:00
|
|
|
/// Contains data for specific kinds of imports.
|
2022-08-15 18:29:43 +02:00
|
|
|
#[derive(Clone)]
|
2020-03-07 18:49:13 +03:00
|
|
|
pub enum ImportKind<'a> {
|
|
|
|
Single {
|
2018-12-01 22:14:37 +03:00
|
|
|
/// `source` in `use prefix::source as target`.
|
2016-11-29 02:07:12 +00:00
|
|
|
source: Ident,
|
2018-12-01 22:14:37 +03:00
|
|
|
/// `target` in `use prefix::source as target`.
|
2018-11-30 21:16:21 +03:00
|
|
|
target: Ident,
|
2018-12-01 22:14:37 +03:00
|
|
|
/// Bindings to which `source` refers to.
|
2018-11-30 21:16:21 +03:00
|
|
|
source_bindings: PerNS<Cell<Result<&'a NameBinding<'a>, Determinacy>>>,
|
2018-12-01 22:14:37 +03:00
|
|
|
/// Bindings introduced by `target`.
|
2018-11-30 21:16:21 +03:00
|
|
|
target_bindings: PerNS<Cell<Option<&'a NameBinding<'a>>>>,
|
2018-12-01 22:14:37 +03:00
|
|
|
/// `true` for `...::{self [as target]}` imports, `false` otherwise.
|
2016-12-12 03:35:48 +00:00
|
|
|
type_ns_only: bool,
|
2019-01-29 13:34:40 +01:00
|
|
|
/// Did this import result from a nested import? ie. `use foo::{bar, baz};`
|
|
|
|
nested: bool,
|
2022-10-30 13:35:31 +04:00
|
|
|
/// The ID of the `UseTree` that imported this `Import`.
|
|
|
|
///
|
|
|
|
/// In the case where the `Import` was expanded from a "nested" use tree,
|
|
|
|
/// this id is the ID of the leaf tree. For example:
|
|
|
|
///
|
|
|
|
/// ```ignore (pacify the merciless tidy)
|
|
|
|
/// use foo::bar::{a, b}
|
|
|
|
/// ```
|
|
|
|
///
|
|
|
|
/// If this is the import for `foo::bar::a`, we would have the ID of the `UseTree`
|
|
|
|
/// for `a` in this field.
|
|
|
|
id: NodeId,
|
2016-02-13 21:49:16 +00:00
|
|
|
},
|
2020-03-07 18:49:13 +03:00
|
|
|
Glob {
|
2016-08-20 00:23:32 +00:00
|
|
|
is_prelude: bool,
|
2022-10-30 13:35:31 +04:00
|
|
|
// The visibility of the greatest re-export.
|
|
|
|
// n.b. `max_vis` is only used in `finalize_import` to check for re-export errors.
|
|
|
|
max_vis: Cell<Option<ty::Visibility>>,
|
|
|
|
id: NodeId,
|
2016-08-20 00:23:32 +00:00
|
|
|
},
|
2018-10-21 00:23:29 +02:00
|
|
|
ExternCrate {
|
2020-04-19 13:00:18 +02:00
|
|
|
source: Option<Symbol>,
|
2018-10-21 00:23:29 +02:00
|
|
|
target: Ident,
|
2022-10-30 13:35:31 +04:00
|
|
|
id: NodeId,
|
2018-10-21 00:23:29 +02:00
|
|
|
},
|
2017-01-14 08:58:50 +00:00
|
|
|
MacroUse,
|
2022-10-30 15:55:58 +04:00
|
|
|
MacroExport,
|
2015-03-16 10:44:19 +13:00
|
|
|
}
|
|
|
|
|
2022-08-15 18:29:43 +02:00
|
|
|
/// Manually implement `Debug` for `ImportKind` because the `source/target_bindings`
|
|
|
|
/// contain `Cell`s which can introduce infinite loops while printing.
|
|
|
|
impl<'a> std::fmt::Debug for ImportKind<'a> {
|
|
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
|
|
use ImportKind::*;
|
|
|
|
match self {
|
|
|
|
Single {
|
|
|
|
ref source,
|
|
|
|
ref target,
|
|
|
|
ref type_ns_only,
|
|
|
|
ref nested,
|
2022-10-30 13:35:31 +04:00
|
|
|
ref id,
|
2022-08-15 18:29:43 +02:00
|
|
|
// Ignore the following to avoid an infinite loop while printing.
|
|
|
|
source_bindings: _,
|
|
|
|
target_bindings: _,
|
|
|
|
} => f
|
|
|
|
.debug_struct("Single")
|
|
|
|
.field("source", source)
|
|
|
|
.field("target", target)
|
|
|
|
.field("type_ns_only", type_ns_only)
|
|
|
|
.field("nested", nested)
|
2022-10-30 13:35:31 +04:00
|
|
|
.field("id", id)
|
2022-08-15 20:51:32 +02:00
|
|
|
.finish_non_exhaustive(),
|
2022-10-30 13:35:31 +04:00
|
|
|
Glob { ref is_prelude, ref max_vis, ref id } => f
|
2022-08-15 18:29:43 +02:00
|
|
|
.debug_struct("Glob")
|
|
|
|
.field("is_prelude", is_prelude)
|
|
|
|
.field("max_vis", max_vis)
|
2022-10-30 13:35:31 +04:00
|
|
|
.field("id", id)
|
2022-08-15 18:29:43 +02:00
|
|
|
.finish(),
|
2022-10-30 13:35:31 +04:00
|
|
|
ExternCrate { ref source, ref target, ref id } => f
|
2022-08-15 18:29:43 +02:00
|
|
|
.debug_struct("ExternCrate")
|
|
|
|
.field("source", source)
|
|
|
|
.field("target", target)
|
2022-10-30 13:35:31 +04:00
|
|
|
.field("id", id)
|
2022-08-15 18:29:43 +02:00
|
|
|
.finish(),
|
|
|
|
MacroUse => f.debug_struct("MacroUse").finish(),
|
2022-10-30 15:55:58 +04:00
|
|
|
MacroExport => f.debug_struct("MacroExport").finish(),
|
2022-08-15 18:29:43 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-07 19:02:32 +03:00
|
|
|
/// One import.
|
2019-09-01 00:01:25 -07:00
|
|
|
#[derive(Debug, Clone)]
|
2022-05-20 19:51:09 -04:00
|
|
|
pub(crate) struct Import<'a> {
|
2020-03-07 18:49:13 +03:00
|
|
|
pub kind: ImportKind<'a>,
|
|
|
|
|
2022-10-30 13:35:31 +04:00
|
|
|
/// Node ID of the "root" use item -- this is always the same as `ImportKind`'s `id`
|
|
|
|
/// (if it exists) except in the case of "nested" use trees, in which case
|
|
|
|
/// it will be the ID of the root use tree. e.g., in the example
|
|
|
|
/// ```ignore (incomplete code)
|
2018-05-18 17:18:04 -04:00
|
|
|
/// use foo::bar::{a, b}
|
|
|
|
/// ```
|
2022-10-30 13:35:31 +04:00
|
|
|
/// this would be the ID of the `use foo::bar` `UseTree` node.
|
|
|
|
/// In case of imports without their own node ID it's the closest node that can be used,
|
|
|
|
/// for example, for reporting lints.
|
2018-05-18 17:18:04 -04:00
|
|
|
pub root_id: NodeId,
|
|
|
|
|
2019-01-29 13:34:40 +01:00
|
|
|
/// Span of the entire use statement.
|
|
|
|
pub use_span: Span,
|
|
|
|
|
|
|
|
/// Span of the entire use statement with attributes.
|
|
|
|
pub use_span_with_attributes: Span,
|
|
|
|
|
|
|
|
/// Did the use statement have any attributes?
|
|
|
|
pub has_attributes: bool,
|
|
|
|
|
2018-05-18 17:18:04 -04:00
|
|
|
/// Span of this use tree.
|
|
|
|
pub span: Span,
|
|
|
|
|
|
|
|
/// Span of the *root* use tree (see `root_id`).
|
|
|
|
pub root_span: Span,
|
|
|
|
|
2018-10-22 01:28:59 +03:00
|
|
|
pub parent_scope: ParentScope<'a>,
|
2018-09-12 15:21:50 +12:00
|
|
|
pub module_path: Vec<Segment>,
|
2018-08-09 16:29:22 +03:00
|
|
|
/// The resolution of `module_path`.
|
|
|
|
pub imported_module: Cell<Option<ModuleOrUniformRoot<'a>>>,
|
2022-08-27 18:36:57 +03:00
|
|
|
pub vis: Cell<Option<ty::Visibility>>,
|
2017-01-14 07:35:54 +00:00
|
|
|
pub used: Cell<bool>,
|
2015-03-16 10:44:19 +13:00
|
|
|
}
|
|
|
|
|
2020-03-07 18:49:13 +03:00
|
|
|
impl<'a> Import<'a> {
|
2016-04-17 01:57:09 +00:00
|
|
|
pub fn is_glob(&self) -> bool {
|
2020-10-26 21:02:48 -04:00
|
|
|
matches!(self.kind, ImportKind::Glob { .. })
|
2016-04-17 01:57:09 +00:00
|
|
|
}
|
2018-05-22 11:10:17 -04:00
|
|
|
|
2019-01-29 13:34:40 +01:00
|
|
|
pub fn is_nested(&self) -> bool {
|
2020-03-07 18:49:13 +03:00
|
|
|
match self.kind {
|
|
|
|
ImportKind::Single { nested, .. } => nested,
|
2019-12-24 17:38:22 -05:00
|
|
|
_ => false,
|
2019-01-29 13:34:40 +01:00
|
|
|
}
|
|
|
|
}
|
2022-08-27 18:36:57 +03:00
|
|
|
|
|
|
|
pub(crate) fn expect_vis(&self) -> ty::Visibility {
|
|
|
|
self.vis.get().expect("encountered cleared import visibility")
|
|
|
|
}
|
2022-10-30 13:35:31 +04:00
|
|
|
|
|
|
|
pub(crate) fn id(&self) -> Option<NodeId> {
|
|
|
|
match self.kind {
|
|
|
|
ImportKind::Single { id, .. }
|
|
|
|
| ImportKind::Glob { id, .. }
|
|
|
|
| ImportKind::ExternCrate { id, .. } => Some(id),
|
2022-10-30 15:55:58 +04:00
|
|
|
ImportKind::MacroUse | ImportKind::MacroExport => None,
|
2022-10-30 13:35:31 +04:00
|
|
|
}
|
|
|
|
}
|
2015-03-16 10:44:19 +13:00
|
|
|
}
|
|
|
|
|
2016-03-17 08:43:17 +00:00
|
|
|
/// Records information about the resolution of a name in a namespace of a module.
|
2022-03-26 20:59:09 +01:00
|
|
|
#[derive(Clone, Default, Debug)]
|
2022-05-20 19:51:09 -04:00
|
|
|
pub(crate) struct NameResolution<'a> {
|
2018-07-17 04:12:48 +03:00
|
|
|
/// Single imports that may define the name in the namespace.
|
2020-03-07 19:02:32 +03:00
|
|
|
/// Imports are arena-allocated, so it's ok to use pointers as keys.
|
2022-03-26 20:59:09 +01:00
|
|
|
pub single_imports: FxHashSet<Interned<'a, Import<'a>>>,
|
2016-02-07 23:58:14 +00:00
|
|
|
/// The least shadowable known binding for this name, or None if there are no known bindings.
|
2016-02-07 21:23:58 +00:00
|
|
|
pub binding: Option<&'a NameBinding<'a>>,
|
2022-03-26 20:59:09 +01:00
|
|
|
pub shadowed_glob: Option<&'a NameBinding<'a>>,
|
2015-03-16 10:44:19 +13:00
|
|
|
}
|
|
|
|
|
2016-02-07 22:28:54 +00:00
|
|
|
impl<'a> NameResolution<'a> {
|
2022-11-27 11:15:06 +00:00
|
|
|
/// Returns the binding for the name if it is known or None if it not known.
|
2019-04-07 19:56:41 +02:00
|
|
|
pub(crate) fn binding(&self) -> Option<&'a NameBinding<'a>> {
|
2018-07-17 04:12:48 +03:00
|
|
|
self.binding.and_then(|binding| {
|
2019-12-24 17:38:22 -05:00
|
|
|
if !binding.is_glob_import() || self.single_imports.is_empty() {
|
|
|
|
Some(binding)
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
2016-03-17 08:43:17 +00:00
|
|
|
})
|
|
|
|
}
|
2019-08-08 23:57:35 +03:00
|
|
|
|
2022-05-20 19:51:09 -04:00
|
|
|
pub(crate) fn add_single_import(&mut self, import: &'a Import<'a>) {
|
2022-02-04 14:26:29 +11:00
|
|
|
self.single_imports.insert(Interned::new_unchecked(import));
|
2019-08-08 23:57:35 +03:00
|
|
|
}
|
2016-08-01 20:43:48 +00:00
|
|
|
}
|
|
|
|
|
2021-01-29 00:59:20 +03:00
|
|
|
// Reexports of the form `pub use foo as bar;` where `foo` is `extern crate foo;`
|
|
|
|
// are permitted for backward-compatibility under a deprecation lint.
|
|
|
|
fn pub_use_of_private_extern_crate_hack(import: &Import<'_>, binding: &NameBinding<'_>) -> bool {
|
|
|
|
match (&import.kind, &binding.kind) {
|
|
|
|
(
|
|
|
|
ImportKind::Single { .. },
|
|
|
|
NameBindingKind::Import {
|
|
|
|
import: Import { kind: ImportKind::ExternCrate { .. }, .. },
|
|
|
|
..
|
|
|
|
},
|
2022-08-27 18:36:57 +03:00
|
|
|
) => import.expect_vis().is_public(),
|
2021-01-29 00:59:20 +03:00
|
|
|
_ => false,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-12-10 05:37:10 +01:00
|
|
|
impl<'a> Resolver<'a> {
|
2022-11-27 11:15:06 +00:00
|
|
|
/// Given a binding and an import that resolves to it,
|
|
|
|
/// return the corresponding binding defined by the import.
|
2022-05-20 19:51:09 -04:00
|
|
|
pub(crate) fn import(
|
2019-12-24 17:38:22 -05:00
|
|
|
&self,
|
|
|
|
binding: &'a NameBinding<'a>,
|
2020-03-07 19:02:32 +03:00
|
|
|
import: &'a Import<'a>,
|
2019-12-24 17:38:22 -05:00
|
|
|
) -> &'a NameBinding<'a> {
|
2022-08-28 00:10:06 +03:00
|
|
|
let import_vis = import.expect_vis().to_def_id();
|
2022-08-27 18:36:57 +03:00
|
|
|
let vis = if binding.vis.is_at_least(import_vis, self)
|
2021-01-29 00:59:20 +03:00
|
|
|
|| pub_use_of_private_extern_crate_hack(import, binding)
|
2019-12-24 17:38:22 -05:00
|
|
|
{
|
2022-08-27 18:36:57 +03:00
|
|
|
import_vis
|
2016-08-19 22:52:26 +00:00
|
|
|
} else {
|
2021-01-06 18:07:47 +03:00
|
|
|
binding.vis
|
2016-08-19 22:52:26 +00:00
|
|
|
};
|
|
|
|
|
2020-03-07 19:02:32 +03:00
|
|
|
if let ImportKind::Glob { ref max_vis, .. } = import.kind {
|
2022-08-27 18:36:57 +03:00
|
|
|
if vis == import_vis
|
|
|
|
|| max_vis.get().map_or(true, |max_vis| vis.is_at_least(max_vis, self))
|
|
|
|
{
|
2022-08-28 00:10:06 +03:00
|
|
|
max_vis.set(Some(vis.expect_local()))
|
2016-08-20 00:23:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-11-29 02:53:00 +00:00
|
|
|
self.arenas.alloc_name_binding(NameBinding {
|
2020-03-07 19:02:32 +03:00
|
|
|
kind: NameBindingKind::Import { binding, import, used: Cell::new(false) },
|
2018-12-29 18:15:29 +03:00
|
|
|
ambiguity: None,
|
2020-03-07 19:02:32 +03:00
|
|
|
span: import.span,
|
2017-08-06 22:54:09 -07:00
|
|
|
vis,
|
2020-03-07 19:02:32 +03:00
|
|
|
expansion: import.parent_scope.expansion,
|
2016-11-29 02:53:00 +00:00
|
|
|
})
|
2016-07-31 04:53:04 +00:00
|
|
|
}
|
|
|
|
|
2022-11-27 11:15:06 +00:00
|
|
|
/// Define the name or return the existing binding if there is a collision.
|
2022-05-20 19:51:09 -04:00
|
|
|
pub(crate) fn try_define(
|
2019-09-01 00:01:25 -07:00
|
|
|
&mut self,
|
|
|
|
module: Module<'a>,
|
2019-09-09 21:04:26 +01:00
|
|
|
key: BindingKey,
|
2019-09-01 00:01:25 -07:00
|
|
|
binding: &'a NameBinding<'a>,
|
|
|
|
) -> Result<(), &'a NameBinding<'a>> {
|
2019-06-30 01:24:34 +03:00
|
|
|
let res = binding.res();
|
2019-09-09 21:04:26 +01:00
|
|
|
self.check_reserved_macro_name(key.ident, res);
|
2018-09-27 04:49:40 +03:00
|
|
|
self.set_binding_parent_module(binding, module);
|
2019-09-09 21:04:26 +01:00
|
|
|
self.update_resolution(module, key, |this, resolution| {
|
2016-07-28 02:34:01 +00:00
|
|
|
if let Some(old_binding) = resolution.binding {
|
2022-10-15 22:37:31 +04:00
|
|
|
if res == Res::Err && old_binding.res() != Res::Err {
|
2019-04-20 19:36:05 +03:00
|
|
|
// Do not override real bindings with `Res::Err`s from error recovery.
|
2018-12-29 02:48:38 +03:00
|
|
|
return Ok(());
|
|
|
|
}
|
2018-11-05 01:11:59 +03:00
|
|
|
match (old_binding.is_glob_import(), binding.is_glob_import()) {
|
|
|
|
(true, true) => {
|
2019-06-30 01:24:34 +03:00
|
|
|
if res != old_binding.res() {
|
2019-12-24 17:38:22 -05:00
|
|
|
resolution.binding = Some(this.ambiguity(
|
|
|
|
AmbiguityKind::GlobVsGlob,
|
|
|
|
old_binding,
|
|
|
|
binding,
|
|
|
|
));
|
2018-11-05 01:11:59 +03:00
|
|
|
} else if !old_binding.vis.is_at_least(binding.vis, &*this) {
|
|
|
|
// We are glob-importing the same item but with greater visibility.
|
|
|
|
resolution.binding = Some(binding);
|
|
|
|
}
|
2016-08-20 03:28:35 +00:00
|
|
|
}
|
2018-11-05 01:11:59 +03:00
|
|
|
(old_glob @ true, false) | (old_glob @ false, true) => {
|
2019-12-24 17:38:22 -05:00
|
|
|
let (glob_binding, nonglob_binding) =
|
|
|
|
if old_glob { (old_binding, binding) } else { (binding, old_binding) };
|
2019-09-09 21:04:26 +01:00
|
|
|
if glob_binding.res() != nonglob_binding.res()
|
2019-12-24 17:38:22 -05:00
|
|
|
&& key.ns == MacroNS
|
2021-06-25 20:43:04 +02:00
|
|
|
&& nonglob_binding.expansion != LocalExpnId::ROOT
|
2019-09-09 21:04:26 +01:00
|
|
|
{
|
2019-09-01 00:01:25 -07:00
|
|
|
resolution.binding = Some(this.ambiguity(
|
|
|
|
AmbiguityKind::GlobVsExpanded,
|
|
|
|
nonglob_binding,
|
|
|
|
glob_binding,
|
|
|
|
));
|
2018-11-05 01:11:59 +03:00
|
|
|
} else {
|
|
|
|
resolution.binding = Some(nonglob_binding);
|
|
|
|
}
|
2018-12-29 18:15:29 +03:00
|
|
|
resolution.shadowed_glob = Some(glob_binding);
|
2018-11-05 01:11:59 +03:00
|
|
|
}
|
|
|
|
(false, false) => {
|
2019-12-28 17:37:22 +03:00
|
|
|
return Err(old_binding);
|
2016-11-10 10:29:36 +00:00
|
|
|
}
|
2016-07-28 02:34:01 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
resolution.binding = Some(binding);
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2019-09-01 00:01:25 -07:00
|
|
|
fn ambiguity(
|
2019-12-24 17:38:22 -05:00
|
|
|
&self,
|
|
|
|
kind: AmbiguityKind,
|
2019-09-01 00:01:25 -07:00
|
|
|
primary_binding: &'a NameBinding<'a>,
|
|
|
|
secondary_binding: &'a NameBinding<'a>,
|
|
|
|
) -> &'a NameBinding<'a> {
|
2016-11-10 10:29:36 +00:00
|
|
|
self.arenas.alloc_name_binding(NameBinding {
|
2018-12-29 18:15:29 +03:00
|
|
|
ambiguity: Some((secondary_binding, kind)),
|
2019-01-26 16:29:34 +03:00
|
|
|
..primary_binding.clone()
|
2016-11-10 10:29:36 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2016-07-28 02:34:01 +00:00
|
|
|
// Use `f` to mutate the resolution of the name in the module.
|
2016-02-16 03:54:14 +00:00
|
|
|
// If the resolution becomes a success, define it in the module's glob importers.
|
2019-12-24 17:38:22 -05:00
|
|
|
fn update_resolution<T, F>(&mut self, module: Module<'a>, key: BindingKey, f: F) -> T
|
|
|
|
where
|
|
|
|
F: FnOnce(&mut Resolver<'a>, &mut NameResolution<'a>) -> T,
|
2016-02-16 03:54:14 +00:00
|
|
|
{
|
2016-07-28 02:34:01 +00:00
|
|
|
// Ensure that `resolution` isn't borrowed when defining in the module's glob importers,
|
|
|
|
// during which the resolution might end up getting re-defined via a glob cycle.
|
2016-08-20 07:22:32 +00:00
|
|
|
let (binding, t) = {
|
2019-09-09 21:04:26 +01:00
|
|
|
let resolution = &mut *self.resolution(module, key).borrow_mut();
|
2016-08-20 03:28:35 +00:00
|
|
|
let old_binding = resolution.binding();
|
2016-02-16 03:54:14 +00:00
|
|
|
|
2016-07-28 02:34:01 +00:00
|
|
|
let t = f(self, resolution);
|
2016-04-07 22:14:44 +00:00
|
|
|
|
|
|
|
match resolution.binding() {
|
2016-10-11 07:47:21 +00:00
|
|
|
_ if old_binding.is_some() => return t,
|
2016-04-07 22:14:44 +00:00
|
|
|
None => return t,
|
2016-08-20 03:28:35 +00:00
|
|
|
Some(binding) => match old_binding {
|
2018-07-18 21:53:54 +03:00
|
|
|
Some(old_binding) if ptr::eq(old_binding, binding) => return t,
|
2016-08-20 03:28:35 +00:00
|
|
|
_ => (binding, t),
|
2019-12-24 17:38:22 -05:00
|
|
|
},
|
2016-02-07 23:58:14 +00:00
|
|
|
}
|
2016-04-07 22:14:44 +00:00
|
|
|
};
|
|
|
|
|
2016-08-20 07:22:32 +00:00
|
|
|
// Define `binding` in `module`s glob importers.
|
2020-03-07 19:02:32 +03:00
|
|
|
for import in module.glob_importers.borrow_mut().iter() {
|
2019-09-09 21:04:26 +01:00
|
|
|
let mut ident = key.ident;
|
2020-03-07 19:02:32 +03:00
|
|
|
let scope = match ident.span.reverse_glob_adjust(module.expansion, import.span) {
|
2021-09-12 01:47:46 +03:00
|
|
|
Some(Some(def)) => self.expn_def_scope(def),
|
2020-03-07 19:02:32 +03:00
|
|
|
Some(None) => import.parent_scope.module,
|
2017-03-22 08:39:51 +00:00
|
|
|
None => continue,
|
|
|
|
};
|
|
|
|
if self.is_accessible_from(binding.vis, scope) {
|
2020-03-07 19:02:32 +03:00
|
|
|
let imported_binding = self.import(binding, import);
|
2019-09-09 21:04:26 +01:00
|
|
|
let key = BindingKey { ident, ..key };
|
2020-03-07 19:02:32 +03:00
|
|
|
let _ = self.try_define(import.parent_scope.module, key, imported_binding);
|
2016-07-28 02:34:01 +00:00
|
|
|
}
|
2016-02-16 03:54:14 +00:00
|
|
|
}
|
2016-07-28 02:34:01 +00:00
|
|
|
|
|
|
|
t
|
2015-03-16 10:44:19 +13:00
|
|
|
}
|
2016-11-10 06:19:54 +00:00
|
|
|
|
2022-04-10 17:21:58 +03:00
|
|
|
// Define a dummy resolution containing a `Res::Err` as a placeholder for a failed resolution,
|
|
|
|
// also mark such failed imports as used to avoid duplicate diagnostics.
|
2020-03-07 19:02:32 +03:00
|
|
|
fn import_dummy_binding(&mut self, import: &'a Import<'a>) {
|
2022-04-10 17:21:58 +03:00
|
|
|
if let ImportKind::Single { target, ref target_bindings, .. } = import.kind {
|
|
|
|
if target_bindings.iter().any(|binding| binding.get().is_some()) {
|
|
|
|
return; // Has resolution, do not create the dummy binding
|
|
|
|
}
|
2016-11-10 06:19:54 +00:00
|
|
|
let dummy_binding = self.dummy_binding;
|
2020-03-07 19:02:32 +03:00
|
|
|
let dummy_binding = self.import(dummy_binding, import);
|
2016-11-10 06:19:54 +00:00
|
|
|
self.per_ns(|this, ns| {
|
2019-09-09 21:04:26 +01:00
|
|
|
let key = this.new_key(target, ns);
|
2020-03-07 19:02:32 +03:00
|
|
|
let _ = this.try_define(import.parent_scope.module, key, dummy_binding);
|
2016-11-10 06:19:54 +00:00
|
|
|
});
|
2021-08-22 16:50:59 +02:00
|
|
|
self.record_use(target, dummy_binding, false);
|
2022-04-10 17:21:58 +03:00
|
|
|
} else if import.imported_module.get().is_none() {
|
|
|
|
import.used.set(true);
|
2022-10-30 13:35:31 +04:00
|
|
|
if let Some(id) = import.id() {
|
|
|
|
self.used_imports.insert(id);
|
|
|
|
}
|
2016-11-10 06:19:54 +00:00
|
|
|
}
|
|
|
|
}
|
2015-03-16 10:44:19 +13:00
|
|
|
}
|
|
|
|
|
2019-01-16 15:30:41 -05:00
|
|
|
/// An error that may be transformed into a diagnostic later. Used to combine multiple unresolved
|
|
|
|
/// import errors within the same use tree into a single diagnostic.
|
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
struct UnresolvedImportError {
|
|
|
|
span: Span,
|
|
|
|
label: Option<String>,
|
2022-07-28 18:17:55 +09:00
|
|
|
note: Option<String>,
|
2019-01-16 15:30:41 -05:00
|
|
|
suggestion: Option<Suggestion>,
|
2022-12-27 05:09:33 +00:00
|
|
|
candidates: Option<Vec<ImportSuggestion>>,
|
2019-01-16 15:30:41 -05:00
|
|
|
}
|
|
|
|
|
2019-06-14 19:39:39 +03:00
|
|
|
pub struct ImportResolver<'a, 'b> {
|
2019-08-08 14:06:42 +03:00
|
|
|
pub r: &'a mut Resolver<'b>,
|
2016-07-28 16:17:01 +00:00
|
|
|
}
|
|
|
|
|
2019-06-14 19:39:39 +03:00
|
|
|
impl<'a, 'b> ImportResolver<'a, 'b> {
|
2015-03-16 10:44:19 +13:00
|
|
|
// Import resolution
|
|
|
|
//
|
|
|
|
// This is a fixed-point algorithm. We resolve imports until our efforts
|
|
|
|
// are stymied by an unresolved import; then we bail out of the current
|
|
|
|
// module and continue. We terminate successfully once no more imports
|
|
|
|
// remain or unsuccessfully when no forward progress in resolving imports
|
|
|
|
// is made.
|
|
|
|
|
|
|
|
/// Resolves all imports for the crate. This method performs the fixed-
|
|
|
|
/// point iteration.
|
2016-11-10 10:11:25 +00:00
|
|
|
pub fn resolve_imports(&mut self) {
|
2019-08-08 14:06:42 +03:00
|
|
|
let mut prev_num_indeterminates = self.r.indeterminate_imports.len() + 1;
|
|
|
|
while self.r.indeterminate_imports.len() < prev_num_indeterminates {
|
|
|
|
prev_num_indeterminates = self.r.indeterminate_imports.len();
|
|
|
|
for import in mem::take(&mut self.r.indeterminate_imports) {
|
2016-08-17 00:52:18 +00:00
|
|
|
match self.resolve_import(&import) {
|
2019-08-08 14:06:42 +03:00
|
|
|
true => self.r.determined_imports.push(import),
|
|
|
|
false => self.r.indeterminate_imports.push(import),
|
2016-04-17 20:23:10 +00:00
|
|
|
}
|
2015-03-16 10:44:19 +13:00
|
|
|
}
|
2016-08-17 00:52:18 +00:00
|
|
|
}
|
2016-11-10 10:11:25 +00:00
|
|
|
}
|
2016-08-17 00:52:18 +00:00
|
|
|
|
2016-11-10 10:11:25 +00:00
|
|
|
pub fn finalize_imports(&mut self) {
|
2019-08-08 14:06:42 +03:00
|
|
|
for module in self.r.arenas.local_modules().iter() {
|
2016-08-17 00:52:18 +00:00
|
|
|
self.finalize_resolutions_in(module);
|
|
|
|
}
|
|
|
|
|
2018-10-16 10:44:26 +02:00
|
|
|
let mut seen_spans = FxHashSet::default();
|
2019-01-16 15:30:41 -05:00
|
|
|
let mut errors = vec![];
|
2018-11-07 10:08:41 +01:00
|
|
|
let mut prev_root_id: NodeId = NodeId::from_u32(0);
|
2019-09-01 00:01:25 -07:00
|
|
|
let determined_imports = mem::take(&mut self.r.determined_imports);
|
|
|
|
let indeterminate_imports = mem::take(&mut self.r.indeterminate_imports);
|
|
|
|
|
|
|
|
for (is_indeterminate, import) in determined_imports
|
|
|
|
.into_iter()
|
|
|
|
.map(|i| (false, i))
|
|
|
|
.chain(indeterminate_imports.into_iter().map(|i| (true, i)))
|
|
|
|
{
|
2022-04-10 17:21:58 +03:00
|
|
|
let unresolved_import_error = self.finalize_import(import);
|
|
|
|
|
|
|
|
// If this import is unresolved then create a dummy import
|
|
|
|
// resolution for it so that later resolve stages won't complain.
|
|
|
|
self.r.import_dummy_binding(import);
|
|
|
|
|
|
|
|
if let Some(err) = unresolved_import_error {
|
2020-03-07 18:49:13 +03:00
|
|
|
if let ImportKind::Single { source, ref source_bindings, .. } = import.kind {
|
2019-05-13 22:46:20 +03:00
|
|
|
if source.name == kw::SelfLower {
|
2017-06-10 10:55:19 +01:00
|
|
|
// Silence `unresolved import` error if E0429 is already emitted
|
2018-11-30 21:16:21 +03:00
|
|
|
if let Err(Determined) = source_bindings.value_ns.get() {
|
2018-10-17 11:13:44 +02:00
|
|
|
continue;
|
2017-06-10 10:55:19 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-01-16 15:30:41 -05:00
|
|
|
if prev_root_id.as_u32() != 0
|
2019-12-24 17:38:22 -05:00
|
|
|
&& prev_root_id.as_u32() != import.root_id.as_u32()
|
|
|
|
&& !errors.is_empty()
|
|
|
|
{
|
2019-01-16 15:30:41 -05:00
|
|
|
// In the case of a new import line, throw a diagnostic message
|
|
|
|
// for the previous line.
|
2022-11-04 13:59:04 +09:00
|
|
|
self.throw_unresolved_import_error(errors);
|
2019-01-16 15:30:41 -05:00
|
|
|
errors = vec![];
|
2018-09-03 17:27:14 +00:00
|
|
|
}
|
2019-10-16 13:48:20 +09:00
|
|
|
if seen_spans.insert(err.span) {
|
2022-12-27 04:28:02 +00:00
|
|
|
errors.push((import, err));
|
2018-09-03 17:27:14 +00:00
|
|
|
prev_root_id = import.root_id;
|
2017-07-23 15:15:45 -07:00
|
|
|
}
|
2019-09-01 00:01:25 -07:00
|
|
|
} else if is_indeterminate {
|
|
|
|
let path = import_path_to_string(
|
|
|
|
&import.module_path.iter().map(|seg| seg.ident).collect::<Vec<_>>(),
|
2020-03-07 18:49:13 +03:00
|
|
|
&import.kind,
|
2019-09-01 00:01:25 -07:00
|
|
|
import.span,
|
|
|
|
);
|
|
|
|
let err = UnresolvedImportError {
|
|
|
|
span: import.span,
|
|
|
|
label: None,
|
2022-07-28 18:17:55 +09:00
|
|
|
note: None,
|
2019-09-01 00:01:25 -07:00
|
|
|
suggestion: None,
|
2022-12-27 05:09:33 +00:00
|
|
|
candidates: None,
|
2019-09-01 00:01:25 -07:00
|
|
|
};
|
2022-12-27 04:28:02 +00:00
|
|
|
// FIXME: there should be a better way of doing this than
|
|
|
|
// formatting this as a string then checking for `::`
|
2022-03-04 13:07:39 +09:00
|
|
|
if path.contains("::") {
|
2022-12-27 04:28:02 +00:00
|
|
|
errors.push((import, err))
|
2022-03-04 13:07:39 +09:00
|
|
|
}
|
2016-08-15 08:19:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-01-16 15:30:41 -05:00
|
|
|
if !errors.is_empty() {
|
2022-11-04 13:59:04 +09:00
|
|
|
self.throw_unresolved_import_error(errors);
|
2018-09-03 17:27:14 +00:00
|
|
|
}
|
2015-03-16 10:44:19 +13:00
|
|
|
}
|
|
|
|
|
2022-12-27 04:28:02 +00:00
|
|
|
fn throw_unresolved_import_error(&self, errors: Vec<(&Import<'_>, UnresolvedImportError)>) {
|
2022-11-04 13:59:04 +09:00
|
|
|
if errors.is_empty() {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-01-16 15:30:41 -05:00
|
|
|
/// Upper limit on the number of `span_label` messages.
|
|
|
|
const MAX_LABEL_COUNT: usize = 10;
|
|
|
|
|
2022-11-04 13:59:04 +09:00
|
|
|
let span = MultiSpan::from_spans(errors.iter().map(|(_, err)| err.span).collect());
|
2022-12-27 04:28:02 +00:00
|
|
|
let paths = errors
|
|
|
|
.iter()
|
|
|
|
.map(|(import, err)| {
|
|
|
|
let path = import_path_to_string(
|
|
|
|
&import.module_path.iter().map(|seg| seg.ident).collect::<Vec<_>>(),
|
|
|
|
&import.kind,
|
|
|
|
err.span,
|
|
|
|
);
|
|
|
|
format!("`{path}`")
|
|
|
|
})
|
|
|
|
.collect::<Vec<_>>();
|
2022-11-04 13:59:04 +09:00
|
|
|
let msg = format!("unresolved import{} {}", pluralize!(paths.len()), paths.join(", "),);
|
2018-10-18 19:09:49 +02:00
|
|
|
|
2019-08-08 14:06:42 +03:00
|
|
|
let mut diag = struct_span_err!(self.r.session, span, E0432, "{}", &msg);
|
2019-01-16 15:30:41 -05:00
|
|
|
|
2022-07-28 18:17:55 +09:00
|
|
|
if let Some((_, UnresolvedImportError { note: Some(note), .. })) = errors.iter().last() {
|
|
|
|
diag.note(note);
|
2018-09-03 17:27:14 +00:00
|
|
|
}
|
2019-01-16 15:30:41 -05:00
|
|
|
|
2022-12-27 04:28:02 +00:00
|
|
|
for (import, err) in errors.into_iter().take(MAX_LABEL_COUNT) {
|
2019-01-16 15:30:41 -05:00
|
|
|
if let Some(label) = err.label {
|
|
|
|
diag.span_label(err.span, label);
|
|
|
|
}
|
|
|
|
|
2019-04-12 01:53:32 +02:00
|
|
|
if let Some((suggestions, msg, applicability)) = err.suggestion {
|
2022-05-22 11:48:35 +09:00
|
|
|
if suggestions.is_empty() {
|
|
|
|
diag.help(&msg);
|
|
|
|
continue;
|
|
|
|
}
|
2019-04-12 01:53:32 +02:00
|
|
|
diag.multipart_suggestion(&msg, suggestions, applicability);
|
2019-01-16 15:30:41 -05:00
|
|
|
}
|
2022-10-10 11:14:32 +08:00
|
|
|
|
2022-12-27 05:09:33 +00:00
|
|
|
if let Some(candidates) = &err.candidates {
|
2022-12-27 04:28:02 +00:00
|
|
|
match &import.kind {
|
2022-12-27 07:05:45 +00:00
|
|
|
ImportKind::Single { nested: false, source, target, .. } => import_candidates(
|
2022-12-27 04:28:02 +00:00
|
|
|
self.r.session,
|
|
|
|
&self.r.untracked.source_span,
|
|
|
|
&mut diag,
|
|
|
|
Some(err.span),
|
2022-12-27 05:09:33 +00:00
|
|
|
&candidates,
|
|
|
|
DiagnosticMode::Import,
|
2022-12-27 07:05:45 +00:00
|
|
|
(source != target).then(|| format!(" as {target}")).as_deref(),
|
2022-12-27 04:28:02 +00:00
|
|
|
),
|
2022-12-27 07:05:45 +00:00
|
|
|
ImportKind::Single { nested: true, source, target, .. } => {
|
2022-12-27 05:09:33 +00:00
|
|
|
import_candidates(
|
|
|
|
self.r.session,
|
|
|
|
&self.r.untracked.source_span,
|
|
|
|
&mut diag,
|
|
|
|
None,
|
|
|
|
&candidates,
|
|
|
|
DiagnosticMode::Normal,
|
2022-12-27 07:05:45 +00:00
|
|
|
(source != target).then(|| format!(" as {target}")).as_deref(),
|
2022-12-27 05:09:33 +00:00
|
|
|
);
|
|
|
|
}
|
2022-12-27 04:28:02 +00:00
|
|
|
_ => {}
|
|
|
|
}
|
2022-10-10 11:14:32 +08:00
|
|
|
}
|
2018-10-18 19:09:49 +02:00
|
|
|
}
|
2019-01-16 15:30:41 -05:00
|
|
|
|
|
|
|
diag.emit();
|
2018-09-03 17:27:14 +00:00
|
|
|
}
|
|
|
|
|
2016-11-26 12:21:47 +00:00
|
|
|
/// Attempts to resolve the given import, returning true if its resolution is determined.
|
2015-03-16 10:44:19 +13:00
|
|
|
/// If successful, the resolved bindings are written into the module.
|
2020-03-07 19:02:32 +03:00
|
|
|
fn resolve_import(&mut self, import: &'b Import<'b>) -> bool {
|
2019-08-05 21:18:50 +03:00
|
|
|
debug!(
|
|
|
|
"(resolving import for module) resolving import `{}::...` in `{}`",
|
2020-03-07 19:02:32 +03:00
|
|
|
Segment::names_to_string(&import.module_path),
|
|
|
|
module_to_string(import.parent_scope.module).unwrap_or_else(|| "???".to_string()),
|
2019-08-05 21:18:50 +03:00
|
|
|
);
|
2016-08-17 00:52:18 +00:00
|
|
|
|
2020-03-07 19:02:32 +03:00
|
|
|
let module = if let Some(module) = import.imported_module.get() {
|
2016-08-18 00:11:56 +00:00
|
|
|
module
|
|
|
|
} else {
|
2018-11-09 01:29:07 +03:00
|
|
|
// For better failure detection, pretend that the import will
|
|
|
|
// not define any names while resolving its module path.
|
2022-08-27 18:36:57 +03:00
|
|
|
let orig_vis = import.vis.take();
|
2022-03-24 00:32:00 +03:00
|
|
|
let path_res =
|
2022-04-08 22:50:56 +02:00
|
|
|
self.r.maybe_resolve_path(&import.module_path, None, &import.parent_scope);
|
2020-03-07 19:02:32 +03:00
|
|
|
import.vis.set(orig_vis);
|
2016-08-18 00:11:56 +00:00
|
|
|
|
2018-11-10 18:58:37 +03:00
|
|
|
match path_res {
|
2016-11-25 06:07:21 +00:00
|
|
|
PathResult::Module(module) => module,
|
2016-11-26 12:21:47 +00:00
|
|
|
PathResult::Indeterminate => return false,
|
2019-01-16 15:30:41 -05:00
|
|
|
PathResult::NonModule(..) | PathResult::Failed { .. } => return true,
|
2016-08-18 00:11:56 +00:00
|
|
|
}
|
2016-03-13 02:53:22 +00:00
|
|
|
};
|
2015-03-16 10:44:19 +13:00
|
|
|
|
2020-03-07 19:02:32 +03:00
|
|
|
import.imported_module.set(Some(module));
|
|
|
|
let (source, target, source_bindings, target_bindings, type_ns_only) = match import.kind {
|
2020-03-07 18:49:13 +03:00
|
|
|
ImportKind::Single {
|
|
|
|
source,
|
|
|
|
target,
|
|
|
|
ref source_bindings,
|
|
|
|
ref target_bindings,
|
|
|
|
type_ns_only,
|
|
|
|
..
|
|
|
|
} => (source, target, source_bindings, target_bindings, type_ns_only),
|
|
|
|
ImportKind::Glob { .. } => {
|
2020-03-07 19:02:32 +03:00
|
|
|
self.resolve_glob_import(import);
|
2020-03-07 18:49:13 +03:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
_ => unreachable!(),
|
|
|
|
};
|
2016-02-07 23:58:14 +00:00
|
|
|
|
2016-08-15 08:19:09 +00:00
|
|
|
let mut indeterminate = false;
|
2019-12-24 17:38:22 -05:00
|
|
|
self.r.per_ns(|this, ns| {
|
|
|
|
if !type_ns_only || ns == TypeNS {
|
|
|
|
if let Err(Undetermined) = source_bindings[ns].get() {
|
|
|
|
// For better failure detection, pretend that the import will
|
|
|
|
// not define any names while resolving its module path.
|
2022-08-27 18:36:57 +03:00
|
|
|
let orig_vis = import.vis.take();
|
2019-12-24 17:38:22 -05:00
|
|
|
let binding = this.resolve_ident_in_module(
|
|
|
|
module,
|
|
|
|
source,
|
|
|
|
ns,
|
2020-03-07 19:02:32 +03:00
|
|
|
&import.parent_scope,
|
2022-03-24 00:32:00 +03:00
|
|
|
None,
|
2022-04-08 22:50:56 +02:00
|
|
|
None,
|
2019-12-24 17:38:22 -05:00
|
|
|
);
|
2020-03-07 19:02:32 +03:00
|
|
|
import.vis.set(orig_vis);
|
2019-12-24 17:38:22 -05:00
|
|
|
source_bindings[ns].set(binding);
|
|
|
|
} else {
|
|
|
|
return;
|
|
|
|
};
|
2016-08-17 20:48:53 +00:00
|
|
|
|
2020-03-07 19:02:32 +03:00
|
|
|
let parent = import.parent_scope.module;
|
2019-12-24 17:38:22 -05:00
|
|
|
match source_bindings[ns].get() {
|
|
|
|
Err(Undetermined) => indeterminate = true,
|
|
|
|
// Don't update the resolution, because it was never added.
|
|
|
|
Err(Determined) if target.name == kw::Underscore => {}
|
2022-04-10 17:21:58 +03:00
|
|
|
Ok(binding) if binding.is_importable() => {
|
|
|
|
let imported_binding = this.import(binding, import);
|
|
|
|
target_bindings[ns].set(Some(imported_binding));
|
|
|
|
this.define(parent, target, ns, imported_binding);
|
|
|
|
}
|
|
|
|
source_binding @ (Ok(..) | Err(Determined)) => {
|
|
|
|
if source_binding.is_ok() {
|
|
|
|
let msg = format!("`{}` is not directly importable", target);
|
|
|
|
struct_span_err!(this.session, import.span, E0253, "{}", &msg)
|
|
|
|
.span_label(import.span, "cannot be imported directly")
|
|
|
|
.emit();
|
|
|
|
}
|
2019-12-24 17:38:22 -05:00
|
|
|
let key = this.new_key(target, ns);
|
|
|
|
this.update_resolution(parent, key, |_, resolution| {
|
2022-02-04 14:26:29 +11:00
|
|
|
resolution.single_imports.remove(&Interned::new_unchecked(import));
|
2019-12-24 17:38:22 -05:00
|
|
|
});
|
|
|
|
}
|
2016-02-16 13:14:32 +00:00
|
|
|
}
|
2016-02-13 21:49:16 +00:00
|
|
|
}
|
2016-11-10 06:19:54 +00:00
|
|
|
});
|
2015-03-16 10:44:19 +13:00
|
|
|
|
2016-11-26 12:21:47 +00:00
|
|
|
!indeterminate
|
2016-08-15 08:19:09 +00:00
|
|
|
}
|
|
|
|
|
2019-01-16 15:30:41 -05:00
|
|
|
/// Performs final import resolution, consistency checks and error reporting.
|
|
|
|
///
|
|
|
|
/// Optionally returns an unresolved import error. This error is buffered and used to
|
|
|
|
/// consolidate multiple unresolved import errors into a single diagnostic.
|
2020-03-07 19:02:32 +03:00
|
|
|
fn finalize_import(&mut self, import: &'b Import<'b>) -> Option<UnresolvedImportError> {
|
2022-08-27 18:36:57 +03:00
|
|
|
let orig_vis = import.vis.take();
|
2022-04-30 18:01:01 +03:00
|
|
|
let ignore_binding = match &import.kind {
|
2022-04-08 22:50:56 +02:00
|
|
|
ImportKind::Single { target_bindings, .. } => target_bindings[TypeNS].get(),
|
2020-11-05 15:16:12 -05:00
|
|
|
_ => None,
|
|
|
|
};
|
2019-08-08 14:06:42 +03:00
|
|
|
let prev_ambiguity_errors_len = self.r.ambiguity_errors.len();
|
2022-04-30 17:31:44 +03:00
|
|
|
let finalize = Finalize::with_root_span(import.root_id, import.span, import.root_span);
|
2022-04-08 22:50:56 +02:00
|
|
|
let path_res = self.r.resolve_path(
|
|
|
|
&import.module_path,
|
|
|
|
None,
|
|
|
|
&import.parent_scope,
|
2022-04-30 17:31:44 +03:00
|
|
|
Some(finalize),
|
2022-04-30 18:01:01 +03:00
|
|
|
ignore_binding,
|
2022-04-08 22:50:56 +02:00
|
|
|
);
|
2022-10-10 11:14:32 +08:00
|
|
|
|
2019-08-08 14:06:42 +03:00
|
|
|
let no_ambiguity = self.r.ambiguity_errors.len() == prev_ambiguity_errors_len;
|
2020-03-07 19:02:32 +03:00
|
|
|
import.vis.set(orig_vis);
|
2018-11-10 18:58:37 +03:00
|
|
|
let module = match path_res {
|
|
|
|
PathResult::Module(module) => {
|
2019-08-12 21:52:37 +03:00
|
|
|
// Consistency checks, analogous to `finalize_macro_resolutions`.
|
2020-03-07 19:02:32 +03:00
|
|
|
if let Some(initial_module) = import.imported_module.get() {
|
2018-12-29 00:15:19 +03:00
|
|
|
if !ModuleOrUniformRoot::same_def(module, initial_module) && no_ambiguity {
|
2020-11-05 15:16:12 -05:00
|
|
|
span_bug!(import.span, "inconsistent resolution for an import");
|
2018-11-10 18:58:37 +03:00
|
|
|
}
|
2020-10-26 21:02:48 -04:00
|
|
|
} else if self.r.privacy_errors.is_empty() {
|
|
|
|
let msg = "cannot determine resolution for the import";
|
|
|
|
let msg_note = "import resolution is stuck, try simplifying other imports";
|
|
|
|
self.r.session.struct_span_err(import.span, msg).note(msg_note).emit();
|
2018-11-10 18:58:37 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
module
|
|
|
|
}
|
2019-01-16 15:30:41 -05:00
|
|
|
PathResult::Failed { is_error_from_last_segment: false, span, label, suggestion } => {
|
2018-12-08 04:19:29 +03:00
|
|
|
if no_ambiguity {
|
2020-03-07 19:02:32 +03:00
|
|
|
assert!(import.imported_module.get().is_none());
|
2019-12-24 17:38:22 -05:00
|
|
|
self.r
|
|
|
|
.report_error(span, ResolutionError::FailedToResolve { label, suggestion });
|
2018-12-08 04:19:29 +03:00
|
|
|
}
|
2017-11-19 17:05:29 +03:00
|
|
|
return None;
|
|
|
|
}
|
2019-01-16 15:30:41 -05:00
|
|
|
PathResult::Failed { is_error_from_last_segment: true, span, label, suggestion } => {
|
2018-12-08 04:19:29 +03:00
|
|
|
if no_ambiguity {
|
2020-11-05 15:16:12 -05:00
|
|
|
assert!(import.imported_module.get().is_none());
|
2019-01-16 15:30:41 -05:00
|
|
|
let err = match self.make_path_suggestion(
|
|
|
|
span,
|
2020-03-07 19:02:32 +03:00
|
|
|
import.module_path.clone(),
|
|
|
|
&import.parent_scope,
|
2019-01-16 15:30:41 -05:00
|
|
|
) {
|
2019-12-24 17:38:22 -05:00
|
|
|
Some((suggestion, note)) => UnresolvedImportError {
|
|
|
|
span,
|
|
|
|
label: None,
|
|
|
|
note,
|
|
|
|
suggestion: Some((
|
|
|
|
vec![(span, Segment::names_to_string(&suggestion))],
|
|
|
|
String::from("a similar path exists"),
|
|
|
|
Applicability::MaybeIncorrect,
|
|
|
|
)),
|
2022-12-27 05:09:33 +00:00
|
|
|
candidates: None,
|
2019-12-24 17:38:22 -05:00
|
|
|
},
|
|
|
|
None => UnresolvedImportError {
|
|
|
|
span,
|
|
|
|
label: Some(label),
|
2022-07-28 18:17:55 +09:00
|
|
|
note: None,
|
2019-12-24 17:38:22 -05:00
|
|
|
suggestion,
|
2022-12-27 05:09:33 +00:00
|
|
|
candidates: None,
|
2019-12-24 17:38:22 -05:00
|
|
|
},
|
2019-01-16 15:30:41 -05:00
|
|
|
};
|
|
|
|
return Some(err);
|
2018-12-08 04:19:29 +03:00
|
|
|
}
|
|
|
|
return None;
|
2018-11-10 18:58:37 +03:00
|
|
|
}
|
2021-03-20 20:00:25 -07:00
|
|
|
PathResult::NonModule(_) => {
|
2018-12-08 04:19:29 +03:00
|
|
|
if no_ambiguity {
|
2020-03-07 19:02:32 +03:00
|
|
|
assert!(import.imported_module.get().is_none());
|
2018-12-08 04:19:29 +03:00
|
|
|
}
|
2018-11-10 18:58:37 +03:00
|
|
|
// The error was already reported earlier.
|
|
|
|
return None;
|
|
|
|
}
|
2021-03-20 20:00:25 -07:00
|
|
|
PathResult::Indeterminate => unreachable!(),
|
2016-08-15 08:19:09 +00:00
|
|
|
};
|
|
|
|
|
2022-10-30 13:35:31 +04:00
|
|
|
let (ident, target, source_bindings, target_bindings, type_ns_only, import_id) =
|
|
|
|
match import.kind {
|
|
|
|
ImportKind::Single {
|
|
|
|
source,
|
|
|
|
target,
|
|
|
|
ref source_bindings,
|
|
|
|
ref target_bindings,
|
|
|
|
type_ns_only,
|
|
|
|
id,
|
|
|
|
..
|
|
|
|
} => (source, target, source_bindings, target_bindings, type_ns_only, id),
|
|
|
|
ImportKind::Glob { is_prelude, ref max_vis, id } => {
|
|
|
|
if import.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 = import.module_path.clone();
|
|
|
|
full_path.push(Segment::from_ident(Ident::empty()));
|
|
|
|
self.r.lint_if_path_starts_with_module(Some(finalize), &full_path, None);
|
|
|
|
}
|
2018-08-09 16:29:22 +03:00
|
|
|
|
2022-10-30 13:35:31 +04:00
|
|
|
if let ModuleOrUniformRoot::Module(module) = module {
|
|
|
|
if ptr::eq(module, import.parent_scope.module) {
|
|
|
|
// Importing a module into itself is not allowed.
|
|
|
|
return Some(UnresolvedImportError {
|
|
|
|
span: import.span,
|
|
|
|
label: Some(String::from(
|
|
|
|
"cannot glob-import a module into itself",
|
|
|
|
)),
|
|
|
|
note: None,
|
|
|
|
suggestion: None,
|
2022-12-27 05:09:33 +00:00
|
|
|
candidates: None,
|
2022-10-30 13:35:31 +04:00
|
|
|
});
|
|
|
|
}
|
2018-08-09 16:29:22 +03:00
|
|
|
}
|
2022-10-30 13:35:31 +04:00
|
|
|
if !is_prelude
|
2022-08-27 18:36:57 +03:00
|
|
|
&& let Some(max_vis) = max_vis.get()
|
|
|
|
&& !max_vis.is_at_least(import.expect_vis(), &*self.r)
|
2019-12-24 17:38:22 -05:00
|
|
|
{
|
|
|
|
let msg = "glob import doesn't reexport anything because no candidate is public enough";
|
2022-10-30 13:35:31 +04:00
|
|
|
self.r.lint_buffer.buffer_lint(UNUSED_IMPORTS, id, import.span, msg);
|
2016-08-20 00:23:32 +00:00
|
|
|
}
|
2022-10-30 13:35:31 +04:00
|
|
|
return None;
|
|
|
|
}
|
|
|
|
_ => unreachable!(),
|
|
|
|
};
|
2016-08-15 08:19:09 +00:00
|
|
|
|
2016-11-10 06:19:54 +00:00
|
|
|
let mut all_ns_err = true;
|
2019-12-24 17:38:22 -05:00
|
|
|
self.r.per_ns(|this, ns| {
|
|
|
|
if !type_ns_only || ns == TypeNS {
|
2022-08-27 18:36:57 +03:00
|
|
|
let orig_vis = import.vis.take();
|
2019-12-24 17:38:22 -05:00
|
|
|
let binding = this.resolve_ident_in_module(
|
|
|
|
module,
|
|
|
|
ident,
|
|
|
|
ns,
|
2020-03-07 19:02:32 +03:00
|
|
|
&import.parent_scope,
|
2022-04-30 17:31:44 +03:00
|
|
|
Some(Finalize { report_private: false, ..finalize }),
|
2022-04-08 22:50:56 +02:00
|
|
|
target_bindings[ns].get(),
|
2019-12-24 17:38:22 -05:00
|
|
|
);
|
2020-03-07 19:02:32 +03:00
|
|
|
import.vis.set(orig_vis);
|
2018-11-10 18:58:37 +03:00
|
|
|
|
2019-12-24 17:38:22 -05:00
|
|
|
match binding {
|
|
|
|
Ok(binding) => {
|
|
|
|
// Consistency checks, analogous to `finalize_macro_resolutions`.
|
2022-12-03 21:18:37 +08:00
|
|
|
let initial_binding = source_bindings[ns].get().map(|initial_binding| {
|
2019-12-24 17:38:22 -05:00
|
|
|
all_ns_err = false;
|
|
|
|
if let Some(target_binding) = target_bindings[ns].get() {
|
2020-07-08 11:04:10 +10:00
|
|
|
if target.name == kw::Underscore
|
2019-12-24 17:38:22 -05:00
|
|
|
&& initial_binding.is_extern_crate()
|
|
|
|
&& !initial_binding.is_import()
|
|
|
|
{
|
|
|
|
this.record_use(
|
|
|
|
ident,
|
|
|
|
target_binding,
|
2020-03-07 19:02:32 +03:00
|
|
|
import.module_path.is_empty(),
|
2019-12-24 17:38:22 -05:00
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
2022-12-03 21:18:37 +08:00
|
|
|
initial_binding
|
2019-12-24 17:38:22 -05:00
|
|
|
});
|
|
|
|
let res = binding.res();
|
2022-12-03 21:18:37 +08:00
|
|
|
if let Ok(initial_binding) = initial_binding {
|
|
|
|
let initial_res = initial_binding.res();
|
2019-12-24 17:38:22 -05:00
|
|
|
if res != initial_res && this.ambiguity_errors.is_empty() {
|
2022-12-03 21:18:37 +08:00
|
|
|
this.ambiguity_errors.push(AmbiguityError {
|
|
|
|
kind: AmbiguityKind::Import,
|
|
|
|
ident,
|
|
|
|
b1: initial_binding,
|
|
|
|
b2: binding,
|
|
|
|
misc1: AmbiguityErrorMisc::None,
|
|
|
|
misc2: AmbiguityErrorMisc::None,
|
|
|
|
});
|
2019-12-24 17:38:22 -05:00
|
|
|
}
|
2020-10-26 21:02:48 -04:00
|
|
|
} else if res != Res::Err
|
|
|
|
&& this.ambiguity_errors.is_empty()
|
|
|
|
&& this.privacy_errors.is_empty()
|
|
|
|
{
|
|
|
|
let msg = "cannot determine resolution for the import";
|
|
|
|
let msg_note =
|
|
|
|
"import resolution is stuck, try simplifying other imports";
|
|
|
|
this.session.struct_span_err(import.span, msg).note(msg_note).emit();
|
2018-11-10 18:58:37 +03:00
|
|
|
}
|
2018-08-09 16:29:22 +03:00
|
|
|
}
|
2019-12-24 17:38:22 -05:00
|
|
|
Err(..) => {
|
|
|
|
// FIXME: This assert may fire if public glob is later shadowed by a private
|
|
|
|
// single import (see test `issue-55884-2.rs`). In theory single imports should
|
|
|
|
// always block globs, even if they are not yet resolved, so that this kind of
|
|
|
|
// self-inconsistent resolution never happens.
|
2020-03-06 12:13:55 +01:00
|
|
|
// Re-enable the assert when the issue is fixed.
|
2019-12-24 17:38:22 -05:00
|
|
|
// assert!(result[ns].get().is_err());
|
|
|
|
}
|
2018-10-20 20:26:24 +03:00
|
|
|
}
|
2016-08-15 08:19:09 +00:00
|
|
|
}
|
2016-11-10 06:19:54 +00:00
|
|
|
});
|
2016-08-15 08:19:09 +00:00
|
|
|
|
2016-11-10 06:19:54 +00:00
|
|
|
if all_ns_err {
|
|
|
|
let mut all_ns_failed = true;
|
2019-12-24 17:38:22 -05:00
|
|
|
self.r.per_ns(|this, ns| {
|
|
|
|
if !type_ns_only || ns == TypeNS {
|
|
|
|
let binding = this.resolve_ident_in_module(
|
|
|
|
module,
|
|
|
|
ident,
|
|
|
|
ns,
|
2020-03-07 19:02:32 +03:00
|
|
|
&import.parent_scope,
|
2022-04-30 17:31:44 +03:00
|
|
|
Some(finalize),
|
2022-04-08 22:50:56 +02:00
|
|
|
None,
|
2019-12-24 17:38:22 -05:00
|
|
|
);
|
|
|
|
if binding.is_ok() {
|
|
|
|
all_ns_failed = false;
|
|
|
|
}
|
2016-11-10 06:19:54 +00:00
|
|
|
}
|
|
|
|
});
|
2016-08-15 08:19:09 +00:00
|
|
|
|
2016-11-10 06:19:54 +00:00
|
|
|
return if all_ns_failed {
|
2018-08-09 16:29:22 +03:00
|
|
|
let resolutions = match module {
|
2019-12-24 17:38:22 -05:00
|
|
|
ModuleOrUniformRoot::Module(module) => {
|
|
|
|
Some(self.r.resolutions(module).borrow())
|
|
|
|
}
|
2018-11-24 19:14:05 +03:00
|
|
|
_ => None,
|
2018-08-09 16:29:22 +03:00
|
|
|
};
|
|
|
|
let resolutions = resolutions.as_ref().into_iter().flat_map(|r| r.iter());
|
Move lev_distance to rustc_ast, make non-generic
rustc_ast currently has a few dependencies on rustc_lexer. Ideally, an AST
would not have any dependency its lexer, for minimizing unnecessarily
design-time dependencies. Breaking this dependency would also have practical
benefits, since modifying rustc_lexer would not trigger a rebuild of rustc_ast.
This commit does not remove the rustc_ast --> rustc_lexer dependency,
but it does remove one of the sources of this dependency, which is the
code that handles fuzzy matching between symbol names for making suggestions
in diagnostics. Since that code depends only on Symbol, it is easy to move
it to rustc_span. It might even be best to move it to a separate crate,
since other tools such as Cargo use the same algorithm, and have simply
contain a duplicate of the code.
This changes the signature of find_best_match_for_name so that it is no
longer generic over its input. I checked the optimized binaries, and this
function was duplicated at nearly every call site, because most call sites
used short-lived iterator chains, generic over Map and such. But there's
no good reason for a function like this to be generic, since all it does
is immediately convert the generic input (the Iterator impl) to a concrete
Vec<Symbol>. This has all of the costs of generics (duplicated method bodies)
with no benefit.
Changing find_best_match_for_name to be non-generic removed about 10KB of
code from the optimized binary. I know it's a drop in the bucket, but we have
to start reducing binary size, and beginning to tame over-use of generics
is part of that.
2020-11-12 11:24:10 -08:00
|
|
|
let names = resolutions
|
|
|
|
.filter_map(|(BindingKey { ident: i, .. }, resolution)| {
|
|
|
|
if *i == ident {
|
|
|
|
return None;
|
|
|
|
} // Never suggest the same name
|
|
|
|
match *resolution.borrow() {
|
|
|
|
NameResolution { binding: Some(name_binding), .. } => {
|
|
|
|
match name_binding.kind {
|
|
|
|
NameBindingKind::Import { binding, .. } => {
|
|
|
|
match binding.kind {
|
|
|
|
// Never suggest the name that has binding error
|
|
|
|
// i.e., the name that cannot be previously resolved
|
2022-10-30 15:55:58 +04:00
|
|
|
NameBindingKind::Res(Res::Err) => None,
|
Move lev_distance to rustc_ast, make non-generic
rustc_ast currently has a few dependencies on rustc_lexer. Ideally, an AST
would not have any dependency its lexer, for minimizing unnecessarily
design-time dependencies. Breaking this dependency would also have practical
benefits, since modifying rustc_lexer would not trigger a rebuild of rustc_ast.
This commit does not remove the rustc_ast --> rustc_lexer dependency,
but it does remove one of the sources of this dependency, which is the
code that handles fuzzy matching between symbol names for making suggestions
in diagnostics. Since that code depends only on Symbol, it is easy to move
it to rustc_span. It might even be best to move it to a separate crate,
since other tools such as Cargo use the same algorithm, and have simply
contain a duplicate of the code.
This changes the signature of find_best_match_for_name so that it is no
longer generic over its input. I checked the optimized binaries, and this
function was duplicated at nearly every call site, because most call sites
used short-lived iterator chains, generic over Map and such. But there's
no good reason for a function like this to be generic, since all it does
is immediately convert the generic input (the Iterator impl) to a concrete
Vec<Symbol>. This has all of the costs of generics (duplicated method bodies)
with no benefit.
Changing find_best_match_for_name to be non-generic removed about 10KB of
code from the optimized binary. I know it's a drop in the bucket, but we have
to start reducing binary size, and beginning to tame over-use of generics
is part of that.
2020-11-12 11:24:10 -08:00
|
|
|
_ => Some(i.name),
|
|
|
|
}
|
2017-02-02 22:05:49 +11:00
|
|
|
}
|
Move lev_distance to rustc_ast, make non-generic
rustc_ast currently has a few dependencies on rustc_lexer. Ideally, an AST
would not have any dependency its lexer, for minimizing unnecessarily
design-time dependencies. Breaking this dependency would also have practical
benefits, since modifying rustc_lexer would not trigger a rebuild of rustc_ast.
This commit does not remove the rustc_ast --> rustc_lexer dependency,
but it does remove one of the sources of this dependency, which is the
code that handles fuzzy matching between symbol names for making suggestions
in diagnostics. Since that code depends only on Symbol, it is easy to move
it to rustc_span. It might even be best to move it to a separate crate,
since other tools such as Cargo use the same algorithm, and have simply
contain a duplicate of the code.
This changes the signature of find_best_match_for_name so that it is no
longer generic over its input. I checked the optimized binaries, and this
function was duplicated at nearly every call site, because most call sites
used short-lived iterator chains, generic over Map and such. But there's
no good reason for a function like this to be generic, since all it does
is immediately convert the generic input (the Iterator impl) to a concrete
Vec<Symbol>. This has all of the costs of generics (duplicated method bodies)
with no benefit.
Changing find_best_match_for_name to be non-generic removed about 10KB of
code from the optimized binary. I know it's a drop in the bucket, but we have
to start reducing binary size, and beginning to tame over-use of generics
is part of that.
2020-11-12 11:24:10 -08:00
|
|
|
_ => Some(i.name),
|
2019-12-24 17:38:22 -05:00
|
|
|
}
|
2017-02-02 22:05:49 +11:00
|
|
|
}
|
Move lev_distance to rustc_ast, make non-generic
rustc_ast currently has a few dependencies on rustc_lexer. Ideally, an AST
would not have any dependency its lexer, for minimizing unnecessarily
design-time dependencies. Breaking this dependency would also have practical
benefits, since modifying rustc_lexer would not trigger a rebuild of rustc_ast.
This commit does not remove the rustc_ast --> rustc_lexer dependency,
but it does remove one of the sources of this dependency, which is the
code that handles fuzzy matching between symbol names for making suggestions
in diagnostics. Since that code depends only on Symbol, it is easy to move
it to rustc_span. It might even be best to move it to a separate crate,
since other tools such as Cargo use the same algorithm, and have simply
contain a duplicate of the code.
This changes the signature of find_best_match_for_name so that it is no
longer generic over its input. I checked the optimized binaries, and this
function was duplicated at nearly every call site, because most call sites
used short-lived iterator chains, generic over Map and such. But there's
no good reason for a function like this to be generic, since all it does
is immediately convert the generic input (the Iterator impl) to a concrete
Vec<Symbol>. This has all of the costs of generics (duplicated method bodies)
with no benefit.
Changing find_best_match_for_name to be non-generic removed about 10KB of
code from the optimized binary. I know it's a drop in the bucket, but we have
to start reducing binary size, and beginning to tame over-use of generics
is part of that.
2020-11-12 11:24:10 -08:00
|
|
|
NameResolution { ref single_imports, .. }
|
|
|
|
if single_imports.is_empty() =>
|
|
|
|
{
|
|
|
|
None
|
|
|
|
}
|
|
|
|
_ => Some(i.name),
|
2019-12-24 17:38:22 -05:00
|
|
|
}
|
Move lev_distance to rustc_ast, make non-generic
rustc_ast currently has a few dependencies on rustc_lexer. Ideally, an AST
would not have any dependency its lexer, for minimizing unnecessarily
design-time dependencies. Breaking this dependency would also have practical
benefits, since modifying rustc_lexer would not trigger a rebuild of rustc_ast.
This commit does not remove the rustc_ast --> rustc_lexer dependency,
but it does remove one of the sources of this dependency, which is the
code that handles fuzzy matching between symbol names for making suggestions
in diagnostics. Since that code depends only on Symbol, it is easy to move
it to rustc_span. It might even be best to move it to a separate crate,
since other tools such as Cargo use the same algorithm, and have simply
contain a duplicate of the code.
This changes the signature of find_best_match_for_name so that it is no
longer generic over its input. I checked the optimized binaries, and this
function was duplicated at nearly every call site, because most call sites
used short-lived iterator chains, generic over Map and such. But there's
no good reason for a function like this to be generic, since all it does
is immediately convert the generic input (the Iterator impl) to a concrete
Vec<Symbol>. This has all of the costs of generics (duplicated method bodies)
with no benefit.
Changing find_best_match_for_name to be non-generic removed about 10KB of
code from the optimized binary. I know it's a drop in the bucket, but we have
to start reducing binary size, and beginning to tame over-use of generics
is part of that.
2020-11-12 11:24:10 -08:00
|
|
|
})
|
|
|
|
.collect::<Vec<Symbol>>();
|
2019-01-16 15:30:41 -05:00
|
|
|
|
2019-12-24 17:38:22 -05:00
|
|
|
let lev_suggestion =
|
Move lev_distance to rustc_ast, make non-generic
rustc_ast currently has a few dependencies on rustc_lexer. Ideally, an AST
would not have any dependency its lexer, for minimizing unnecessarily
design-time dependencies. Breaking this dependency would also have practical
benefits, since modifying rustc_lexer would not trigger a rebuild of rustc_ast.
This commit does not remove the rustc_ast --> rustc_lexer dependency,
but it does remove one of the sources of this dependency, which is the
code that handles fuzzy matching between symbol names for making suggestions
in diagnostics. Since that code depends only on Symbol, it is easy to move
it to rustc_span. It might even be best to move it to a separate crate,
since other tools such as Cargo use the same algorithm, and have simply
contain a duplicate of the code.
This changes the signature of find_best_match_for_name so that it is no
longer generic over its input. I checked the optimized binaries, and this
function was duplicated at nearly every call site, because most call sites
used short-lived iterator chains, generic over Map and such. But there's
no good reason for a function like this to be generic, since all it does
is immediately convert the generic input (the Iterator impl) to a concrete
Vec<Symbol>. This has all of the costs of generics (duplicated method bodies)
with no benefit.
Changing find_best_match_for_name to be non-generic removed about 10KB of
code from the optimized binary. I know it's a drop in the bucket, but we have
to start reducing binary size, and beginning to tame over-use of generics
is part of that.
2020-11-12 11:24:10 -08:00
|
|
|
find_best_match_for_name(&names, ident.name, None).map(|suggestion| {
|
2019-12-24 17:38:22 -05:00
|
|
|
(
|
|
|
|
vec![(ident.span, suggestion.to_string())],
|
|
|
|
String::from("a similar name exists in the module"),
|
|
|
|
Applicability::MaybeIncorrect,
|
|
|
|
)
|
|
|
|
});
|
2019-04-07 20:34:21 +02:00
|
|
|
|
2019-12-24 17:38:22 -05:00
|
|
|
let (suggestion, note) =
|
2020-03-07 19:02:32 +03:00
|
|
|
match self.check_for_module_export_macro(import, module, ident) {
|
2019-12-24 17:38:22 -05:00
|
|
|
Some((suggestion, note)) => (suggestion.or(lev_suggestion), note),
|
2022-07-28 18:17:55 +09:00
|
|
|
_ => (lev_suggestion, None),
|
2019-12-24 17:38:22 -05:00
|
|
|
};
|
2019-01-16 15:30:41 -05:00
|
|
|
|
|
|
|
let label = match module {
|
2018-08-09 16:29:22 +03:00
|
|
|
ModuleOrUniformRoot::Module(module) => {
|
|
|
|
let module_str = module_to_string(module);
|
|
|
|
if let Some(module_str) = module_str {
|
2019-01-16 15:30:41 -05:00
|
|
|
format!("no `{}` in `{}`", ident, module_str)
|
2018-08-09 16:29:22 +03:00
|
|
|
} else {
|
2019-01-16 15:30:41 -05:00
|
|
|
format!("no `{}` in the root", ident)
|
2018-08-09 16:29:22 +03:00
|
|
|
}
|
|
|
|
}
|
2018-11-24 19:14:05 +03:00
|
|
|
_ => {
|
2018-08-09 16:29:22 +03:00
|
|
|
if !ident.is_path_segment_keyword() {
|
2020-09-30 15:52:13 -07:00
|
|
|
format!("no external crate `{}`", ident)
|
2018-08-09 16:29:22 +03:00
|
|
|
} else {
|
|
|
|
// HACK(eddyb) this shows up for `self` & `super`, which
|
|
|
|
// should work instead - for now keep the same error message.
|
2019-01-16 15:30:41 -05:00
|
|
|
format!("no `{}` in the root", ident)
|
2018-08-09 16:29:22 +03:00
|
|
|
}
|
|
|
|
}
|
2016-04-09 01:06:57 +00:00
|
|
|
};
|
2019-04-07 19:56:41 +02:00
|
|
|
|
2022-10-10 11:14:32 +08:00
|
|
|
let parent_suggestion =
|
|
|
|
self.r.lookup_import_candidates(ident, TypeNS, &import.parent_scope, |_| true);
|
|
|
|
|
2019-01-16 15:30:41 -05:00
|
|
|
Some(UnresolvedImportError {
|
2020-03-07 19:02:32 +03:00
|
|
|
span: import.span,
|
2019-01-16 15:30:41 -05:00
|
|
|
label: Some(label),
|
2019-04-07 19:56:41 +02:00
|
|
|
note,
|
|
|
|
suggestion,
|
2022-12-27 05:09:33 +00:00
|
|
|
candidates: if !parent_suggestion.is_empty() {
|
2022-10-10 11:14:32 +08:00
|
|
|
Some(parent_suggestion)
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
},
|
2019-01-16 15:30:41 -05:00
|
|
|
})
|
2016-08-15 08:19:09 +00:00
|
|
|
} else {
|
2016-11-29 02:07:12 +00:00
|
|
|
// `resolve_ident_in_module` reported a privacy error.
|
2016-11-26 12:21:47 +00:00
|
|
|
None
|
2019-12-24 17:38:22 -05:00
|
|
|
};
|
2016-07-25 23:04:42 +00:00
|
|
|
}
|
|
|
|
|
2016-11-10 06:19:54 +00:00
|
|
|
let mut reexport_error = None;
|
|
|
|
let mut any_successful_reexport = false;
|
2021-11-06 04:43:55 +09:00
|
|
|
let mut crate_private_reexport = false;
|
2019-08-08 14:06:42 +03:00
|
|
|
self.r.per_ns(|this, ns| {
|
2018-11-30 21:16:21 +03:00
|
|
|
if let Ok(binding) = source_bindings[ns].get() {
|
2022-08-27 18:36:57 +03:00
|
|
|
if !binding.vis.is_at_least(import.expect_vis(), &*this) {
|
2016-11-10 06:19:54 +00:00
|
|
|
reexport_error = Some((ns, binding));
|
2021-11-06 04:43:55 +09:00
|
|
|
if let ty::Visibility::Restricted(binding_def_id) = binding.vis {
|
|
|
|
if binding_def_id.is_top_level_module() {
|
|
|
|
crate_private_reexport = true;
|
|
|
|
}
|
|
|
|
}
|
2016-02-16 03:54:14 +00:00
|
|
|
} else {
|
2016-11-10 06:19:54 +00:00
|
|
|
any_successful_reexport = true;
|
2015-03-16 10:44:19 +13:00
|
|
|
}
|
2016-01-14 01:42:45 +00:00
|
|
|
}
|
2016-11-10 06:19:54 +00:00
|
|
|
});
|
2015-12-14 22:36:31 +05:30
|
|
|
|
2016-11-10 06:19:54 +00:00
|
|
|
// All namespaces must be re-exported with extra visibility for an error to occur.
|
|
|
|
if !any_successful_reexport {
|
2017-05-21 15:50:38 +03:00
|
|
|
let (ns, binding) = reexport_error.unwrap();
|
2021-01-29 00:59:20 +03:00
|
|
|
if pub_use_of_private_extern_crate_hack(import, binding) {
|
2019-12-24 17:38:22 -05:00
|
|
|
let msg = format!(
|
|
|
|
"extern crate `{}` is private, and cannot be \
|
2018-01-12 16:41:45 -05:00
|
|
|
re-exported (error E0365), consider declaring with \
|
|
|
|
`pub`",
|
2019-12-24 17:38:22 -05:00
|
|
|
ident
|
|
|
|
);
|
|
|
|
self.r.lint_buffer.buffer_lint(
|
|
|
|
PUB_USE_OF_PRIVATE_EXTERN_CRATE,
|
2022-10-30 13:35:31 +04:00
|
|
|
import_id,
|
2020-03-07 19:02:32 +03:00
|
|
|
import.span,
|
2019-12-24 17:38:22 -05:00
|
|
|
&msg,
|
|
|
|
);
|
2016-11-10 06:19:54 +00:00
|
|
|
} else {
|
2021-11-06 04:43:55 +09:00
|
|
|
let error_msg = if crate_private_reexport {
|
|
|
|
format!(
|
|
|
|
"`{}` is only public within the crate, and cannot be re-exported outside",
|
|
|
|
ident
|
|
|
|
)
|
|
|
|
} else {
|
|
|
|
format!("`{}` is private, and cannot be re-exported", ident)
|
|
|
|
};
|
|
|
|
|
|
|
|
if ns == TypeNS {
|
|
|
|
let label_msg = if crate_private_reexport {
|
|
|
|
format!("re-export of crate public `{}`", ident)
|
|
|
|
} else {
|
|
|
|
format!("re-export of private `{}`", ident)
|
|
|
|
};
|
|
|
|
|
|
|
|
struct_span_err!(self.r.session, import.span, E0365, "{}", error_msg)
|
|
|
|
.span_label(import.span, label_msg)
|
|
|
|
.note(&format!("consider declaring type or module `{}` with `pub`", ident))
|
|
|
|
.emit();
|
|
|
|
} else {
|
2022-06-14 14:58:46 +09:00
|
|
|
let mut err =
|
|
|
|
struct_span_err!(self.r.session, import.span, E0364, "{error_msg}");
|
|
|
|
match binding.kind {
|
2022-10-30 15:55:58 +04:00
|
|
|
NameBindingKind::Res(Res::Def(DefKind::Macro(_), def_id))
|
2022-06-14 14:58:46 +09:00
|
|
|
// exclude decl_macro
|
2022-06-15 00:31:21 +09:00
|
|
|
if self.r.get_macro_by_def_id(def_id).macro_rules =>
|
2022-06-14 14:58:46 +09:00
|
|
|
{
|
|
|
|
err.span_help(
|
|
|
|
binding.span,
|
|
|
|
"consider adding a `#[macro_export]` to the macro in the imported module",
|
|
|
|
);
|
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
err.span_note(
|
|
|
|
import.span,
|
|
|
|
&format!(
|
|
|
|
"consider marking `{ident}` as `pub` in the imported module"
|
|
|
|
),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
err.emit();
|
2021-11-06 04:43:55 +09:00
|
|
|
}
|
2016-11-10 06:19:54 +00:00
|
|
|
}
|
2016-01-14 01:42:45 +00:00
|
|
|
}
|
2015-03-16 10:44:19 +13:00
|
|
|
|
2020-03-07 19:02:32 +03:00
|
|
|
if import.module_path.len() <= 1 {
|
2018-08-09 16:29:22 +03:00
|
|
|
// HACK(eddyb) `lint_if_path_starts_with_module` needs at least
|
|
|
|
// 2 segments, so the `resolve_path` above won't trigger it.
|
2020-03-07 19:02:32 +03:00
|
|
|
let mut full_path = import.module_path.clone();
|
2018-09-12 15:21:50 +12:00
|
|
|
full_path.push(Segment::from_ident(ident));
|
2019-08-08 14:06:42 +03:00
|
|
|
self.r.per_ns(|this, ns| {
|
2018-11-30 21:16:21 +03:00
|
|
|
if let Ok(binding) = source_bindings[ns].get() {
|
2022-04-30 17:31:44 +03:00
|
|
|
this.lint_if_path_starts_with_module(Some(finalize), &full_path, Some(binding));
|
2018-05-11 10:02:17 -07:00
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2016-02-07 23:06:10 +00:00
|
|
|
// Record what this import resolves to for later uses in documentation,
|
|
|
|
// this may resolve to either a value or a type, but for documentation
|
|
|
|
// purposes it's good enough to just favor one over the other.
|
2019-12-24 17:38:22 -05:00
|
|
|
self.r.per_ns(|this, ns| {
|
2020-03-02 00:09:17 +01:00
|
|
|
if let Ok(binding) = source_bindings[ns].get() {
|
2022-10-30 13:35:31 +04:00
|
|
|
this.import_res_map.entry(import_id).or_default()[ns] = Some(binding.res());
|
2019-12-24 17:38:22 -05:00
|
|
|
}
|
2016-11-10 06:19:54 +00:00
|
|
|
});
|
2015-03-16 10:44:19 +13:00
|
|
|
|
2020-03-07 19:02:32 +03:00
|
|
|
self.check_for_redundant_imports(ident, import, source_bindings, target_bindings, target);
|
2019-02-22 15:07:18 +01:00
|
|
|
|
2015-03-16 10:44:19 +13:00
|
|
|
debug!("(resolving single import) successfully resolved import");
|
2016-11-26 12:21:47 +00:00
|
|
|
None
|
2015-03-16 10:44:19 +13:00
|
|
|
}
|
|
|
|
|
2019-02-22 15:07:18 +01:00
|
|
|
fn check_for_redundant_imports(
|
|
|
|
&mut self,
|
|
|
|
ident: Ident,
|
2020-03-07 19:02:32 +03:00
|
|
|
import: &'b Import<'b>,
|
2019-02-22 15:07:18 +01:00
|
|
|
source_bindings: &PerNS<Cell<Result<&'b NameBinding<'b>, Determinacy>>>,
|
|
|
|
target_bindings: &PerNS<Cell<Option<&'b NameBinding<'b>>>>,
|
|
|
|
target: Ident,
|
|
|
|
) {
|
2022-10-30 13:35:31 +04:00
|
|
|
// This function is only called for single imports.
|
|
|
|
let ImportKind::Single { id, .. } = import.kind else { unreachable!() };
|
|
|
|
|
2019-03-16 16:49:13 +01:00
|
|
|
// Skip if the import was produced by a macro.
|
2021-06-25 20:43:04 +02:00
|
|
|
if import.parent_scope.expansion != LocalExpnId::ROOT {
|
2019-02-22 15:07:18 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-03-16 16:49:13 +01:00
|
|
|
// Skip if we are inside a named module (in contrast to an anonymous
|
|
|
|
// module defined by a block).
|
2020-03-07 19:02:32 +03:00
|
|
|
if let ModuleKind::Def(..) = import.parent_scope.module.kind {
|
2019-02-22 15:07:18 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-12-24 17:38:22 -05:00
|
|
|
let mut is_redundant = PerNS { value_ns: None, type_ns: None, macro_ns: None };
|
2019-02-22 15:07:18 +01:00
|
|
|
|
2019-12-24 17:38:22 -05:00
|
|
|
let mut redundant_span = PerNS { value_ns: None, type_ns: None, macro_ns: None };
|
2019-02-22 15:07:18 +01:00
|
|
|
|
2019-12-24 17:38:22 -05:00
|
|
|
self.r.per_ns(|this, ns| {
|
2020-03-02 00:09:17 +01:00
|
|
|
if let Ok(binding) = source_bindings[ns].get() {
|
2019-12-24 17:38:22 -05:00
|
|
|
if binding.res() == Res::Err {
|
|
|
|
return;
|
|
|
|
}
|
2019-02-22 15:07:18 +01:00
|
|
|
|
2019-12-24 17:38:22 -05:00
|
|
|
match this.early_resolve_ident_in_lexical_scope(
|
|
|
|
target,
|
|
|
|
ScopeSet::All(ns, false),
|
2020-03-07 19:02:32 +03:00
|
|
|
&import.parent_scope,
|
2022-03-24 00:32:00 +03:00
|
|
|
None,
|
2019-12-24 17:38:22 -05:00
|
|
|
false,
|
2022-04-08 22:50:56 +02:00
|
|
|
target_bindings[ns].get(),
|
2019-12-24 17:38:22 -05:00
|
|
|
) {
|
|
|
|
Ok(other_binding) => {
|
|
|
|
is_redundant[ns] = Some(
|
|
|
|
binding.res() == other_binding.res() && !other_binding.is_ambiguity(),
|
|
|
|
);
|
|
|
|
redundant_span[ns] = Some((other_binding.span, other_binding.is_import()));
|
|
|
|
}
|
|
|
|
Err(_) => is_redundant[ns] = Some(false),
|
2019-02-22 15:07:18 +01:00
|
|
|
}
|
2019-12-24 17:38:22 -05:00
|
|
|
}
|
2019-02-22 15:07:18 +01:00
|
|
|
});
|
|
|
|
|
2019-12-24 17:38:22 -05:00
|
|
|
if !is_redundant.is_empty() && is_redundant.present_items().all(|is_redundant| is_redundant)
|
2019-02-22 15:07:18 +01:00
|
|
|
{
|
2019-04-11 16:15:48 -07:00
|
|
|
let mut redundant_spans: Vec<_> = redundant_span.present_items().collect();
|
2019-04-12 11:42:52 -07:00
|
|
|
redundant_spans.sort();
|
2019-04-11 16:15:48 -07:00
|
|
|
redundant_spans.dedup();
|
2019-10-25 09:15:33 -04:00
|
|
|
self.r.lint_buffer.buffer_lint_with_diagnostic(
|
2019-03-17 09:49:31 +01:00
|
|
|
UNUSED_IMPORTS,
|
2022-10-30 13:35:31 +04:00
|
|
|
id,
|
2020-03-07 19:02:32 +03:00
|
|
|
import.span,
|
2019-02-22 15:07:18 +01:00
|
|
|
&format!("the item `{}` is imported redundantly", ident),
|
2019-04-11 16:15:48 -07:00
|
|
|
BuiltinLintDiagnostics::RedundantImport(redundant_spans, ident),
|
2019-02-22 15:07:18 +01:00
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-07 19:02:32 +03:00
|
|
|
fn resolve_glob_import(&mut self, import: &'b Import<'b>) {
|
2022-10-30 13:35:31 +04:00
|
|
|
// This function is only called for glob imports.
|
|
|
|
let ImportKind::Glob { id, is_prelude, .. } = import.kind else { unreachable!() };
|
|
|
|
|
2022-02-19 00:48:49 +01:00
|
|
|
let ModuleOrUniformRoot::Module(module) = import.imported_module.get().unwrap() else {
|
|
|
|
self.r.session.span_err(import.span, "cannot glob-import all possible crates");
|
|
|
|
return;
|
2018-08-09 16:29:22 +03:00
|
|
|
};
|
|
|
|
|
2019-03-15 14:55:04 -07:00
|
|
|
if module.is_trait() {
|
2021-10-03 15:53:02 +09:00
|
|
|
self.r.session.span_err(import.span, "items in traits are not importable");
|
2016-08-19 21:46:28 +00:00
|
|
|
return;
|
2021-09-26 19:29:53 +03:00
|
|
|
} else if ptr::eq(module, import.parent_scope.module) {
|
2016-08-15 08:19:09 +00:00
|
|
|
return;
|
2022-10-30 13:35:31 +04:00
|
|
|
} else if is_prelude {
|
2019-08-08 14:06:42 +03:00
|
|
|
self.r.prelude = Some(module);
|
2016-08-15 08:19:09 +00:00
|
|
|
return;
|
2016-03-09 01:46:46 +00:00
|
|
|
}
|
|
|
|
|
2016-08-18 01:43:26 +00:00
|
|
|
// Add to module's glob_importers
|
2020-03-07 19:02:32 +03:00
|
|
|
module.glob_importers.borrow_mut().push(import);
|
2016-02-16 03:54:14 +00:00
|
|
|
|
2016-07-28 02:34:01 +00:00
|
|
|
// Ensure that `resolutions` isn't borrowed during `try_define`,
|
2016-04-11 18:30:48 +00:00
|
|
|
// since it might get updated via a glob cycle.
|
2019-12-24 17:38:22 -05:00
|
|
|
let bindings = self
|
|
|
|
.r
|
|
|
|
.resolutions(module)
|
|
|
|
.borrow()
|
|
|
|
.iter()
|
|
|
|
.filter_map(|(key, resolution)| {
|
|
|
|
resolution.borrow().binding().map(|binding| (*key, binding))
|
|
|
|
})
|
|
|
|
.collect::<Vec<_>>();
|
2019-09-09 21:04:26 +01:00
|
|
|
for (mut key, binding) in bindings {
|
2020-03-07 19:02:32 +03:00
|
|
|
let scope = match key.ident.span.reverse_glob_adjust(module.expansion, import.span) {
|
2021-09-12 01:47:46 +03:00
|
|
|
Some(Some(def)) => self.r.expn_def_scope(def),
|
2020-03-07 19:02:32 +03:00
|
|
|
Some(None) => import.parent_scope.module,
|
2017-03-22 08:39:51 +00:00
|
|
|
None => continue,
|
|
|
|
};
|
2021-01-06 18:07:47 +03:00
|
|
|
if self.r.is_accessible_from(binding.vis, scope) {
|
2020-03-07 19:02:32 +03:00
|
|
|
let imported_binding = self.r.import(binding, import);
|
|
|
|
let _ = self.r.try_define(import.parent_scope.module, key, imported_binding);
|
2016-02-07 23:58:14 +00:00
|
|
|
}
|
2016-02-16 03:54:14 +00:00
|
|
|
}
|
2015-03-16 10:44:19 +13:00
|
|
|
|
|
|
|
// Record the destination of this import
|
2022-10-30 13:35:31 +04:00
|
|
|
self.r.record_partial_res(id, PartialRes::new(module.res().unwrap()));
|
2015-03-16 10:44:19 +13:00
|
|
|
}
|
|
|
|
|
2018-01-12 16:41:25 -05:00
|
|
|
// Miscellaneous post-processing, including recording re-exports,
|
2017-05-21 14:11:08 +03:00
|
|
|
// reporting conflicts, and reporting unresolved imports.
|
2016-08-17 00:52:18 +00:00
|
|
|
fn finalize_resolutions_in(&mut self, module: Module<'b>) {
|
2016-02-16 03:54:14 +00:00
|
|
|
// Since import resolution is finished, globs will not define any more names.
|
2016-03-17 11:05:09 +00:00
|
|
|
*module.globs.borrow_mut() = Vec::new();
|
2016-02-16 03:54:14 +00:00
|
|
|
|
2022-06-27 16:29:56 +10:00
|
|
|
if let Some(def_id) = module.opt_def_id() {
|
|
|
|
let mut reexports = Vec::new();
|
|
|
|
|
2022-08-14 17:04:30 +03:00
|
|
|
module.for_each_child(self.r, |this, ident, _, binding| {
|
|
|
|
if let Some(res) = this.is_reexport(binding) {
|
|
|
|
reexports.push(ModChild {
|
|
|
|
ident,
|
|
|
|
res,
|
|
|
|
vis: binding.vis,
|
|
|
|
span: binding.span,
|
|
|
|
macro_rules: false,
|
|
|
|
});
|
2016-08-20 05:23:19 +00:00
|
|
|
}
|
2022-06-27 16:29:56 +10:00
|
|
|
});
|
2016-02-16 03:54:14 +00:00
|
|
|
|
2022-06-27 16:29:56 +10:00
|
|
|
if !reexports.is_empty() {
|
2020-06-07 11:14:47 +01:00
|
|
|
// Call to `expect_local` should be fine because current
|
|
|
|
// code is only called for local modules.
|
2021-12-21 11:24:43 +08:00
|
|
|
self.r.reexport_map.insert(def_id.expect_local(), reexports);
|
2016-02-16 03:54:14 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2015-03-16 10:44:19 +13:00
|
|
|
}
|
|
|
|
|
2020-03-07 18:49:13 +03:00
|
|
|
fn import_path_to_string(names: &[Ident], import_kind: &ImportKind<'_>, span: Span) -> String {
|
2019-12-24 17:38:22 -05:00
|
|
|
let pos = names.iter().position(|p| span == p.span && p.name != kw::PathRoot);
|
2019-05-11 17:41:37 +03:00
|
|
|
let global = !names.is_empty() && names[0].name == kw::PathRoot;
|
2017-07-23 15:15:45 -07:00
|
|
|
if let Some(pos) = pos {
|
|
|
|
let names = if global { &names[1..pos + 1] } else { &names[..pos + 1] };
|
2019-09-14 21:10:12 +01:00
|
|
|
names_to_string(&names.iter().map(|ident| ident.name).collect::<Vec<_>>())
|
2015-03-16 10:44:19 +13:00
|
|
|
} else {
|
2017-07-23 15:15:45 -07:00
|
|
|
let names = if global { &names[1..] } else { names };
|
|
|
|
if names.is_empty() {
|
2020-03-07 19:02:32 +03:00
|
|
|
import_kind_to_string(import_kind)
|
2017-07-23 15:15:45 -07:00
|
|
|
} else {
|
2019-09-14 21:10:12 +01:00
|
|
|
format!(
|
|
|
|
"{}::{}",
|
|
|
|
names_to_string(&names.iter().map(|ident| ident.name).collect::<Vec<_>>()),
|
2020-03-07 19:02:32 +03:00
|
|
|
import_kind_to_string(import_kind),
|
2019-09-14 21:10:12 +01:00
|
|
|
)
|
2017-07-23 15:15:45 -07:00
|
|
|
}
|
2015-03-16 10:44:19 +13:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-07 19:02:32 +03:00
|
|
|
fn import_kind_to_string(import_kind: &ImportKind<'_>) -> String {
|
2020-03-07 18:49:13 +03:00
|
|
|
match import_kind {
|
|
|
|
ImportKind::Single { source, .. } => source.to_string(),
|
|
|
|
ImportKind::Glob { .. } => "*".to_string(),
|
|
|
|
ImportKind::ExternCrate { .. } => "<extern crate>".to_string(),
|
|
|
|
ImportKind::MacroUse => "#[macro_use]".to_string(),
|
2022-10-30 15:55:58 +04:00
|
|
|
ImportKind::MacroExport => "#[macro_export]".to_string(),
|
2015-03-16 10:44:19 +13:00
|
|
|
}
|
|
|
|
}
|