2019-11-24 15:05:12 +00:00
|
|
|
//! The core of the module-level name resolution algorithm.
|
|
|
|
//!
|
|
|
|
//! `DefCollector::collect` contains the fixed-point iteration loop which
|
|
|
|
//! resolves imports and expands macros.
|
2019-09-30 08:58:53 +00:00
|
|
|
|
2022-03-23 17:09:53 +00:00
|
|
|
use std::{iter, mem};
|
2020-09-17 13:28:23 +00:00
|
|
|
|
2022-03-08 20:41:19 +00:00
|
|
|
use base_db::{CrateId, Edition, FileId};
|
2020-10-22 17:19:18 +00:00
|
|
|
use cfg::{CfgExpr, CfgOptions};
|
2022-03-08 20:41:19 +00:00
|
|
|
use either::Either;
|
2019-10-31 15:45:10 +00:00
|
|
|
use hir_expand::{
|
2022-01-07 13:19:11 +00:00
|
|
|
ast_id_map::FileAstId,
|
2023-01-09 18:29:28 +00:00
|
|
|
attrs::{Attr, AttrId},
|
2021-11-17 18:46:32 +00:00
|
|
|
builtin_attr_macro::find_builtin_attr,
|
2021-10-10 12:44:03 +00:00
|
|
|
builtin_derive_macro::find_builtin_derive,
|
|
|
|
builtin_fn_macro::find_builtin_macro,
|
2023-04-19 15:54:01 +00:00
|
|
|
hygiene::Hygiene,
|
2021-06-01 11:39:19 +00:00
|
|
|
name::{name, AsName, Name},
|
2020-03-18 09:47:59 +00:00
|
|
|
proc_macro::ProcMacroExpander,
|
2023-04-16 13:46:12 +00:00
|
|
|
ExpandResult, ExpandTo, HirFileId, InFile, MacroCallId, MacroCallKind, MacroCallLoc,
|
|
|
|
MacroDefId, MacroDefKind,
|
2019-10-31 07:31:29 +00:00
|
|
|
};
|
2022-07-24 12:05:37 +00:00
|
|
|
use itertools::{izip, Itertools};
|
2021-05-25 23:01:58 +00:00
|
|
|
use la_arena::Idx;
|
2021-07-10 20:49:17 +00:00
|
|
|
use limit::Limit;
|
2020-09-18 14:43:50 +00:00
|
|
|
use rustc_hash::{FxHashMap, FxHashSet};
|
2022-06-28 08:41:10 +00:00
|
|
|
use stdx::always;
|
2022-03-09 13:33:39 +00:00
|
|
|
use syntax::{ast, SmolStr};
|
2019-03-02 20:59:04 +00:00
|
|
|
|
|
|
|
use crate::{
|
2023-01-09 18:29:28 +00:00
|
|
|
attr::Attrs,
|
2022-01-06 11:30:16 +00:00
|
|
|
attr_macro_as_call_id,
|
2019-11-23 11:44:43 +00:00
|
|
|
db::DefDatabase,
|
2021-03-19 13:23:13 +00:00
|
|
|
derive_macro_as_call_id,
|
2020-06-26 01:34:39 +00:00
|
|
|
item_scope::{ImportType, PerNsGlobImports},
|
2020-12-15 14:37:37 +00:00
|
|
|
item_tree::{
|
2022-09-21 22:05:30 +00:00
|
|
|
self, Fields, FileItemTreeId, ImportKind, ItemTree, ItemTreeId, ItemTreeNode, MacroCall,
|
|
|
|
MacroDef, MacroRules, Mod, ModItem, ModKind, TreeId,
|
2020-12-15 14:37:37 +00:00
|
|
|
},
|
2022-03-08 20:41:19 +00:00
|
|
|
macro_call_as_call_id, macro_id_to_def_id,
|
2019-03-23 17:41:59 +00:00
|
|
|
nameres::{
|
internal: move diagnostics to hir
The idea here is to eventually get rid of `dyn Diagnostic` and
`DiagnosticSink` infrastructure altogether, and just have a `enum
hir::Diagnostic` instead.
The problem with `dyn Diagnostic` is that it is defined in the lowest
level of the stack (hir_expand), but is used by the highest level (ide).
As a first step, we free hir_expand and hir_def from `dyn Diagnostic`
and kick the can up to `hir_ty`, as an intermediate state. The plan is
then to move DiagnosticSink similarly to the hir crate, and, as final
third step, remove its usage from the ide.
One currently unsolved problem is testing. You can notice that the test
which checks precise diagnostic ranges, unresolved_import_in_use_tree,
was moved to the ide layer. Logically, only IDE should have the infra to
render a specific range.
At the same time, the range is determined with the data produced in
hir_def and hir crates, so this layering is rather unfortunate. Working
on hir_def shouldn't require compiling `ide` for testing.
2021-05-23 20:31:59 +00:00
|
|
|
diagnostics::DefDiagnostic,
|
|
|
|
mod_resolution::ModDir,
|
|
|
|
path_resolution::ReachedFixedPoint,
|
2022-11-07 12:24:17 +00:00
|
|
|
proc_macro::{parse_macro_name_and_helper_attrs, ProcMacroDef, ProcMacroKind},
|
2021-01-18 19:18:05 +00:00
|
|
|
BuiltinShadowMode, DefMap, ModuleData, ModuleOrigin, ResolveMode,
|
2019-03-23 17:41:59 +00:00
|
|
|
},
|
2020-02-02 13:04:06 +00:00
|
|
|
path::{ImportAlias, ModPath, PathKind},
|
2019-11-23 13:53:16 +00:00
|
|
|
per_ns::PerNs,
|
2023-01-31 10:49:49 +00:00
|
|
|
tt,
|
2020-06-15 17:16:14 +00:00
|
|
|
visibility::{RawVisibility, Visibility},
|
2022-03-09 10:26:06 +00:00
|
|
|
AdtId, AstId, AstIdWithPath, ConstLoc, EnumLoc, EnumVariantId, ExternBlockLoc, FunctionId,
|
|
|
|
FunctionLoc, ImplLoc, Intern, ItemContainerId, LocalModuleId, Macro2Id, Macro2Loc,
|
|
|
|
MacroExpander, MacroId, MacroRulesId, MacroRulesLoc, ModuleDefId, ModuleId, ProcMacroId,
|
2023-03-03 15:24:07 +00:00
|
|
|
ProcMacroLoc, StaticLoc, StructLoc, TraitAliasLoc, TraitLoc, TypeAliasLoc, UnionLoc,
|
|
|
|
UnresolvedMacro,
|
2019-03-02 20:59:04 +00:00
|
|
|
};
|
|
|
|
|
2021-10-21 10:21:34 +00:00
|
|
|
static GLOB_RECURSION_LIMIT: Limit = Limit::new(100);
|
|
|
|
static EXPANSION_DEPTH_LIMIT: Limit = Limit::new(128);
|
|
|
|
static FIXED_POINT_LIMIT: Limit = Limit::new(8192);
|
2020-07-15 13:52:32 +00:00
|
|
|
|
2021-11-25 23:17:20 +00:00
|
|
|
pub(super) fn collect_defs(db: &dyn DefDatabase, mut def_map: DefMap, tree_id: TreeId) -> DefMap {
|
2019-10-31 15:45:10 +00:00
|
|
|
let crate_graph = db.crate_graph();
|
|
|
|
|
2021-09-28 19:23:46 +00:00
|
|
|
let mut deps = FxHashMap::default();
|
|
|
|
// populate external prelude and dependency list
|
2022-03-09 13:33:39 +00:00
|
|
|
let krate = &crate_graph[def_map.krate];
|
|
|
|
for dep in &krate.dependencies {
|
2021-09-28 19:23:46 +00:00
|
|
|
tracing::debug!("crate dep {:?} -> {:?}", dep.name, dep.crate_id);
|
|
|
|
let dep_def_map = db.crate_def_map(dep.crate_id);
|
|
|
|
let dep_root = dep_def_map.module_id(dep_def_map.root);
|
|
|
|
|
2022-12-30 08:42:44 +00:00
|
|
|
deps.insert(dep.as_name(), dep_root);
|
2021-09-28 19:23:46 +00:00
|
|
|
|
2021-11-25 23:17:20 +00:00
|
|
|
if dep.is_prelude() && !tree_id.is_block() {
|
2022-03-22 14:54:46 +00:00
|
|
|
def_map.extern_prelude.insert(dep.as_name(), dep_root);
|
2019-03-13 13:04:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-03-09 13:33:39 +00:00
|
|
|
let cfg_options = &krate.cfg_options;
|
2023-03-25 15:42:52 +00:00
|
|
|
|
|
|
|
let is_proc_macro = krate.is_proc_macro;
|
|
|
|
let proc_macros = if is_proc_macro {
|
|
|
|
match db.proc_macros().get(&def_map.krate) {
|
|
|
|
Some(Ok(proc_macros)) => {
|
|
|
|
proc_macros
|
|
|
|
.iter()
|
|
|
|
.enumerate()
|
|
|
|
.map(|(idx, it)| {
|
|
|
|
// FIXME: a hacky way to create a Name from string.
|
|
|
|
let name =
|
|
|
|
tt::Ident { text: it.name.clone(), span: tt::TokenId::unspecified() };
|
|
|
|
(name.as_name(), ProcMacroExpander::new(base_db::ProcMacroId(idx as u32)))
|
|
|
|
})
|
|
|
|
.collect()
|
|
|
|
}
|
|
|
|
Some(Err(e)) => {
|
|
|
|
def_map.proc_macro_loading_error = Some(e.clone().into_boxed_str());
|
|
|
|
Vec::new()
|
|
|
|
}
|
|
|
|
None => {
|
|
|
|
def_map.proc_macro_loading_error =
|
|
|
|
Some("No proc-macros present for crate".to_owned().into_boxed_str());
|
|
|
|
Vec::new()
|
|
|
|
}
|
2022-06-15 15:33:55 +00:00
|
|
|
}
|
2023-03-25 15:42:52 +00:00
|
|
|
} else {
|
|
|
|
vec![]
|
2022-06-15 15:33:55 +00:00
|
|
|
};
|
2019-09-29 22:52:15 +00:00
|
|
|
|
2019-03-02 20:59:04 +00:00
|
|
|
let mut collector = DefCollector {
|
|
|
|
db,
|
2019-03-13 13:04:28 +00:00
|
|
|
def_map,
|
2021-09-28 19:23:46 +00:00
|
|
|
deps,
|
2019-03-13 13:04:28 +00:00
|
|
|
glob_imports: FxHashMap::default(),
|
2019-03-02 20:59:04 +00:00
|
|
|
unresolved_imports: Vec::new(),
|
2022-05-26 10:59:57 +00:00
|
|
|
indeterminate_imports: Vec::new(),
|
2021-05-20 11:12:29 +00:00
|
|
|
unresolved_macros: Vec::new(),
|
2019-10-10 11:45:05 +00:00
|
|
|
mod_dirs: FxHashMap::default(),
|
2019-09-29 22:52:15 +00:00
|
|
|
cfg_options,
|
2020-03-18 12:56:46 +00:00
|
|
|
proc_macros,
|
2020-06-26 01:34:39 +00:00
|
|
|
from_glob_import: Default::default(),
|
2021-05-20 18:18:53 +00:00
|
|
|
skip_attrs: Default::default(),
|
2022-03-09 13:33:39 +00:00
|
|
|
is_proc_macro,
|
2023-04-22 09:22:29 +00:00
|
|
|
hygienes: FxHashMap::default(),
|
2019-03-02 20:59:04 +00:00
|
|
|
};
|
2021-11-25 23:17:20 +00:00
|
|
|
if tree_id.is_block() {
|
|
|
|
collector.seed_with_inner(tree_id);
|
|
|
|
} else {
|
|
|
|
collector.seed_with_top_level();
|
2021-01-21 14:22:17 +00:00
|
|
|
}
|
2019-03-02 20:59:04 +00:00
|
|
|
collector.collect();
|
2021-04-03 21:45:27 +00:00
|
|
|
let mut def_map = collector.finish();
|
|
|
|
def_map.shrink_to_fit();
|
|
|
|
def_map
|
2019-03-02 20:59:04 +00:00
|
|
|
}
|
|
|
|
|
2019-12-07 11:20:41 +00:00
|
|
|
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
|
|
|
enum PartialResolvedImport {
|
|
|
|
/// None of any namespaces is resolved
|
|
|
|
Unresolved,
|
|
|
|
/// One of namespaces is resolved
|
|
|
|
Indeterminate(PerNs),
|
2021-11-17 14:30:12 +00:00
|
|
|
/// All namespaces are resolved, OR it comes from other crate
|
2019-12-07 11:20:41 +00:00
|
|
|
Resolved(PerNs),
|
|
|
|
}
|
|
|
|
|
|
|
|
impl PartialResolvedImport {
|
2021-11-17 14:30:12 +00:00
|
|
|
fn namespaces(self) -> PerNs {
|
2019-12-07 11:20:41 +00:00
|
|
|
match self {
|
|
|
|
PartialResolvedImport::Unresolved => PerNs::none(),
|
2021-11-17 14:30:12 +00:00
|
|
|
PartialResolvedImport::Indeterminate(ns) | PartialResolvedImport::Resolved(ns) => ns,
|
2019-12-07 11:20:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-16 13:47:58 +00:00
|
|
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
|
|
|
enum ImportSource {
|
2021-05-25 23:01:58 +00:00
|
|
|
Import { id: ItemTreeId<item_tree::Import>, use_tree: Idx<ast::UseTree> },
|
2020-09-16 13:47:58 +00:00
|
|
|
ExternCrate(ItemTreeId<item_tree::ExternCrate>),
|
|
|
|
}
|
|
|
|
|
2022-05-26 10:59:57 +00:00
|
|
|
#[derive(Debug, Eq, PartialEq)]
|
2020-06-22 13:07:06 +00:00
|
|
|
struct Import {
|
2022-05-26 10:59:57 +00:00
|
|
|
path: ModPath,
|
2020-11-02 12:13:32 +00:00
|
|
|
alias: Option<ImportAlias>,
|
|
|
|
visibility: RawVisibility,
|
2021-06-28 18:11:58 +00:00
|
|
|
kind: ImportKind,
|
2020-11-02 12:13:32 +00:00
|
|
|
is_prelude: bool,
|
|
|
|
is_extern_crate: bool,
|
|
|
|
is_macro_use: bool,
|
2020-09-16 13:47:58 +00:00
|
|
|
source: ImportSource,
|
2020-06-22 13:07:06 +00:00
|
|
|
}
|
|
|
|
|
2020-06-24 13:36:18 +00:00
|
|
|
impl Import {
|
2020-12-18 19:37:26 +00:00
|
|
|
fn from_use(
|
|
|
|
db: &dyn DefDatabase,
|
|
|
|
krate: CrateId,
|
|
|
|
tree: &ItemTree,
|
|
|
|
id: ItemTreeId<item_tree::Import>,
|
2021-05-25 23:01:58 +00:00
|
|
|
) -> Vec<Self> {
|
2020-09-16 13:47:58 +00:00
|
|
|
let it = &tree[id.value];
|
2020-12-18 19:37:26 +00:00
|
|
|
let attrs = &tree.attrs(db, krate, ModItem::from(id.value).into());
|
2020-06-24 13:36:18 +00:00
|
|
|
let visibility = &tree[it.visibility];
|
2021-05-25 23:01:58 +00:00
|
|
|
let is_prelude = attrs.by_key("prelude_import").exists();
|
|
|
|
|
|
|
|
let mut res = Vec::new();
|
2021-06-28 18:11:58 +00:00
|
|
|
it.use_tree.expand(|idx, path, kind, alias| {
|
2021-05-25 23:01:58 +00:00
|
|
|
res.push(Self {
|
2022-05-26 10:59:57 +00:00
|
|
|
path,
|
2021-05-25 23:01:58 +00:00
|
|
|
alias,
|
|
|
|
visibility: visibility.clone(),
|
2021-06-28 18:11:58 +00:00
|
|
|
kind,
|
2021-05-25 23:01:58 +00:00
|
|
|
is_prelude,
|
|
|
|
is_extern_crate: false,
|
|
|
|
is_macro_use: false,
|
|
|
|
source: ImportSource::Import { id, use_tree: idx },
|
|
|
|
});
|
|
|
|
});
|
|
|
|
res
|
2020-06-22 13:07:06 +00:00
|
|
|
}
|
|
|
|
|
2020-12-18 19:37:26 +00:00
|
|
|
fn from_extern_crate(
|
|
|
|
db: &dyn DefDatabase,
|
|
|
|
krate: CrateId,
|
|
|
|
tree: &ItemTree,
|
|
|
|
id: ItemTreeId<item_tree::ExternCrate>,
|
|
|
|
) -> Self {
|
2020-09-16 13:47:58 +00:00
|
|
|
let it = &tree[id.value];
|
2020-12-18 19:37:26 +00:00
|
|
|
let attrs = &tree.attrs(db, krate, ModItem::from(id.value).into());
|
2020-06-24 13:36:18 +00:00
|
|
|
let visibility = &tree[it.visibility];
|
2020-06-22 13:07:06 +00:00
|
|
|
Self {
|
2022-05-26 10:59:57 +00:00
|
|
|
path: ModPath::from_segments(PathKind::Plain, iter::once(it.name.clone())),
|
2020-06-24 13:36:18 +00:00
|
|
|
alias: it.alias.clone(),
|
|
|
|
visibility: visibility.clone(),
|
2021-06-28 18:11:58 +00:00
|
|
|
kind: ImportKind::Plain,
|
2020-06-22 13:07:06 +00:00
|
|
|
is_prelude: false,
|
|
|
|
is_extern_crate: true,
|
2020-12-18 19:37:26 +00:00
|
|
|
is_macro_use: attrs.by_key("macro_use").exists(),
|
2020-09-16 13:47:58 +00:00
|
|
|
source: ImportSource::ExternCrate(id),
|
2020-06-22 13:07:06 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-05-26 10:59:57 +00:00
|
|
|
#[derive(Debug, Eq, PartialEq)]
|
2019-12-07 11:20:41 +00:00
|
|
|
struct ImportDirective {
|
2022-11-11 10:50:26 +00:00
|
|
|
/// The module this import directive is in.
|
2019-12-07 11:20:41 +00:00
|
|
|
module_id: LocalModuleId,
|
2020-06-12 21:24:26 +00:00
|
|
|
import: Import,
|
2019-12-07 11:20:41 +00:00
|
|
|
status: PartialResolvedImport,
|
|
|
|
}
|
|
|
|
|
2019-12-08 12:33:42 +00:00
|
|
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
|
|
|
struct MacroDirective {
|
|
|
|
module_id: LocalModuleId,
|
2020-03-13 12:57:44 +00:00
|
|
|
depth: usize,
|
2021-03-23 16:23:10 +00:00
|
|
|
kind: MacroDirectiveKind,
|
2021-12-07 16:31:26 +00:00
|
|
|
container: ItemContainerId,
|
2019-12-08 12:33:42 +00:00
|
|
|
}
|
|
|
|
|
2020-02-17 04:57:24 +00:00
|
|
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
2021-03-23 16:23:10 +00:00
|
|
|
enum MacroDirectiveKind {
|
2021-09-05 19:30:06 +00:00
|
|
|
FnLike { ast_id: AstIdWithPath<ast::MacroCall>, expand_to: ExpandTo },
|
2022-01-07 13:19:11 +00:00
|
|
|
Derive { ast_id: AstIdWithPath<ast::Adt>, derive_attr: AttrId, derive_pos: usize },
|
2021-11-26 02:57:25 +00:00
|
|
|
Attr { ast_id: AstIdWithPath<ast::Item>, attr: Attr, mod_item: ModItem, tree: TreeId },
|
2020-02-17 04:57:24 +00:00
|
|
|
}
|
|
|
|
|
2019-03-02 20:59:04 +00:00
|
|
|
/// Walks the tree of module recursively
|
2020-03-13 15:05:46 +00:00
|
|
|
struct DefCollector<'a> {
|
|
|
|
db: &'a dyn DefDatabase,
|
2021-01-18 19:18:05 +00:00
|
|
|
def_map: DefMap,
|
2022-03-22 14:54:46 +00:00
|
|
|
deps: FxHashMap<Name, ModuleId>,
|
2019-12-26 15:00:10 +00:00
|
|
|
glob_imports: FxHashMap<LocalModuleId, Vec<(LocalModuleId, Visibility)>>,
|
2019-12-07 11:20:41 +00:00
|
|
|
unresolved_imports: Vec<ImportDirective>,
|
2022-05-26 10:59:57 +00:00
|
|
|
indeterminate_imports: Vec<ImportDirective>,
|
2021-05-20 11:12:29 +00:00
|
|
|
unresolved_macros: Vec<MacroDirective>,
|
2019-11-23 13:49:53 +00:00
|
|
|
mod_dirs: FxHashMap<LocalModuleId, ModDir>,
|
2019-09-29 22:52:15 +00:00
|
|
|
cfg_options: &'a CfgOptions,
|
2020-09-28 11:02:28 +00:00
|
|
|
/// List of procedural macros defined by this crate. This is read from the dynamic library
|
|
|
|
/// built by the build system, and is the list of proc. macros we can actually expand. It is
|
|
|
|
/// empty when proc. macro support is disabled (in which case we still do name resolution for
|
|
|
|
/// them).
|
2020-03-25 12:14:22 +00:00
|
|
|
proc_macros: Vec<(Name, ProcMacroExpander)>,
|
2022-03-09 13:33:39 +00:00
|
|
|
is_proc_macro: bool,
|
2020-06-26 01:34:39 +00:00
|
|
|
from_glob_import: PerNsGlobImports,
|
2021-05-20 17:56:04 +00:00
|
|
|
/// If we fail to resolve an attribute on a `ModItem`, we fall back to ignoring the attribute.
|
|
|
|
/// This map is used to skip all attributes up to and including the one that failed to resolve,
|
|
|
|
/// in order to not expand them twice.
|
|
|
|
///
|
|
|
|
/// This also stores the attributes to skip when we resolve derive helpers and non-macro
|
|
|
|
/// non-builtin attributes in general.
|
2021-05-20 18:18:53 +00:00
|
|
|
skip_attrs: FxHashMap<InFile<ModItem>, AttrId>,
|
2023-04-22 09:22:29 +00:00
|
|
|
/// `Hygiene` cache, because `Hygiene` construction is expensive.
|
|
|
|
///
|
|
|
|
/// Almost all paths should have been lowered to `ModPath` during `ItemTree` construction.
|
|
|
|
/// However, `DefCollector` still needs to lower paths in attributes, in particular those in
|
|
|
|
/// derive meta item list.
|
|
|
|
hygienes: FxHashMap<HirFileId, Hygiene>,
|
2019-03-02 20:59:04 +00:00
|
|
|
}
|
|
|
|
|
2020-03-13 15:05:46 +00:00
|
|
|
impl DefCollector<'_> {
|
2021-01-21 14:22:17 +00:00
|
|
|
fn seed_with_top_level(&mut self) {
|
2021-10-01 13:30:00 +00:00
|
|
|
let _p = profile::span("seed_with_top_level");
|
|
|
|
|
2020-03-09 10:11:59 +00:00
|
|
|
let file_id = self.db.crate_graph()[self.def_map.krate].root_file_id;
|
2021-03-13 01:24:26 +00:00
|
|
|
let item_tree = self.db.file_item_tree(file_id.into());
|
2019-03-02 20:59:04 +00:00
|
|
|
let module_id = self.def_map.root;
|
2021-05-20 18:40:02 +00:00
|
|
|
|
|
|
|
let attrs = item_tree.top_level_attrs(self.db, self.def_map.krate);
|
|
|
|
if attrs.cfg().map_or(true, |cfg| self.cfg_options.check(&cfg) != Some(false)) {
|
2021-06-01 11:39:19 +00:00
|
|
|
self.inject_prelude(&attrs);
|
|
|
|
|
2021-05-20 18:40:02 +00:00
|
|
|
// Process other crate-level attributes.
|
|
|
|
for attr in &*attrs {
|
|
|
|
let attr_name = match attr.path.as_ident() {
|
|
|
|
Some(name) => name,
|
|
|
|
None => continue,
|
|
|
|
};
|
|
|
|
|
2022-01-27 22:23:09 +00:00
|
|
|
if *attr_name == hir_expand::name![recursion_limit] {
|
2022-03-09 13:33:39 +00:00
|
|
|
if let Some(limit) = attr.string_value() {
|
|
|
|
if let Ok(limit) = limit.parse() {
|
|
|
|
self.def_map.recursion_limit = Some(limit);
|
2022-01-27 22:23:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2022-03-09 13:33:39 +00:00
|
|
|
if *attr_name == hir_expand::name![crate_type] {
|
|
|
|
if let Some("proc-macro") = attr.string_value().map(SmolStr::as_str) {
|
|
|
|
self.is_proc_macro = true;
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2023-01-20 22:09:35 +00:00
|
|
|
if attr_name.as_text().as_deref() == Some("rustc_coherence_is_core") {
|
|
|
|
self.def_map.rustc_coherence_is_core = true;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2022-09-02 07:52:58 +00:00
|
|
|
if *attr_name == hir_expand::name![feature] {
|
2023-04-22 09:22:29 +00:00
|
|
|
let hygiene = &Hygiene::new_unhygienic();
|
2023-04-19 15:54:01 +00:00
|
|
|
let features = attr
|
2023-04-22 09:22:29 +00:00
|
|
|
.parse_path_comma_token_tree(self.db.upcast(), hygiene)
|
2023-04-19 15:54:01 +00:00
|
|
|
.into_iter()
|
|
|
|
.flatten()
|
|
|
|
.filter_map(|feat| match feat.segments() {
|
|
|
|
[name] => Some(name.to_smol_str()),
|
|
|
|
_ => None,
|
|
|
|
});
|
2022-09-02 07:52:58 +00:00
|
|
|
self.def_map.unstable_features.extend(features);
|
|
|
|
}
|
|
|
|
|
2021-11-17 14:30:12 +00:00
|
|
|
let attr_is_register_like = *attr_name == hir_expand::name![register_attr]
|
|
|
|
|| *attr_name == hir_expand::name![register_tool];
|
|
|
|
if !attr_is_register_like {
|
2021-05-20 18:40:02 +00:00
|
|
|
continue;
|
2021-11-17 14:30:12 +00:00
|
|
|
}
|
|
|
|
|
2022-03-09 13:33:39 +00:00
|
|
|
let registered_name = match attr.single_ident_value() {
|
|
|
|
Some(ident) => ident.as_name(),
|
2021-11-17 14:30:12 +00:00
|
|
|
_ => continue,
|
2021-05-20 18:40:02 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
if *attr_name == hir_expand::name![register_attr] {
|
2022-01-06 11:30:16 +00:00
|
|
|
self.def_map.registered_attrs.push(registered_name.to_smol_str());
|
2021-05-20 18:40:02 +00:00
|
|
|
cov_mark::hit!(register_attr);
|
|
|
|
} else {
|
2022-01-06 11:30:16 +00:00
|
|
|
self.def_map.registered_tools.push(registered_name.to_smol_str());
|
2021-05-20 18:40:02 +00:00
|
|
|
cov_mark::hit!(register_tool);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-17 23:23:46 +00:00
|
|
|
ModCollector {
|
2021-11-17 14:30:12 +00:00
|
|
|
def_collector: self,
|
2020-12-17 23:23:46 +00:00
|
|
|
macro_depth: 0,
|
|
|
|
module_id,
|
2021-07-19 12:53:18 +00:00
|
|
|
tree_id: TreeId::new(file_id.into(), None),
|
2020-12-17 23:23:46 +00:00
|
|
|
item_tree: &item_tree,
|
|
|
|
mod_dir: ModDir::root(),
|
|
|
|
}
|
2021-12-07 16:31:26 +00:00
|
|
|
.collect_in_top_module(item_tree.top_level_items());
|
2019-03-02 20:59:04 +00:00
|
|
|
}
|
2021-01-21 14:22:17 +00:00
|
|
|
}
|
|
|
|
|
2021-11-25 23:17:20 +00:00
|
|
|
fn seed_with_inner(&mut self, tree_id: TreeId) {
|
|
|
|
let item_tree = tree_id.item_tree(self.db);
|
2021-01-21 14:22:17 +00:00
|
|
|
let module_id = self.def_map.root;
|
2021-11-17 14:30:12 +00:00
|
|
|
|
|
|
|
let is_cfg_enabled = item_tree
|
2021-01-21 14:22:17 +00:00
|
|
|
.top_level_attrs(self.db, self.def_map.krate)
|
|
|
|
.cfg()
|
2021-11-17 14:30:12 +00:00
|
|
|
.map_or(true, |cfg| self.cfg_options.check(&cfg) != Some(false));
|
|
|
|
if is_cfg_enabled {
|
2021-01-21 14:22:17 +00:00
|
|
|
ModCollector {
|
2021-11-17 14:30:12 +00:00
|
|
|
def_collector: self,
|
2021-01-21 14:22:17 +00:00
|
|
|
macro_depth: 0,
|
|
|
|
module_id,
|
2021-11-25 23:17:20 +00:00
|
|
|
tree_id,
|
2021-01-21 14:22:17 +00:00
|
|
|
item_tree: &item_tree,
|
|
|
|
mod_dir: ModDir::root(),
|
|
|
|
}
|
2021-12-07 16:31:26 +00:00
|
|
|
.collect_in_top_module(item_tree.top_level_items());
|
2021-01-21 14:22:17 +00:00
|
|
|
}
|
|
|
|
}
|
2019-03-02 20:59:04 +00:00
|
|
|
|
2021-10-01 13:30:00 +00:00
|
|
|
fn resolution_loop(&mut self) {
|
|
|
|
let _p = profile::span("DefCollector::resolution_loop");
|
|
|
|
|
2019-03-02 20:59:04 +00:00
|
|
|
// main name resolution fixed-point loop.
|
|
|
|
let mut i = 0;
|
2022-05-26 10:59:57 +00:00
|
|
|
'resolve_attr: loop {
|
|
|
|
'resolve_macros: loop {
|
2021-05-17 17:07:10 +00:00
|
|
|
self.db.unwind_if_cancelled();
|
2022-05-26 10:59:57 +00:00
|
|
|
|
2021-10-01 13:30:00 +00:00
|
|
|
{
|
|
|
|
let _p = profile::span("resolve_imports loop");
|
2022-05-26 10:59:57 +00:00
|
|
|
|
|
|
|
'resolve_imports: loop {
|
2021-10-01 13:30:00 +00:00
|
|
|
if self.resolve_imports() == ReachedFixedPoint::Yes {
|
2022-05-26 10:59:57 +00:00
|
|
|
break 'resolve_imports;
|
2021-10-01 13:30:00 +00:00
|
|
|
}
|
2021-05-19 16:56:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if self.resolve_macros() == ReachedFixedPoint::Yes {
|
2022-05-26 10:59:57 +00:00
|
|
|
break 'resolve_macros;
|
2021-05-19 16:56:00 +00:00
|
|
|
}
|
2019-12-07 11:20:41 +00:00
|
|
|
|
2021-05-19 16:56:00 +00:00
|
|
|
i += 1;
|
2021-07-10 20:49:17 +00:00
|
|
|
if FIXED_POINT_LIMIT.check(i).is_err() {
|
2021-08-15 12:46:13 +00:00
|
|
|
tracing::error!("name resolution is stuck");
|
2022-05-26 10:59:57 +00:00
|
|
|
break 'resolve_attr;
|
2021-05-19 16:56:00 +00:00
|
|
|
}
|
2019-03-02 20:59:04 +00:00
|
|
|
}
|
2021-05-19 16:56:00 +00:00
|
|
|
|
2021-05-20 17:56:04 +00:00
|
|
|
if self.reseed_with_unresolved_attribute() == ReachedFixedPoint::Yes {
|
2022-05-26 10:59:57 +00:00
|
|
|
break 'resolve_attr;
|
2019-03-02 20:59:04 +00:00
|
|
|
}
|
|
|
|
}
|
2021-10-01 13:30:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn collect(&mut self) {
|
|
|
|
let _p = profile::span("DefCollector::collect");
|
|
|
|
|
|
|
|
self.resolution_loop();
|
2019-03-14 08:53:40 +00:00
|
|
|
|
2019-12-07 11:20:41 +00:00
|
|
|
// Resolve all indeterminate resolved imports again
|
|
|
|
// As some of the macros will expand newly import shadowing partial resolved imports
|
2021-01-08 14:46:48 +00:00
|
|
|
// FIXME: We maybe could skip this, if we handle the indeterminate imports in `resolve_imports`
|
2019-12-07 11:20:41 +00:00
|
|
|
// correctly
|
2022-07-16 09:17:15 +00:00
|
|
|
let partial_resolved = self.indeterminate_imports.drain(..).map(|directive| {
|
|
|
|
ImportDirective { status: PartialResolvedImport::Unresolved, ..directive }
|
2019-12-07 11:20:41 +00:00
|
|
|
});
|
|
|
|
self.unresolved_imports.extend(partial_resolved);
|
|
|
|
self.resolve_imports();
|
|
|
|
|
2022-03-23 17:09:53 +00:00
|
|
|
let unresolved_imports = mem::take(&mut self.unresolved_imports);
|
2019-03-14 08:53:40 +00:00
|
|
|
// show unresolved imports in completion, etc
|
2020-09-16 13:47:58 +00:00
|
|
|
for directive in &unresolved_imports {
|
2022-03-23 17:09:53 +00:00
|
|
|
self.record_resolved_import(directive);
|
2019-03-14 08:53:40 +00:00
|
|
|
}
|
2020-09-16 13:47:58 +00:00
|
|
|
self.unresolved_imports = unresolved_imports;
|
2020-09-18 15:50:04 +00:00
|
|
|
|
2022-03-09 13:33:39 +00:00
|
|
|
if self.is_proc_macro {
|
2020-09-18 15:50:04 +00:00
|
|
|
// A crate exporting procedural macros is not allowed to export anything else.
|
|
|
|
//
|
|
|
|
// Additionally, while the proc macro entry points must be `pub`, they are not publicly
|
|
|
|
// exported in type/value namespace. This function reduces the visibility of all items
|
|
|
|
// in the crate root that aren't proc macros.
|
|
|
|
let root = self.def_map.root;
|
2021-01-25 14:21:33 +00:00
|
|
|
let module_id = self.def_map.module_id(root);
|
2020-09-18 15:50:04 +00:00
|
|
|
let root = &mut self.def_map.modules[root];
|
2021-01-25 14:21:33 +00:00
|
|
|
root.scope.censor_non_proc_macros(module_id);
|
2020-09-18 15:50:04 +00:00
|
|
|
}
|
2019-03-02 20:59:04 +00:00
|
|
|
}
|
|
|
|
|
2022-06-24 12:19:18 +00:00
|
|
|
/// When the fixed-point loop reaches a stable state, we might still have
|
|
|
|
/// some unresolved attributes left over. This takes one of them, and feeds
|
|
|
|
/// the item it's applied to back into name resolution.
|
2021-05-19 13:17:57 +00:00
|
|
|
///
|
|
|
|
/// This effectively ignores the fact that the macro is there and just treats the items as
|
|
|
|
/// normal code.
|
|
|
|
///
|
2022-06-24 12:19:18 +00:00
|
|
|
/// This improves UX for unresolved attributes, and replicates the
|
|
|
|
/// behavior before we supported proc. attribute macros.
|
2021-05-20 17:56:04 +00:00
|
|
|
fn reseed_with_unresolved_attribute(&mut self) -> ReachedFixedPoint {
|
2021-05-19 19:05:58 +00:00
|
|
|
cov_mark::hit!(unresolved_attribute_fallback);
|
|
|
|
|
2022-07-16 09:17:15 +00:00
|
|
|
let unresolved_attr =
|
|
|
|
self.unresolved_macros.iter().enumerate().find_map(|(idx, directive)| match &directive
|
|
|
|
.kind
|
|
|
|
{
|
|
|
|
MacroDirectiveKind::Attr { ast_id, mod_item, attr, tree } => {
|
|
|
|
self.def_map.diagnostics.push(DefDiagnostic::unresolved_macro_call(
|
|
|
|
directive.module_id,
|
|
|
|
MacroCallKind::Attr {
|
|
|
|
ast_id: ast_id.ast_id,
|
2023-01-31 10:49:49 +00:00
|
|
|
attr_args: std::sync::Arc::new((
|
|
|
|
tt::Subtree::empty(),
|
|
|
|
Default::default(),
|
|
|
|
)),
|
2023-01-09 19:47:51 +00:00
|
|
|
invoc_attr_index: attr.id,
|
2022-07-16 09:17:15 +00:00
|
|
|
},
|
|
|
|
attr.path().clone(),
|
|
|
|
));
|
|
|
|
|
|
|
|
self.skip_attrs.insert(ast_id.ast_id.with_value(*mod_item), attr.id);
|
|
|
|
|
|
|
|
Some((idx, directive, *mod_item, *tree))
|
|
|
|
}
|
|
|
|
_ => None,
|
|
|
|
});
|
2021-05-19 13:17:57 +00:00
|
|
|
|
2022-07-16 09:17:15 +00:00
|
|
|
match unresolved_attr {
|
|
|
|
Some((pos, &MacroDirective { module_id, depth, container, .. }, mod_item, tree_id)) => {
|
|
|
|
let item_tree = &tree_id.item_tree(self.db);
|
|
|
|
let mod_dir = self.mod_dirs[&module_id].clone();
|
2021-05-19 13:17:57 +00:00
|
|
|
ModCollector {
|
2021-11-17 14:30:12 +00:00
|
|
|
def_collector: self,
|
2022-07-16 09:17:15 +00:00
|
|
|
macro_depth: depth,
|
|
|
|
module_id,
|
|
|
|
tree_id,
|
|
|
|
item_tree,
|
2021-05-19 13:17:57 +00:00
|
|
|
mod_dir,
|
|
|
|
}
|
2022-07-16 09:17:15 +00:00
|
|
|
.collect(&[mod_item], container);
|
2021-05-19 13:17:57 +00:00
|
|
|
|
2022-07-16 09:17:15 +00:00
|
|
|
self.unresolved_macros.swap_remove(pos);
|
|
|
|
// Continue name resolution with the new data.
|
|
|
|
ReachedFixedPoint::No
|
|
|
|
}
|
|
|
|
None => ReachedFixedPoint::Yes,
|
2021-05-19 13:17:57 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-01 11:39:19 +00:00
|
|
|
fn inject_prelude(&mut self, crate_attrs: &Attrs) {
|
|
|
|
// See compiler/rustc_builtin_macros/src/standard_library_imports.rs
|
|
|
|
|
|
|
|
if crate_attrs.by_key("no_core").exists() {
|
|
|
|
// libcore does not get a prelude.
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
let krate = if crate_attrs.by_key("no_std").exists() {
|
|
|
|
name![core]
|
|
|
|
} else {
|
|
|
|
let std = name![std];
|
|
|
|
if self.def_map.extern_prelude().any(|(name, _)| *name == std) {
|
|
|
|
std
|
|
|
|
} else {
|
|
|
|
// If `std` does not exist for some reason, fall back to core. This mostly helps
|
|
|
|
// keep r-a's own tests minimal.
|
|
|
|
name![core]
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
let edition = match self.def_map.edition {
|
|
|
|
Edition::Edition2015 => name![rust_2015],
|
|
|
|
Edition::Edition2018 => name![rust_2018],
|
|
|
|
Edition::Edition2021 => name![rust_2021],
|
|
|
|
};
|
|
|
|
|
2022-09-02 15:43:20 +00:00
|
|
|
let path_kind = match self.def_map.edition {
|
|
|
|
Edition::Edition2015 => PathKind::Plain,
|
|
|
|
_ => PathKind::Abs,
|
2021-06-01 11:39:19 +00:00
|
|
|
};
|
2022-03-12 14:30:07 +00:00
|
|
|
let path =
|
|
|
|
ModPath::from_segments(path_kind, [krate.clone(), name![prelude], edition].into_iter());
|
2021-06-01 17:03:00 +00:00
|
|
|
// Fall back to the older `std::prelude::v1` for compatibility with Rust <1.52.0
|
|
|
|
// FIXME remove this fallback
|
|
|
|
let fallback_path =
|
2021-10-22 06:23:29 +00:00
|
|
|
ModPath::from_segments(path_kind, [krate, name![prelude], name![v1]].into_iter());
|
2021-06-01 17:03:00 +00:00
|
|
|
|
|
|
|
for path in &[path, fallback_path] {
|
|
|
|
let (per_ns, _) = self.def_map.resolve_path(
|
|
|
|
self.db,
|
|
|
|
self.def_map.root,
|
2021-06-13 03:54:16 +00:00
|
|
|
path,
|
2021-06-01 17:03:00 +00:00
|
|
|
BuiltinShadowMode::Other,
|
|
|
|
);
|
|
|
|
|
2021-11-17 14:30:12 +00:00
|
|
|
match per_ns.types {
|
2021-06-01 17:03:00 +00:00
|
|
|
Some((ModuleDefId::ModuleId(m), _)) => {
|
2021-11-17 14:30:12 +00:00
|
|
|
self.def_map.prelude = Some(m);
|
2022-09-15 10:12:22 +00:00
|
|
|
break;
|
2021-06-01 17:03:00 +00:00
|
|
|
}
|
2021-11-17 14:30:12 +00:00
|
|
|
types => {
|
2021-08-15 12:46:13 +00:00
|
|
|
tracing::debug!(
|
2021-06-01 17:03:00 +00:00
|
|
|
"could not resolve prelude path `{}` to module (resolved to {:?})",
|
|
|
|
path,
|
2021-11-17 14:30:12 +00:00
|
|
|
types
|
2021-06-01 17:03:00 +00:00
|
|
|
);
|
|
|
|
}
|
2021-06-01 11:39:19 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-28 11:02:28 +00:00
|
|
|
/// Adds a definition of procedural macro `name` to the root module.
|
|
|
|
///
|
|
|
|
/// # Notes on procedural macro resolution
|
|
|
|
///
|
|
|
|
/// Procedural macro functionality is provided by the build system: It has to build the proc
|
|
|
|
/// macro and pass the resulting dynamic library to rust-analyzer.
|
|
|
|
///
|
|
|
|
/// When procedural macro support is enabled, the list of proc macros exported by a crate is
|
|
|
|
/// known before we resolve names in the crate. This list is stored in `self.proc_macros` and is
|
|
|
|
/// derived from the dynamic library.
|
|
|
|
///
|
|
|
|
/// However, we *also* would like to be able to at least *resolve* macros on our own, without
|
|
|
|
/// help by the build system. So, when the macro isn't found in `self.proc_macros`, we instead
|
|
|
|
/// use a dummy expander that always errors. This comes with the drawback of macros potentially
|
|
|
|
/// going out of sync with what the build system sees (since we resolve using VFS state, but
|
|
|
|
/// Cargo builds only on-disk files). We could and probably should add diagnostics for that.
|
2022-03-08 20:41:19 +00:00
|
|
|
fn export_proc_macro(
|
|
|
|
&mut self,
|
|
|
|
def: ProcMacroDef,
|
|
|
|
id: ItemTreeId<item_tree::Function>,
|
2022-03-09 10:26:06 +00:00
|
|
|
fn_id: FunctionId,
|
2022-03-08 20:41:19 +00:00
|
|
|
module_id: ModuleId,
|
|
|
|
) {
|
2022-03-08 23:01:19 +00:00
|
|
|
let kind = def.kind.to_basedb_kind();
|
2022-03-08 20:41:19 +00:00
|
|
|
let (expander, kind) = match self.proc_macros.iter().find(|(n, _)| n == &def.name) {
|
|
|
|
Some(&(_, expander)) => (expander, kind),
|
2023-03-13 15:49:32 +00:00
|
|
|
None => (ProcMacroExpander::dummy(), kind),
|
2020-09-18 14:43:50 +00:00
|
|
|
};
|
|
|
|
|
2022-03-08 20:41:19 +00:00
|
|
|
let proc_macro_id =
|
|
|
|
ProcMacroLoc { container: module_id, id, expander, kind }.intern(self.db);
|
2022-03-12 12:43:53 +00:00
|
|
|
self.define_proc_macro(def.name.clone(), proc_macro_id);
|
2022-03-08 23:01:19 +00:00
|
|
|
if let ProcMacroKind::CustomDerive { helpers } = def.kind {
|
|
|
|
self.def_map
|
|
|
|
.exported_derives
|
|
|
|
.insert(macro_id_to_def_id(self.db, proc_macro_id.into()), helpers);
|
|
|
|
}
|
2022-03-09 10:26:06 +00:00
|
|
|
self.def_map.fn_proc_macro_mapping.insert(fn_id, proc_macro_id);
|
2020-09-18 14:43:50 +00:00
|
|
|
}
|
|
|
|
|
2019-09-09 12:54:02 +00:00
|
|
|
/// Define a macro with `macro_rules`.
|
|
|
|
///
|
|
|
|
/// It will define the macro in legacy textual scope, and if it has `#[macro_export]`,
|
|
|
|
/// then it is also defined in the root module scope.
|
|
|
|
/// You can `use` or invoke it by `crate::macro_name` anywhere, before or after the definition.
|
|
|
|
///
|
|
|
|
/// It is surprising that the macro will never be in the current module scope.
|
|
|
|
/// These code fails with "unresolved import/macro",
|
|
|
|
/// ```rust,compile_fail
|
|
|
|
/// mod m { macro_rules! foo { () => {} } }
|
|
|
|
/// use m::foo as bar;
|
|
|
|
/// ```
|
|
|
|
///
|
|
|
|
/// ```rust,compile_fail
|
|
|
|
/// macro_rules! foo { () => {} }
|
|
|
|
/// self::foo!();
|
|
|
|
/// crate::foo!();
|
|
|
|
/// ```
|
|
|
|
///
|
2019-11-17 15:35:05 +00:00
|
|
|
/// Well, this code compiles, because the plain path `foo` in `use` is searched
|
2019-09-09 12:54:02 +00:00
|
|
|
/// in the legacy textual scope only.
|
|
|
|
/// ```rust
|
|
|
|
/// macro_rules! foo { () => {} }
|
|
|
|
/// use foo as bar;
|
|
|
|
/// ```
|
2021-03-27 05:44:54 +00:00
|
|
|
fn define_macro_rules(
|
2019-06-08 17:42:02 +00:00
|
|
|
&mut self,
|
2019-11-23 13:49:53 +00:00
|
|
|
module_id: LocalModuleId,
|
2019-06-08 17:42:02 +00:00
|
|
|
name: Name,
|
2022-03-08 20:41:19 +00:00
|
|
|
macro_: MacroRulesId,
|
2019-06-08 17:42:02 +00:00
|
|
|
export: bool,
|
|
|
|
) {
|
2019-09-09 12:54:02 +00:00
|
|
|
// Textual scoping
|
2022-03-23 13:30:04 +00:00
|
|
|
self.define_legacy_macro(module_id, name.clone(), macro_.into());
|
2019-06-08 17:42:02 +00:00
|
|
|
|
2019-09-09 12:54:02 +00:00
|
|
|
// Module scoping
|
2019-06-08 17:42:02 +00:00
|
|
|
// In Rust, `#[macro_export]` macros are unconditionally visible at the
|
|
|
|
// crate root, even if the parent modules is **not** visible.
|
2019-03-26 10:09:39 +00:00
|
|
|
if export {
|
2022-03-08 23:19:53 +00:00
|
|
|
let module_id = self.def_map.root;
|
|
|
|
self.def_map.modules[module_id].scope.declare(macro_.into());
|
2019-12-25 14:00:10 +00:00
|
|
|
self.update(
|
2022-03-08 23:19:53 +00:00
|
|
|
module_id,
|
|
|
|
&[(Some(name), PerNs::macros(macro_.into(), Visibility::Public))],
|
2019-12-26 15:00:10 +00:00
|
|
|
Visibility::Public,
|
2020-06-25 16:42:12 +00:00
|
|
|
ImportType::Named,
|
2019-12-25 14:00:10 +00:00
|
|
|
);
|
2019-03-02 20:59:04 +00:00
|
|
|
}
|
2019-09-06 16:55:58 +00:00
|
|
|
}
|
|
|
|
|
2019-09-07 16:37:54 +00:00
|
|
|
/// Define a legacy textual scoped macro in module
|
2019-09-06 16:55:58 +00:00
|
|
|
///
|
2019-12-20 15:19:28 +00:00
|
|
|
/// We use a map `legacy_macros` to store all legacy textual scoped macros visible per module.
|
2019-09-07 16:37:54 +00:00
|
|
|
/// It will clone all macros from parent legacy scope, whose definition is prior to
|
2019-09-06 16:55:58 +00:00
|
|
|
/// the definition of current module.
|
2019-12-20 15:19:28 +00:00
|
|
|
/// And also, `macro_use` on a module will import all legacy macros visible inside to
|
2019-09-07 16:37:54 +00:00
|
|
|
/// current legacy scope, with possible shadowing.
|
2022-03-23 13:30:04 +00:00
|
|
|
fn define_legacy_macro(&mut self, module_id: LocalModuleId, name: Name, mac: MacroId) {
|
2019-09-06 16:55:58 +00:00
|
|
|
// Always shadowing
|
2019-12-20 16:09:13 +00:00
|
|
|
self.def_map.modules[module_id].scope.define_legacy_macro(name, mac);
|
2019-03-02 20:59:04 +00:00
|
|
|
}
|
|
|
|
|
2021-03-27 05:44:54 +00:00
|
|
|
/// Define a macro 2.0 macro
|
|
|
|
///
|
|
|
|
/// The scoped of macro 2.0 macro is equal to normal function
|
|
|
|
fn define_macro_def(
|
|
|
|
&mut self,
|
|
|
|
module_id: LocalModuleId,
|
|
|
|
name: Name,
|
2022-03-08 20:41:19 +00:00
|
|
|
macro_: Macro2Id,
|
2021-03-27 05:44:54 +00:00
|
|
|
vis: &RawVisibility,
|
|
|
|
) {
|
2023-02-19 14:30:49 +00:00
|
|
|
let vis = self
|
|
|
|
.def_map
|
|
|
|
.resolve_visibility(self.db, module_id, vis, false)
|
|
|
|
.unwrap_or(Visibility::Public);
|
2022-03-08 23:19:53 +00:00
|
|
|
self.def_map.modules[module_id].scope.declare(macro_.into());
|
|
|
|
self.update(
|
|
|
|
module_id,
|
|
|
|
&[(Some(name), PerNs::macros(macro_.into(), Visibility::Public))],
|
|
|
|
vis,
|
|
|
|
ImportType::Named,
|
|
|
|
);
|
2021-03-27 05:44:54 +00:00
|
|
|
}
|
|
|
|
|
2020-03-18 09:47:59 +00:00
|
|
|
/// Define a proc macro
|
|
|
|
///
|
2021-01-08 14:46:48 +00:00
|
|
|
/// A proc macro is similar to normal macro scope, but it would not visible in legacy textual scoped.
|
2020-03-18 09:47:59 +00:00
|
|
|
/// And unconditionally exported.
|
2022-03-08 20:41:19 +00:00
|
|
|
fn define_proc_macro(&mut self, name: Name, macro_: ProcMacroId) {
|
2022-03-08 23:19:53 +00:00
|
|
|
let module_id = self.def_map.root;
|
|
|
|
self.def_map.modules[module_id].scope.declare(macro_.into());
|
2020-03-18 09:47:59 +00:00
|
|
|
self.update(
|
2022-03-08 23:19:53 +00:00
|
|
|
module_id,
|
|
|
|
&[(Some(name), PerNs::macros(macro_.into(), Visibility::Public))],
|
2020-03-18 09:47:59 +00:00
|
|
|
Visibility::Public,
|
2020-06-25 16:42:12 +00:00
|
|
|
ImportType::Named,
|
2020-03-18 09:47:59 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2019-09-05 03:35:13 +00:00
|
|
|
/// Import macros from `#[macro_use] extern crate`.
|
2019-09-06 16:55:58 +00:00
|
|
|
fn import_macros_from_extern_crate(
|
|
|
|
&mut self,
|
2019-11-23 13:49:53 +00:00
|
|
|
current_module_id: LocalModuleId,
|
2020-09-17 13:28:23 +00:00
|
|
|
extern_crate: &item_tree::ExternCrate,
|
2019-09-06 16:55:58 +00:00
|
|
|
) {
|
2021-08-15 12:46:13 +00:00
|
|
|
tracing::debug!(
|
2019-09-05 03:35:13 +00:00
|
|
|
"importing macros from extern crate: {:?} ({:?})",
|
2020-09-17 13:28:23 +00:00
|
|
|
extern_crate,
|
2019-09-05 03:35:13 +00:00
|
|
|
self.def_map.edition,
|
|
|
|
);
|
|
|
|
|
2022-03-22 14:54:46 +00:00
|
|
|
if let Some(m) = self.resolve_extern_crate(&extern_crate.name) {
|
2021-05-16 18:05:52 +00:00
|
|
|
if m == self.def_map.module_id(current_module_id) {
|
2021-05-17 09:37:24 +00:00
|
|
|
cov_mark::hit!(ignore_macro_use_extern_crate_self);
|
2021-05-16 18:05:52 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-03-08 20:19:44 +00:00
|
|
|
cov_mark::hit!(macro_rules_from_other_crates_are_visible_with_macro_use);
|
2019-10-31 15:45:10 +00:00
|
|
|
self.import_all_macros_exported(current_module_id, m.krate);
|
2019-09-05 08:20:36 +00:00
|
|
|
}
|
|
|
|
}
|
2019-09-05 03:35:13 +00:00
|
|
|
|
2019-09-09 12:54:02 +00:00
|
|
|
/// Import all exported macros from another crate
|
|
|
|
///
|
|
|
|
/// Exported macros are just all macros in the root module scope.
|
|
|
|
/// Note that it contains not only all `#[macro_export]` macros, but also all aliases
|
|
|
|
/// created by `use` in the root module, ignoring the visibility of `use`.
|
2019-11-23 13:49:53 +00:00
|
|
|
fn import_all_macros_exported(&mut self, current_module_id: LocalModuleId, krate: CrateId) {
|
2019-09-09 12:54:02 +00:00
|
|
|
let def_map = self.db.crate_def_map(krate);
|
|
|
|
for (name, def) in def_map[def_map.root].scope.macros() {
|
2022-03-23 13:30:04 +00:00
|
|
|
// `#[macro_use]` brings macros into legacy scope. Yes, even non-`macro_rules!` macros.
|
|
|
|
self.define_legacy_macro(current_module_id, name.clone(), def);
|
2019-09-05 03:35:13 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-19 16:56:00 +00:00
|
|
|
/// Tries to resolve every currently unresolved import.
|
|
|
|
fn resolve_imports(&mut self) -> ReachedFixedPoint {
|
|
|
|
let mut res = ReachedFixedPoint::Yes;
|
2022-03-23 17:09:53 +00:00
|
|
|
let imports = mem::take(&mut self.unresolved_imports);
|
2022-07-16 09:17:15 +00:00
|
|
|
|
|
|
|
self.unresolved_imports = imports
|
2021-05-19 17:05:03 +00:00
|
|
|
.into_iter()
|
|
|
|
.filter_map(|mut directive| {
|
2019-12-07 11:20:41 +00:00
|
|
|
directive.status = self.resolve_import(directive.module_id, &directive.import);
|
|
|
|
match directive.status {
|
|
|
|
PartialResolvedImport::Indeterminate(_) => {
|
|
|
|
self.record_resolved_import(&directive);
|
2022-05-26 10:59:57 +00:00
|
|
|
self.indeterminate_imports.push(directive);
|
2021-05-19 17:05:03 +00:00
|
|
|
res = ReachedFixedPoint::No;
|
|
|
|
None
|
2019-12-07 11:20:41 +00:00
|
|
|
}
|
|
|
|
PartialResolvedImport::Resolved(_) => {
|
|
|
|
self.record_resolved_import(&directive);
|
2021-05-19 17:05:03 +00:00
|
|
|
res = ReachedFixedPoint::No;
|
|
|
|
None
|
2019-12-07 11:20:41 +00:00
|
|
|
}
|
2021-05-19 17:05:03 +00:00
|
|
|
PartialResolvedImport::Unresolved => Some(directive),
|
2019-12-07 11:20:41 +00:00
|
|
|
}
|
2021-05-19 17:05:03 +00:00
|
|
|
})
|
|
|
|
.collect();
|
2021-05-19 16:56:00 +00:00
|
|
|
res
|
2019-03-02 20:59:04 +00:00
|
|
|
}
|
|
|
|
|
2020-06-12 21:24:26 +00:00
|
|
|
fn resolve_import(&self, module_id: LocalModuleId, import: &Import) -> PartialResolvedImport {
|
2021-10-01 13:30:00 +00:00
|
|
|
let _p = profile::span("resolve_import").detail(|| format!("{}", import.path));
|
2021-08-15 12:46:13 +00:00
|
|
|
tracing::debug!("resolving import: {:?} ({:?})", import, self.def_map.edition);
|
2019-03-13 13:04:28 +00:00
|
|
|
if import.is_extern_crate {
|
2021-09-28 19:23:46 +00:00
|
|
|
let name = import
|
|
|
|
.path
|
|
|
|
.as_ident()
|
|
|
|
.expect("extern crate should have been desugared to one-element path");
|
|
|
|
|
|
|
|
let res = self.resolve_extern_crate(name);
|
|
|
|
|
2022-03-22 14:54:46 +00:00
|
|
|
match res {
|
|
|
|
Some(res) => {
|
|
|
|
PartialResolvedImport::Resolved(PerNs::types(res.into(), Visibility::Public))
|
|
|
|
}
|
|
|
|
None => PartialResolvedImport::Unresolved,
|
2020-09-16 13:46:56 +00:00
|
|
|
}
|
2019-03-13 13:04:28 +00:00
|
|
|
} else {
|
2019-05-26 12:10:56 +00:00
|
|
|
let res = self.def_map.resolve_path_fp_with_macro(
|
|
|
|
self.db,
|
|
|
|
ResolveMode::Import,
|
|
|
|
module_id,
|
|
|
|
&import.path,
|
2019-11-30 15:29:21 +00:00
|
|
|
BuiltinShadowMode::Module,
|
2019-05-26 12:10:56 +00:00
|
|
|
);
|
2019-03-13 13:04:28 +00:00
|
|
|
|
2019-12-07 11:20:41 +00:00
|
|
|
let def = res.resolved_def;
|
2020-01-11 22:19:58 +00:00
|
|
|
if res.reached_fixedpoint == ReachedFixedPoint::No || def.is_none() {
|
2019-12-07 11:20:41 +00:00
|
|
|
return PartialResolvedImport::Unresolved;
|
|
|
|
}
|
|
|
|
|
|
|
|
if let Some(krate) = res.krate {
|
|
|
|
if krate != self.def_map.krate {
|
2021-07-21 15:51:56 +00:00
|
|
|
return PartialResolvedImport::Resolved(
|
|
|
|
def.filter_visibility(|v| matches!(v, Visibility::Public)),
|
|
|
|
);
|
2019-12-07 11:20:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check whether all namespace is resolved
|
|
|
|
if def.take_types().is_some()
|
|
|
|
&& def.take_values().is_some()
|
|
|
|
&& def.take_macros().is_some()
|
|
|
|
{
|
|
|
|
PartialResolvedImport::Resolved(def)
|
|
|
|
} else {
|
|
|
|
PartialResolvedImport::Indeterminate(def)
|
|
|
|
}
|
2019-03-13 13:04:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-03-22 14:54:46 +00:00
|
|
|
fn resolve_extern_crate(&self, name: &Name) -> Option<ModuleId> {
|
2021-11-17 18:46:32 +00:00
|
|
|
if *name == name!(self) {
|
2021-09-28 19:23:46 +00:00
|
|
|
cov_mark::hit!(extern_crate_self_as);
|
2021-11-17 14:30:12 +00:00
|
|
|
let root = match self.def_map.block {
|
|
|
|
Some(_) => {
|
|
|
|
let def_map = self.def_map.crate_root(self.db).def_map(self.db);
|
|
|
|
def_map.module_id(def_map.root())
|
|
|
|
}
|
|
|
|
None => self.def_map.module_id(self.def_map.root()),
|
|
|
|
};
|
2022-03-22 14:54:46 +00:00
|
|
|
Some(root)
|
2021-09-28 19:23:46 +00:00
|
|
|
} else {
|
2022-03-22 14:54:46 +00:00
|
|
|
self.deps.get(name).copied()
|
2021-09-28 19:23:46 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-07 11:20:41 +00:00
|
|
|
fn record_resolved_import(&mut self, directive: &ImportDirective) {
|
2021-10-01 13:30:00 +00:00
|
|
|
let _p = profile::span("record_resolved_import");
|
|
|
|
|
2019-12-07 11:20:41 +00:00
|
|
|
let module_id = directive.module_id;
|
|
|
|
let import = &directive.import;
|
2021-06-28 18:11:58 +00:00
|
|
|
let mut def = directive.status.namespaces();
|
2019-12-25 14:00:10 +00:00
|
|
|
let vis = self
|
|
|
|
.def_map
|
2023-02-19 14:30:49 +00:00
|
|
|
.resolve_visibility(self.db, module_id, &directive.import.visibility, false)
|
2019-12-26 15:00:10 +00:00
|
|
|
.unwrap_or(Visibility::Public);
|
2019-12-07 11:20:41 +00:00
|
|
|
|
2021-06-28 18:11:58 +00:00
|
|
|
match import.kind {
|
|
|
|
ImportKind::Plain | ImportKind::TypeOnly => {
|
|
|
|
let name = match &import.alias {
|
2021-11-17 14:30:12 +00:00
|
|
|
Some(ImportAlias::Alias(name)) => Some(name),
|
2021-06-28 18:11:58 +00:00
|
|
|
Some(ImportAlias::Underscore) => None,
|
|
|
|
None => match import.path.segments().last() {
|
2021-11-17 14:30:12 +00:00
|
|
|
Some(last_segment) => Some(last_segment),
|
2021-06-28 18:11:58 +00:00
|
|
|
None => {
|
|
|
|
cov_mark::hit!(bogus_paths);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
};
|
2019-12-25 17:05:16 +00:00
|
|
|
|
2021-06-28 18:11:58 +00:00
|
|
|
if import.kind == ImportKind::TypeOnly {
|
|
|
|
def.values = None;
|
|
|
|
def.macros = None;
|
|
|
|
}
|
2019-12-25 17:05:16 +00:00
|
|
|
|
2021-08-15 12:46:13 +00:00
|
|
|
tracing::debug!("resolved import {:?} ({:?}) to {:?}", name, import, def);
|
2021-06-28 18:11:58 +00:00
|
|
|
|
|
|
|
// extern crates in the crate root are special-cased to insert entries into the extern prelude: rust-lang/rust#54658
|
2022-09-02 15:43:20 +00:00
|
|
|
if import.is_extern_crate
|
|
|
|
&& self.def_map.block.is_none()
|
|
|
|
&& module_id == self.def_map.root
|
|
|
|
{
|
2022-03-22 14:54:46 +00:00
|
|
|
if let (Some(ModuleDefId::ModuleId(def)), Some(name)) = (def.take_types(), name)
|
|
|
|
{
|
2021-06-28 18:11:58 +00:00
|
|
|
self.def_map.extern_prelude.insert(name.clone(), def);
|
2019-03-13 13:04:28 +00:00
|
|
|
}
|
|
|
|
}
|
2021-06-28 18:11:58 +00:00
|
|
|
|
2021-11-17 14:30:12 +00:00
|
|
|
self.update(module_id, &[(name.cloned(), def)], vis, ImportType::Named);
|
2019-03-13 13:04:28 +00:00
|
|
|
}
|
2021-06-28 18:11:58 +00:00
|
|
|
ImportKind::Glob => {
|
2021-08-15 12:46:13 +00:00
|
|
|
tracing::debug!("glob import: {:?}", import);
|
2021-06-28 18:11:58 +00:00
|
|
|
match def.take_types() {
|
|
|
|
Some(ModuleDefId::ModuleId(m)) => {
|
|
|
|
if import.is_prelude {
|
|
|
|
// Note: This dodgily overrides the injected prelude. The rustc
|
|
|
|
// implementation seems to work the same though.
|
|
|
|
cov_mark::hit!(std_prelude);
|
|
|
|
self.def_map.prelude = Some(m);
|
|
|
|
} else if m.krate != self.def_map.krate {
|
|
|
|
cov_mark::hit!(glob_across_crates);
|
|
|
|
// glob import from other crate => we can just import everything once
|
|
|
|
let item_map = m.def_map(self.db);
|
|
|
|
let scope = &item_map[m.local_id].scope;
|
|
|
|
|
|
|
|
// Module scoped macros is included
|
|
|
|
let items = scope
|
|
|
|
.resolutions()
|
|
|
|
// only keep visible names...
|
|
|
|
.map(|(n, res)| {
|
|
|
|
(n, res.filter_visibility(|v| v.is_visible_from_other_crate()))
|
|
|
|
})
|
|
|
|
.filter(|(_, res)| !res.is_none())
|
|
|
|
.collect::<Vec<_>>();
|
|
|
|
|
|
|
|
self.update(module_id, &items, vis, ImportType::Glob);
|
|
|
|
} else {
|
|
|
|
// glob import from same crate => we do an initial
|
|
|
|
// import, and then need to propagate any further
|
|
|
|
// additions
|
|
|
|
let def_map;
|
|
|
|
let scope = if m.block == self.def_map.block_id() {
|
|
|
|
&self.def_map[m.local_id].scope
|
|
|
|
} else {
|
|
|
|
def_map = m.def_map(self.db);
|
|
|
|
&def_map[m.local_id].scope
|
|
|
|
};
|
|
|
|
|
|
|
|
// Module scoped macros is included
|
|
|
|
let items = scope
|
|
|
|
.resolutions()
|
|
|
|
// only keep visible names...
|
|
|
|
.map(|(n, res)| {
|
|
|
|
(
|
|
|
|
n,
|
|
|
|
res.filter_visibility(|v| {
|
|
|
|
v.is_visible_from_def_map(
|
|
|
|
self.db,
|
|
|
|
&self.def_map,
|
|
|
|
module_id,
|
|
|
|
)
|
|
|
|
}),
|
|
|
|
)
|
|
|
|
})
|
|
|
|
.filter(|(_, res)| !res.is_none())
|
|
|
|
.collect::<Vec<_>>();
|
|
|
|
|
|
|
|
self.update(module_id, &items, vis, ImportType::Glob);
|
|
|
|
// record the glob import in case we add further items
|
|
|
|
let glob = self.glob_imports.entry(m.local_id).or_default();
|
|
|
|
if !glob.iter().any(|(mid, _)| *mid == module_id) {
|
|
|
|
glob.push((module_id, vis));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Some(ModuleDefId::AdtId(AdtId::EnumId(e))) => {
|
|
|
|
cov_mark::hit!(glob_enum);
|
|
|
|
// glob import from enum => just import all the variants
|
|
|
|
|
|
|
|
// XXX: urgh, so this works by accident! Here, we look at
|
|
|
|
// the enum data, and, in theory, this might require us to
|
|
|
|
// look back at the crate_def_map, creating a cycle. For
|
|
|
|
// example, `enum E { crate::some_macro!(); }`. Luckily, the
|
|
|
|
// only kind of macro that is allowed inside enum is a
|
|
|
|
// `cfg_macro`, and we don't need to run name resolution for
|
|
|
|
// it, but this is sheer luck!
|
|
|
|
let enum_data = self.db.enum_data(e);
|
|
|
|
let resolutions = enum_data
|
|
|
|
.variants
|
|
|
|
.iter()
|
|
|
|
.map(|(local_id, variant_data)| {
|
|
|
|
let name = variant_data.name.clone();
|
|
|
|
let variant = EnumVariantId { parent: e, local_id };
|
|
|
|
let res = PerNs::both(variant.into(), variant.into(), vis);
|
|
|
|
(Some(name), res)
|
|
|
|
})
|
|
|
|
.collect::<Vec<_>>();
|
|
|
|
self.update(module_id, &resolutions, vis, ImportType::Glob);
|
|
|
|
}
|
|
|
|
Some(d) => {
|
2021-08-15 12:46:13 +00:00
|
|
|
tracing::debug!("glob import {:?} from non-module/enum {:?}", import, d);
|
2021-06-28 18:11:58 +00:00
|
|
|
}
|
2021-03-17 21:24:51 +00:00
|
|
|
None => {
|
2021-08-15 12:46:13 +00:00
|
|
|
tracing::debug!("glob import {:?} didn't resolve as type", import);
|
2019-03-16 15:06:45 +00:00
|
|
|
}
|
2019-03-13 13:04:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-25 01:42:44 +00:00
|
|
|
fn update(
|
|
|
|
&mut self,
|
2022-11-11 10:50:26 +00:00
|
|
|
// The module for which `resolutions` have been resolve
|
2020-06-25 01:42:44 +00:00
|
|
|
module_id: LocalModuleId,
|
2020-07-21 15:52:43 +00:00
|
|
|
resolutions: &[(Option<Name>, PerNs)],
|
2022-11-11 10:50:26 +00:00
|
|
|
// Visibility this import will have
|
2020-06-25 01:42:44 +00:00
|
|
|
vis: Visibility,
|
2020-06-25 16:42:12 +00:00
|
|
|
import_type: ImportType,
|
2020-06-25 01:42:44 +00:00
|
|
|
) {
|
2021-05-17 17:07:10 +00:00
|
|
|
self.db.unwind_if_cancelled();
|
2020-06-25 16:42:12 +00:00
|
|
|
self.update_recursive(module_id, resolutions, vis, import_type, 0)
|
2019-03-02 20:59:04 +00:00
|
|
|
}
|
|
|
|
|
2019-03-13 13:04:28 +00:00
|
|
|
fn update_recursive(
|
|
|
|
&mut self,
|
2022-11-11 10:50:26 +00:00
|
|
|
// The module for which `resolutions` have been resolve
|
2019-11-23 13:49:53 +00:00
|
|
|
module_id: LocalModuleId,
|
2020-07-21 15:52:43 +00:00
|
|
|
resolutions: &[(Option<Name>, PerNs)],
|
2021-01-08 14:46:48 +00:00
|
|
|
// All resolutions are imported with this visibility; the visibilities in
|
2019-12-25 17:05:16 +00:00
|
|
|
// the `PerNs` values are ignored and overwritten
|
2019-12-26 15:00:10 +00:00
|
|
|
vis: Visibility,
|
2020-06-25 16:42:12 +00:00
|
|
|
import_type: ImportType,
|
2019-03-13 13:04:28 +00:00
|
|
|
depth: usize,
|
|
|
|
) {
|
2021-07-10 20:49:17 +00:00
|
|
|
if GLOB_RECURSION_LIMIT.check(depth).is_err() {
|
2019-03-13 13:04:28 +00:00
|
|
|
// prevent stack overflows (but this shouldn't be possible)
|
|
|
|
panic!("infinite recursion in glob imports!");
|
2019-03-02 20:59:04 +00:00
|
|
|
}
|
2019-03-13 13:04:28 +00:00
|
|
|
let mut changed = false;
|
2020-07-21 15:52:43 +00:00
|
|
|
|
2019-03-13 13:04:28 +00:00
|
|
|
for (name, res) in resolutions {
|
2020-07-21 15:52:43 +00:00
|
|
|
match name {
|
|
|
|
Some(name) => {
|
|
|
|
let scope = &mut self.def_map.modules[module_id].scope;
|
|
|
|
changed |= scope.push_res_with_import(
|
|
|
|
&mut self.from_glob_import,
|
|
|
|
(module_id, name.clone()),
|
|
|
|
res.with_visibility(vis),
|
|
|
|
import_type,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
None => {
|
|
|
|
let tr = match res.take_types() {
|
|
|
|
Some(ModuleDefId::TraitId(tr)) => tr,
|
|
|
|
Some(other) => {
|
2021-08-15 12:46:13 +00:00
|
|
|
tracing::debug!("non-trait `_` import of {:?}", other);
|
2020-07-21 15:52:43 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
None => continue,
|
|
|
|
};
|
|
|
|
let old_vis = self.def_map.modules[module_id].scope.unnamed_trait_vis(tr);
|
|
|
|
let should_update = match old_vis {
|
|
|
|
None => true,
|
|
|
|
Some(old_vis) => {
|
|
|
|
let max_vis = old_vis.max(vis, &self.def_map).unwrap_or_else(|| {
|
2022-12-23 18:42:58 +00:00
|
|
|
panic!("`Tr as _` imports with unrelated visibilities {old_vis:?} and {vis:?} (trait {tr:?})");
|
2020-07-21 15:52:43 +00:00
|
|
|
});
|
|
|
|
|
2020-07-22 12:01:50 +00:00
|
|
|
if max_vis == old_vis {
|
|
|
|
false
|
|
|
|
} else {
|
2021-03-08 20:19:44 +00:00
|
|
|
cov_mark::hit!(upgrade_underscore_visibility);
|
2020-07-22 12:01:50 +00:00
|
|
|
true
|
|
|
|
}
|
2020-07-21 15:52:43 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
if should_update {
|
|
|
|
changed = true;
|
|
|
|
self.def_map.modules[module_id].scope.push_unnamed_trait(tr, vis);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-03-13 13:04:28 +00:00
|
|
|
}
|
2019-05-26 12:10:56 +00:00
|
|
|
|
2019-03-13 13:04:28 +00:00
|
|
|
if !changed {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
let glob_imports = self
|
|
|
|
.glob_imports
|
|
|
|
.get(&module_id)
|
|
|
|
.into_iter()
|
2022-07-16 09:17:15 +00:00
|
|
|
.flatten()
|
2020-07-15 13:45:34 +00:00
|
|
|
.filter(|(glob_importing_module, _)| {
|
|
|
|
// we know all resolutions have the same visibility (`vis`), so we
|
|
|
|
// just need to check that once
|
2021-02-23 16:56:16 +00:00
|
|
|
vis.is_visible_from_def_map(self.db, &self.def_map, *glob_importing_module)
|
2020-07-15 13:45:34 +00:00
|
|
|
})
|
2019-03-13 13:04:28 +00:00
|
|
|
.cloned()
|
|
|
|
.collect::<Vec<_>>();
|
2020-07-15 13:45:34 +00:00
|
|
|
|
2019-12-25 17:05:16 +00:00
|
|
|
for (glob_importing_module, glob_import_vis) in glob_imports {
|
2020-06-25 01:42:44 +00:00
|
|
|
self.update_recursive(
|
|
|
|
glob_importing_module,
|
|
|
|
resolutions,
|
|
|
|
glob_import_vis,
|
2020-06-25 16:42:12 +00:00
|
|
|
ImportType::Glob,
|
2020-06-25 01:42:44 +00:00
|
|
|
depth + 1,
|
|
|
|
);
|
2019-03-13 13:04:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn resolve_macros(&mut self) -> ReachedFixedPoint {
|
2022-03-23 17:09:53 +00:00
|
|
|
let mut macros = mem::take(&mut self.unresolved_macros);
|
2019-03-13 13:04:28 +00:00
|
|
|
let mut resolved = Vec::new();
|
2022-02-20 23:02:10 +00:00
|
|
|
let mut push_resolved = |directive: &MacroDirective, call_id| {
|
|
|
|
resolved.push((directive.module_id, directive.depth, directive.container, call_id));
|
|
|
|
};
|
2019-03-16 16:40:41 +00:00
|
|
|
let mut res = ReachedFixedPoint::Yes;
|
2019-12-08 12:33:42 +00:00
|
|
|
macros.retain(|directive| {
|
2022-07-31 17:27:34 +00:00
|
|
|
let resolver = |path| {
|
2021-05-18 15:51:02 +00:00
|
|
|
let resolved_res = self.def_map.resolve_path_fp_with_macro(
|
|
|
|
self.db,
|
|
|
|
ResolveMode::Other,
|
|
|
|
directive.module_id,
|
|
|
|
&path,
|
|
|
|
BuiltinShadowMode::Module,
|
|
|
|
);
|
2022-07-24 12:05:37 +00:00
|
|
|
resolved_res
|
|
|
|
.resolved_def
|
|
|
|
.take_macros()
|
|
|
|
.map(|it| (it, macro_id_to_def_id(self.db, it)))
|
2021-05-18 15:51:02 +00:00
|
|
|
};
|
2022-07-31 17:27:34 +00:00
|
|
|
let resolver_def_id = |path| resolver(path).map(|(_, it)| it);
|
2021-05-18 15:51:02 +00:00
|
|
|
|
2021-03-23 16:23:10 +00:00
|
|
|
match &directive.kind {
|
2021-09-05 19:30:06 +00:00
|
|
|
MacroDirectiveKind::FnLike { ast_id, expand_to } => {
|
2021-11-17 19:51:15 +00:00
|
|
|
let call_id = macro_call_as_call_id(
|
2023-04-17 15:31:39 +00:00
|
|
|
self.db.upcast(),
|
2021-03-23 16:23:10 +00:00
|
|
|
ast_id,
|
2021-09-05 19:30:06 +00:00
|
|
|
*expand_to,
|
2021-03-23 16:23:10 +00:00
|
|
|
self.def_map.krate,
|
2022-12-30 08:05:03 +00:00
|
|
|
resolver_def_id,
|
2021-11-17 19:51:15 +00:00
|
|
|
);
|
2023-04-16 16:29:42 +00:00
|
|
|
if let Ok(Some(call_id)) = call_id {
|
2022-02-20 23:02:10 +00:00
|
|
|
push_resolved(directive, call_id);
|
2023-04-16 16:29:42 +00:00
|
|
|
|
2021-11-18 21:17:22 +00:00
|
|
|
res = ReachedFixedPoint::No;
|
|
|
|
return false;
|
2021-03-23 16:23:10 +00:00
|
|
|
}
|
2021-02-28 11:12:11 +00:00
|
|
|
}
|
2022-01-01 19:31:04 +00:00
|
|
|
MacroDirectiveKind::Derive { ast_id, derive_attr, derive_pos } => {
|
2022-07-24 12:05:37 +00:00
|
|
|
let id = derive_macro_as_call_id(
|
2022-02-21 01:42:58 +00:00
|
|
|
self.db,
|
2021-04-09 11:38:01 +00:00
|
|
|
ast_id,
|
|
|
|
*derive_attr,
|
2022-02-20 23:02:10 +00:00
|
|
|
*derive_pos as u32,
|
2021-04-09 11:38:01 +00:00
|
|
|
self.def_map.krate,
|
2022-12-30 08:05:03 +00:00
|
|
|
resolver,
|
2021-11-17 19:51:15 +00:00
|
|
|
);
|
2022-07-24 12:05:37 +00:00
|
|
|
|
|
|
|
if let Ok((macro_id, def_id, call_id)) = id {
|
2022-01-01 19:31:04 +00:00
|
|
|
self.def_map.modules[directive.module_id].scope.set_derive_macro_invoc(
|
2021-11-18 21:17:22 +00:00
|
|
|
ast_id.ast_id,
|
|
|
|
call_id,
|
|
|
|
*derive_attr,
|
2022-01-01 19:31:04 +00:00
|
|
|
*derive_pos,
|
2021-11-18 21:17:22 +00:00
|
|
|
);
|
2022-07-24 12:05:37 +00:00
|
|
|
// Record its helper attributes.
|
|
|
|
if def_id.krate != self.def_map.krate {
|
|
|
|
let def_map = self.db.crate_def_map(def_id.krate);
|
|
|
|
if let Some(helpers) = def_map.exported_derives.get(&def_id) {
|
|
|
|
self.def_map
|
|
|
|
.derive_helpers_in_scope
|
|
|
|
.entry(ast_id.ast_id.map(|it| it.upcast()))
|
|
|
|
.or_default()
|
|
|
|
.extend(izip!(
|
|
|
|
helpers.iter().cloned(),
|
|
|
|
iter::repeat(macro_id),
|
|
|
|
iter::repeat(call_id),
|
|
|
|
));
|
|
|
|
}
|
|
|
|
}
|
2021-11-18 21:17:22 +00:00
|
|
|
|
2022-02-20 23:02:10 +00:00
|
|
|
push_resolved(directive, call_id);
|
2021-11-18 21:17:22 +00:00
|
|
|
res = ReachedFixedPoint::No;
|
|
|
|
return false;
|
2021-03-23 16:23:10 +00:00
|
|
|
}
|
2021-02-28 11:12:11 +00:00
|
|
|
}
|
2021-11-26 02:57:25 +00:00
|
|
|
MacroDirectiveKind::Attr { ast_id: file_ast_id, mod_item, attr, tree } => {
|
2021-11-19 12:17:35 +00:00
|
|
|
let &AstIdWithPath { ast_id, ref path } = file_ast_id;
|
|
|
|
let file_id = ast_id.file_id;
|
|
|
|
|
2021-11-26 02:57:25 +00:00
|
|
|
let mut recollect_without = |collector: &mut Self| {
|
2021-11-17 19:51:15 +00:00
|
|
|
// Remove the original directive since we resolved it.
|
|
|
|
let mod_dir = collector.mod_dirs[&directive.module_id].clone();
|
|
|
|
collector.skip_attrs.insert(InFile::new(file_id, *mod_item), attr.id);
|
2021-11-26 02:57:25 +00:00
|
|
|
|
|
|
|
let item_tree = tree.item_tree(self.db);
|
2021-11-17 19:51:15 +00:00
|
|
|
ModCollector {
|
|
|
|
def_collector: collector,
|
|
|
|
macro_depth: directive.depth,
|
|
|
|
module_id: directive.module_id,
|
2021-11-26 02:57:25 +00:00
|
|
|
tree_id: *tree,
|
|
|
|
item_tree: &item_tree,
|
2021-11-17 19:51:15 +00:00
|
|
|
mod_dir,
|
|
|
|
}
|
2021-12-07 16:31:26 +00:00
|
|
|
.collect(&[*mod_item], directive.container);
|
2021-11-17 19:51:15 +00:00
|
|
|
res = ReachedFixedPoint::No;
|
|
|
|
false
|
|
|
|
};
|
|
|
|
|
2021-11-19 12:17:35 +00:00
|
|
|
if let Some(ident) = path.as_ident() {
|
2022-07-24 10:04:15 +00:00
|
|
|
if let Some(helpers) = self.def_map.derive_helpers_in_scope.get(&ast_id) {
|
2022-07-24 12:05:37 +00:00
|
|
|
if helpers.iter().any(|(it, ..)| it == ident) {
|
2021-05-20 17:56:04 +00:00
|
|
|
cov_mark::hit!(resolved_derive_helper);
|
|
|
|
// Resolved to derive helper. Collect the item's attributes again,
|
|
|
|
// starting after the derive helper.
|
2021-11-26 02:57:25 +00:00
|
|
|
return recollect_without(self);
|
2021-05-20 17:56:04 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-07-31 17:27:34 +00:00
|
|
|
let def = match resolver_def_id(path.clone()) {
|
2022-01-05 16:26:34 +00:00
|
|
|
Some(def) if def.is_attribute() => def,
|
2022-06-18 22:37:37 +00:00
|
|
|
_ => return true,
|
2022-01-05 16:26:34 +00:00
|
|
|
};
|
2021-11-17 18:46:32 +00:00
|
|
|
if matches!(
|
|
|
|
def,
|
2022-07-24 12:05:37 +00:00
|
|
|
MacroDefId { kind:MacroDefKind::BuiltInAttr(expander, _),.. }
|
2021-11-17 18:46:32 +00:00
|
|
|
if expander.is_derive()
|
|
|
|
) {
|
2021-11-17 19:51:15 +00:00
|
|
|
// Resolved to `#[derive]`
|
2021-11-17 18:46:32 +00:00
|
|
|
|
2022-01-07 13:19:11 +00:00
|
|
|
let item_tree = tree.item_tree(self.db);
|
|
|
|
let ast_adt_id: FileAstId<ast::Adt> = match *mod_item {
|
|
|
|
ModItem::Struct(strukt) => item_tree[strukt].ast_id().upcast(),
|
|
|
|
ModItem::Union(union) => item_tree[union].ast_id().upcast(),
|
|
|
|
ModItem::Enum(enum_) => item_tree[enum_].ast_id().upcast(),
|
2021-11-17 18:46:32 +00:00
|
|
|
_ => {
|
2021-11-18 21:17:22 +00:00
|
|
|
let diag = DefDiagnostic::invalid_derive_target(
|
|
|
|
directive.module_id,
|
2021-11-19 12:17:35 +00:00
|
|
|
ast_id,
|
2021-11-18 21:17:22 +00:00
|
|
|
attr.id,
|
|
|
|
);
|
|
|
|
self.def_map.diagnostics.push(diag);
|
2021-11-26 02:57:25 +00:00
|
|
|
return recollect_without(self);
|
2021-11-17 18:46:32 +00:00
|
|
|
}
|
2022-01-07 13:19:11 +00:00
|
|
|
};
|
|
|
|
let ast_id = ast_id.with_value(ast_adt_id);
|
2023-04-22 09:22:29 +00:00
|
|
|
|
|
|
|
let extend_unhygenic;
|
|
|
|
let hygiene = if file_id.is_macro() {
|
|
|
|
self.hygienes
|
|
|
|
.entry(file_id)
|
|
|
|
.or_insert_with(|| Hygiene::new(self.db.upcast(), file_id))
|
|
|
|
} else {
|
|
|
|
// Avoid heap allocation (`Hygiene` embraces `Arc`) and hash map entry
|
|
|
|
// when we're in an oridinary (non-macro) file.
|
|
|
|
extend_unhygenic = Hygiene::new_unhygienic();
|
|
|
|
&extend_unhygenic
|
|
|
|
};
|
2021-11-17 18:46:32 +00:00
|
|
|
|
2023-04-19 15:54:01 +00:00
|
|
|
match attr.parse_path_comma_token_tree(self.db.upcast(), hygiene) {
|
2021-11-17 18:46:32 +00:00
|
|
|
Some(derive_macros) => {
|
2022-01-01 19:31:04 +00:00
|
|
|
let mut len = 0;
|
|
|
|
for (idx, path) in derive_macros.enumerate() {
|
2021-11-19 12:17:35 +00:00
|
|
|
let ast_id = AstIdWithPath::new(file_id, ast_id.value, path);
|
2021-11-17 18:46:32 +00:00
|
|
|
self.unresolved_macros.push(MacroDirective {
|
|
|
|
module_id: directive.module_id,
|
|
|
|
depth: directive.depth + 1,
|
|
|
|
kind: MacroDirectiveKind::Derive {
|
|
|
|
ast_id,
|
|
|
|
derive_attr: attr.id,
|
2022-01-01 19:31:04 +00:00
|
|
|
derive_pos: idx,
|
2021-11-17 18:46:32 +00:00
|
|
|
},
|
2021-12-07 16:31:26 +00:00
|
|
|
container: directive.container,
|
2021-11-17 18:46:32 +00:00
|
|
|
});
|
2022-01-01 19:31:04 +00:00
|
|
|
len = idx;
|
2021-11-17 18:46:32 +00:00
|
|
|
}
|
2022-01-01 19:31:04 +00:00
|
|
|
|
2022-02-22 09:45:29 +00:00
|
|
|
// We treat the #[derive] macro as an attribute call, but we do not resolve it for nameres collection.
|
|
|
|
// This is just a trick to be able to resolve the input to derives as proper paths.
|
|
|
|
// Check the comment in [`builtin_attr_macro`].
|
2022-02-21 01:42:58 +00:00
|
|
|
let call_id = attr_macro_as_call_id(
|
|
|
|
self.db,
|
|
|
|
file_ast_id,
|
|
|
|
attr,
|
|
|
|
self.def_map.krate,
|
|
|
|
def,
|
|
|
|
);
|
2022-01-01 19:31:04 +00:00
|
|
|
self.def_map.modules[directive.module_id]
|
|
|
|
.scope
|
2022-02-21 01:42:58 +00:00
|
|
|
.init_derive_attribute(ast_id, attr.id, call_id, len + 1);
|
2021-11-17 18:46:32 +00:00
|
|
|
}
|
|
|
|
None => {
|
2021-11-19 12:17:35 +00:00
|
|
|
let diag = DefDiagnostic::malformed_derive(
|
|
|
|
directive.module_id,
|
|
|
|
ast_id,
|
|
|
|
attr.id,
|
|
|
|
);
|
|
|
|
self.def_map.diagnostics.push(diag);
|
2021-11-17 18:46:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-26 02:57:25 +00:00
|
|
|
return recollect_without(self);
|
2021-11-17 18:46:32 +00:00
|
|
|
}
|
|
|
|
|
2022-01-05 16:26:34 +00:00
|
|
|
// Not resolved to a derive helper or the derive attribute, so try to treat as a normal attribute.
|
2023-04-22 12:29:28 +00:00
|
|
|
let call_id =
|
|
|
|
attr_macro_as_call_id(self.db, file_ast_id, attr, self.def_map.krate, def);
|
2022-01-05 16:26:34 +00:00
|
|
|
let loc: MacroCallLoc = self.db.lookup_intern_macro_call(call_id);
|
2021-06-06 13:51:05 +00:00
|
|
|
|
2022-06-24 12:19:18 +00:00
|
|
|
// If proc attribute macro expansion is disabled, skip expanding it here
|
2023-03-29 17:13:40 +00:00
|
|
|
if !self.db.expand_proc_attr_macros() {
|
2022-06-24 11:03:13 +00:00
|
|
|
self.def_map.diagnostics.push(DefDiagnostic::unresolved_proc_macro(
|
|
|
|
directive.module_id,
|
|
|
|
loc.kind,
|
2022-06-28 08:41:10 +00:00
|
|
|
loc.def.krate,
|
2022-06-24 11:03:13 +00:00
|
|
|
));
|
|
|
|
return recollect_without(self);
|
|
|
|
}
|
|
|
|
|
2022-01-05 16:26:34 +00:00
|
|
|
// Skip #[test]/#[bench] expansion, which would merely result in more memory usage
|
|
|
|
// due to duplicating functions into macro expansions
|
|
|
|
if matches!(
|
|
|
|
loc.def.kind,
|
|
|
|
MacroDefKind::BuiltInAttr(expander, _)
|
|
|
|
if expander.is_test() || expander.is_bench()
|
|
|
|
) {
|
|
|
|
return recollect_without(self);
|
|
|
|
}
|
2021-06-06 13:51:05 +00:00
|
|
|
|
2022-01-05 16:26:34 +00:00
|
|
|
if let MacroDefKind::ProcMacro(exp, ..) = loc.def.kind {
|
|
|
|
if exp.is_dummy() {
|
2022-06-24 12:19:18 +00:00
|
|
|
// If there's no expander for the proc macro (e.g.
|
|
|
|
// because proc macros are disabled, or building the
|
|
|
|
// proc macro crate failed), report this and skip
|
|
|
|
// expansion like we would if it was disabled
|
2022-01-05 16:26:34 +00:00
|
|
|
self.def_map.diagnostics.push(DefDiagnostic::unresolved_proc_macro(
|
2021-12-07 16:31:26 +00:00
|
|
|
directive.module_id,
|
2022-01-05 16:26:34 +00:00
|
|
|
loc.kind,
|
2022-06-28 08:41:10 +00:00
|
|
|
loc.def.krate,
|
2021-12-07 16:31:26 +00:00
|
|
|
));
|
2022-01-05 16:26:34 +00:00
|
|
|
|
|
|
|
return recollect_without(self);
|
2021-05-31 11:37:11 +00:00
|
|
|
}
|
|
|
|
}
|
2022-01-05 16:26:34 +00:00
|
|
|
|
|
|
|
self.def_map.modules[directive.module_id]
|
|
|
|
.scope
|
|
|
|
.add_attr_macro_invoc(ast_id, call_id);
|
|
|
|
|
2022-02-20 23:02:10 +00:00
|
|
|
push_resolved(directive, call_id);
|
2022-01-05 16:26:34 +00:00
|
|
|
res = ReachedFixedPoint::No;
|
|
|
|
return false;
|
2021-05-19 13:17:57 +00:00
|
|
|
}
|
2019-03-13 13:04:28 +00:00
|
|
|
}
|
2019-05-26 12:10:56 +00:00
|
|
|
|
|
|
|
true
|
2019-03-13 13:04:28 +00:00
|
|
|
});
|
2021-05-20 17:56:04 +00:00
|
|
|
// Attribute resolution can add unresolved macro invocations, so concatenate the lists.
|
2022-07-31 17:27:34 +00:00
|
|
|
macros.extend(mem::take(&mut self.unresolved_macros));
|
|
|
|
self.unresolved_macros = macros;
|
2019-05-14 15:55:24 +00:00
|
|
|
|
2022-02-20 23:02:10 +00:00
|
|
|
for (module_id, depth, container, macro_call_id) in resolved {
|
2021-12-07 16:31:26 +00:00
|
|
|
self.collect_macro_expansion(module_id, macro_call_id, depth, container);
|
2019-03-13 13:04:28 +00:00
|
|
|
}
|
2019-05-14 15:55:24 +00:00
|
|
|
|
2019-03-13 13:04:28 +00:00
|
|
|
res
|
2019-03-02 20:59:04 +00:00
|
|
|
}
|
|
|
|
|
2020-03-13 12:57:44 +00:00
|
|
|
fn collect_macro_expansion(
|
|
|
|
&mut self,
|
|
|
|
module_id: LocalModuleId,
|
|
|
|
macro_call_id: MacroCallId,
|
|
|
|
depth: usize,
|
2021-12-07 16:31:26 +00:00
|
|
|
container: ItemContainerId,
|
2020-03-13 12:57:44 +00:00
|
|
|
) {
|
2021-07-10 20:49:17 +00:00
|
|
|
if EXPANSION_DEPTH_LIMIT.check(depth).is_err() {
|
2021-03-08 20:19:44 +00:00
|
|
|
cov_mark::hit!(macro_expansion_overflow);
|
2021-08-15 12:46:13 +00:00
|
|
|
tracing::warn!("macro expansion is too deep");
|
2020-07-14 16:31:48 +00:00
|
|
|
return;
|
|
|
|
}
|
2020-11-26 19:09:54 +00:00
|
|
|
let file_id = macro_call_id.as_file();
|
|
|
|
|
|
|
|
// First, fetch the raw expansion result for purposes of error reporting. This goes through
|
2023-04-16 16:29:42 +00:00
|
|
|
// `parse_macro_expansion_error` to avoid depending on the full expansion result (to improve
|
2020-11-26 19:09:54 +00:00
|
|
|
// incrementality).
|
2023-04-16 16:29:42 +00:00
|
|
|
let ExpandResult { value, err } = self.db.parse_macro_expansion_error(macro_call_id);
|
2020-11-26 19:09:54 +00:00
|
|
|
if let Some(err) = err {
|
2023-04-16 16:29:42 +00:00
|
|
|
let loc: MacroCallLoc = self.db.lookup_intern_macro_call(macro_call_id);
|
2021-05-19 18:19:08 +00:00
|
|
|
let diag = match err {
|
2023-04-16 16:29:42 +00:00
|
|
|
// why is this reported here?
|
2022-06-28 08:41:10 +00:00
|
|
|
hir_expand::ExpandError::UnresolvedProcMacro(krate) => {
|
|
|
|
always!(krate == loc.def.krate);
|
|
|
|
DefDiagnostic::unresolved_proc_macro(module_id, loc.kind.clone(), loc.def.krate)
|
2021-05-19 18:19:08 +00:00
|
|
|
}
|
2023-04-16 16:29:42 +00:00
|
|
|
_ => DefDiagnostic::macro_error(module_id, loc.kind.clone(), err.to_string()),
|
2021-05-19 18:19:08 +00:00
|
|
|
};
|
2020-11-26 19:09:54 +00:00
|
|
|
|
2021-05-19 18:19:08 +00:00
|
|
|
self.def_map.diagnostics.push(diag);
|
2020-11-26 19:09:54 +00:00
|
|
|
}
|
2023-04-16 17:20:42 +00:00
|
|
|
if let errors @ [_, ..] = &*value {
|
2023-04-16 16:29:42 +00:00
|
|
|
let loc: MacroCallLoc = self.db.lookup_intern_macro_call(macro_call_id);
|
|
|
|
let diag = DefDiagnostic::macro_expansion_parse_error(module_id, loc.kind, &errors);
|
|
|
|
self.def_map.diagnostics.push(diag);
|
|
|
|
}
|
2020-11-26 19:09:54 +00:00
|
|
|
|
|
|
|
// Then, fetch and process the item tree. This will reuse the expansion result from above.
|
2021-03-13 01:24:26 +00:00
|
|
|
let item_tree = self.db.file_item_tree(file_id);
|
2023-04-16 12:15:59 +00:00
|
|
|
|
2019-12-08 12:33:42 +00:00
|
|
|
let mod_dir = self.mod_dirs[&module_id].clone();
|
|
|
|
ModCollector {
|
|
|
|
def_collector: &mut *self,
|
2020-03-13 12:57:44 +00:00
|
|
|
macro_depth: depth,
|
2021-07-19 12:53:18 +00:00
|
|
|
tree_id: TreeId::new(file_id, None),
|
2019-12-08 12:33:42 +00:00
|
|
|
module_id,
|
2020-06-12 21:24:26 +00:00
|
|
|
item_tree: &item_tree,
|
2019-12-08 12:33:42 +00:00
|
|
|
mod_dir,
|
2019-04-20 15:05:25 +00:00
|
|
|
}
|
2021-12-07 16:31:26 +00:00
|
|
|
.collect(item_tree.top_level_items(), container);
|
2019-03-02 20:59:04 +00:00
|
|
|
}
|
|
|
|
|
2021-01-18 19:18:05 +00:00
|
|
|
fn finish(mut self) -> DefMap {
|
2021-01-05 14:42:43 +00:00
|
|
|
// Emit diagnostics for all remaining unexpanded macros.
|
|
|
|
|
2021-10-01 13:30:00 +00:00
|
|
|
let _p = profile::span("DefCollector::finish");
|
|
|
|
|
2021-05-20 11:12:29 +00:00
|
|
|
for directive in &self.unresolved_macros {
|
2021-03-23 16:23:10 +00:00
|
|
|
match &directive.kind {
|
2021-09-05 19:30:06 +00:00
|
|
|
MacroDirectiveKind::FnLike { ast_id, expand_to } => {
|
2023-04-16 16:29:42 +00:00
|
|
|
// FIXME: we shouldn't need to re-resolve the macro here just to get the unresolved error!
|
2021-11-17 18:46:32 +00:00
|
|
|
let macro_call_as_call_id = macro_call_as_call_id(
|
2023-04-17 15:31:39 +00:00
|
|
|
self.db.upcast(),
|
2021-09-05 19:30:06 +00:00
|
|
|
ast_id,
|
|
|
|
*expand_to,
|
|
|
|
self.def_map.krate,
|
|
|
|
|path| {
|
|
|
|
let resolved_res = self.def_map.resolve_path_fp_with_macro(
|
|
|
|
self.db,
|
|
|
|
ResolveMode::Other,
|
|
|
|
directive.module_id,
|
|
|
|
&path,
|
|
|
|
BuiltinShadowMode::Module,
|
|
|
|
);
|
2022-03-08 20:41:19 +00:00
|
|
|
resolved_res
|
|
|
|
.resolved_def
|
|
|
|
.take_macros()
|
|
|
|
.map(|it| macro_id_to_def_id(self.db, it))
|
2021-09-05 19:30:06 +00:00
|
|
|
},
|
2021-11-17 18:46:32 +00:00
|
|
|
);
|
|
|
|
if let Err(UnresolvedMacro { path }) = macro_call_as_call_id {
|
|
|
|
self.def_map.diagnostics.push(DefDiagnostic::unresolved_macro_call(
|
|
|
|
directive.module_id,
|
2022-04-27 18:03:57 +00:00
|
|
|
MacroCallKind::FnLike { ast_id: ast_id.ast_id, expand_to: *expand_to },
|
2021-11-17 18:46:32 +00:00
|
|
|
path,
|
|
|
|
));
|
2021-03-23 16:23:10 +00:00
|
|
|
}
|
2021-09-05 19:30:06 +00:00
|
|
|
}
|
2022-04-27 18:03:57 +00:00
|
|
|
MacroDirectiveKind::Derive { ast_id, derive_attr, derive_pos } => {
|
|
|
|
self.def_map.diagnostics.push(DefDiagnostic::unresolved_macro_call(
|
|
|
|
directive.module_id,
|
|
|
|
MacroCallKind::Derive {
|
|
|
|
ast_id: ast_id.ast_id,
|
2023-01-09 19:47:51 +00:00
|
|
|
derive_attr_index: *derive_attr,
|
2022-04-27 18:03:57 +00:00
|
|
|
derive_index: *derive_pos as u32,
|
|
|
|
},
|
|
|
|
ast_id.path.clone(),
|
|
|
|
));
|
|
|
|
}
|
2022-06-18 22:37:37 +00:00
|
|
|
// These are diagnosed by `reseed_with_unresolved_attribute`, as that function consumes them
|
|
|
|
MacroDirectiveKind::Attr { .. } => {}
|
2021-03-23 16:23:10 +00:00
|
|
|
}
|
2021-01-05 14:42:43 +00:00
|
|
|
}
|
|
|
|
|
2020-09-17 12:48:17 +00:00
|
|
|
// Emit diagnostics for all remaining unresolved imports.
|
|
|
|
|
|
|
|
// We'd like to avoid emitting a diagnostics avalanche when some `extern crate` doesn't
|
|
|
|
// resolve. We first emit diagnostics for unresolved extern crates and collect the missing
|
|
|
|
// crate names. Then we emit diagnostics for unresolved imports, but only if the import
|
|
|
|
// doesn't start with an unresolved crate's name. Due to renaming and reexports, this is a
|
|
|
|
// heuristic, but it works in practice.
|
|
|
|
let mut diagnosed_extern_crates = FxHashSet::default();
|
2020-09-16 13:47:58 +00:00
|
|
|
for directive in &self.unresolved_imports {
|
2020-09-17 12:48:17 +00:00
|
|
|
if let ImportSource::ExternCrate(krate) = directive.import.source {
|
2021-03-12 23:34:01 +00:00
|
|
|
let item_tree = krate.item_tree(self.db);
|
2020-09-17 12:48:17 +00:00
|
|
|
let extern_crate = &item_tree[krate.value];
|
|
|
|
|
2020-09-17 13:28:23 +00:00
|
|
|
diagnosed_extern_crates.insert(extern_crate.name.clone());
|
2020-09-17 12:48:17 +00:00
|
|
|
|
|
|
|
self.def_map.diagnostics.push(DefDiagnostic::unresolved_extern_crate(
|
|
|
|
directive.module_id,
|
2021-03-12 23:34:01 +00:00
|
|
|
InFile::new(krate.file_id(), extern_crate.ast_id),
|
2020-09-17 12:48:17 +00:00
|
|
|
));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for directive in &self.unresolved_imports {
|
2021-11-18 20:43:54 +00:00
|
|
|
if let ImportSource::Import { id: import, use_tree } = directive.import.source {
|
|
|
|
if matches!(
|
|
|
|
(directive.import.path.segments().first(), &directive.import.path.kind),
|
|
|
|
(Some(krate), PathKind::Plain | PathKind::Abs) if diagnosed_extern_crates.contains(krate)
|
|
|
|
) {
|
|
|
|
continue;
|
2020-09-16 13:47:58 +00:00
|
|
|
}
|
2020-09-17 12:48:17 +00:00
|
|
|
|
|
|
|
self.def_map.diagnostics.push(DefDiagnostic::unresolved_import(
|
|
|
|
directive.module_id,
|
2021-11-18 20:43:54 +00:00
|
|
|
import,
|
|
|
|
use_tree,
|
2020-09-17 12:48:17 +00:00
|
|
|
));
|
2020-09-16 13:47:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-02 20:59:04 +00:00
|
|
|
self.def_map
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-13 13:38:02 +00:00
|
|
|
/// Walks a single module, populating defs, imports and macros
|
2020-03-13 15:05:46 +00:00
|
|
|
struct ModCollector<'a, 'b> {
|
|
|
|
def_collector: &'a mut DefCollector<'b>,
|
2020-03-13 12:57:44 +00:00
|
|
|
macro_depth: usize,
|
2019-11-23 13:49:53 +00:00
|
|
|
module_id: LocalModuleId,
|
2021-07-19 12:53:18 +00:00
|
|
|
tree_id: TreeId,
|
2020-06-12 21:24:26 +00:00
|
|
|
item_tree: &'a ItemTree,
|
2019-10-10 11:45:05 +00:00
|
|
|
mod_dir: ModDir,
|
2019-03-13 13:38:02 +00:00
|
|
|
}
|
|
|
|
|
2020-03-13 15:05:46 +00:00
|
|
|
impl ModCollector<'_, '_> {
|
2021-12-07 16:31:26 +00:00
|
|
|
fn collect_in_top_module(&mut self, items: &[ModItem]) {
|
|
|
|
let module = self.def_collector.def_map.module_id(self.module_id);
|
|
|
|
self.collect(items, module.into())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn collect(&mut self, items: &[ModItem], container: ItemContainerId) {
|
2020-12-17 23:23:46 +00:00
|
|
|
let krate = self.def_collector.def_map.krate;
|
|
|
|
|
2019-10-10 11:45:05 +00:00
|
|
|
// Note: don't assert that inserted value is fresh: it's simply not true
|
|
|
|
// for macros.
|
|
|
|
self.def_collector.mod_dirs.insert(self.module_id, self.mod_dir.clone());
|
|
|
|
|
2019-09-05 08:20:36 +00:00
|
|
|
// Prelude module is always considered to be `#[macro_use]`.
|
|
|
|
if let Some(prelude_module) = self.def_collector.def_map.prelude {
|
2021-05-20 17:56:04 +00:00
|
|
|
if prelude_module.krate != krate {
|
2021-03-08 20:19:44 +00:00
|
|
|
cov_mark::hit!(prelude_is_macro_use);
|
2019-10-31 15:45:10 +00:00
|
|
|
self.def_collector.import_all_macros_exported(self.module_id, prelude_module.krate);
|
2019-09-07 18:43:41 +00:00
|
|
|
}
|
2019-09-05 08:20:36 +00:00
|
|
|
}
|
|
|
|
|
2019-09-05 10:39:56 +00:00
|
|
|
// This should be processed eagerly instead of deferred to resolving.
|
|
|
|
// `#[macro_use] extern crate` is hoisted to imports macros before collecting
|
|
|
|
// any other items.
|
2021-11-18 20:43:54 +00:00
|
|
|
for &item in items {
|
|
|
|
let attrs = self.item_tree.attrs(self.def_collector.db, krate, item.into());
|
2020-10-22 17:19:18 +00:00
|
|
|
if attrs.cfg().map_or(true, |cfg| self.is_cfg_enabled(&cfg)) {
|
2020-06-22 13:07:06 +00:00
|
|
|
if let ModItem::ExternCrate(id) = item {
|
2021-11-18 20:43:54 +00:00
|
|
|
let import = &self.item_tree[id];
|
2020-12-18 19:37:26 +00:00
|
|
|
let attrs = self.item_tree.attrs(
|
|
|
|
self.def_collector.db,
|
|
|
|
krate,
|
2021-11-18 20:43:54 +00:00
|
|
|
ModItem::from(id).into(),
|
2020-12-18 19:37:26 +00:00
|
|
|
);
|
|
|
|
if attrs.by_key("macro_use").exists() {
|
2021-11-18 20:43:54 +00:00
|
|
|
self.def_collector.import_macros_from_extern_crate(self.module_id, import);
|
2019-09-29 22:52:15 +00:00
|
|
|
}
|
2019-09-05 10:39:56 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-15 17:16:14 +00:00
|
|
|
for &item in items {
|
2020-12-17 23:23:46 +00:00
|
|
|
let attrs = self.item_tree.attrs(self.def_collector.db, krate, item.into());
|
2020-10-22 17:19:18 +00:00
|
|
|
if let Some(cfg) = attrs.cfg() {
|
|
|
|
if !self.is_cfg_enabled(&cfg) {
|
2022-09-21 22:05:30 +00:00
|
|
|
self.emit_unconfigured_diagnostic(item, &cfg);
|
2020-10-22 17:19:18 +00:00
|
|
|
continue;
|
|
|
|
}
|
2020-09-18 10:32:07 +00:00
|
|
|
}
|
2021-05-19 13:17:57 +00:00
|
|
|
|
2021-12-07 16:31:26 +00:00
|
|
|
if let Err(()) = self.resolve_attributes(&attrs, item, container) {
|
2021-05-19 21:35:09 +00:00
|
|
|
// Do not process the item. It has at least one non-builtin attribute, so the
|
|
|
|
// fixed-point algorithm is required to resolve the rest of them.
|
2021-05-19 13:17:57 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2022-02-23 10:57:11 +00:00
|
|
|
let db = self.def_collector.db;
|
2022-09-21 22:05:30 +00:00
|
|
|
let module = self.def_collector.def_map.module_id(self.module_id);
|
|
|
|
let def_map = &mut self.def_collector.def_map;
|
2022-02-23 10:57:11 +00:00
|
|
|
let update_def =
|
2022-07-20 13:02:08 +00:00
|
|
|
|def_collector: &mut DefCollector<'_>, id, name: &Name, vis, has_constructor| {
|
2022-09-21 22:05:30 +00:00
|
|
|
def_collector.def_map.modules[self.module_id].scope.declare(id);
|
2022-02-23 10:57:11 +00:00
|
|
|
def_collector.update(
|
2022-09-21 22:05:30 +00:00
|
|
|
self.module_id,
|
2022-02-23 10:57:11 +00:00
|
|
|
&[(Some(name.clone()), PerNs::from_def(id, vis, has_constructor))],
|
|
|
|
vis,
|
|
|
|
ImportType::Named,
|
|
|
|
)
|
|
|
|
};
|
|
|
|
let resolve_vis = |def_map: &DefMap, visibility| {
|
2022-09-21 22:05:30 +00:00
|
|
|
def_map
|
2023-02-19 14:30:49 +00:00
|
|
|
.resolve_visibility(db, self.module_id, visibility, false)
|
2022-09-21 22:05:30 +00:00
|
|
|
.unwrap_or(Visibility::Public)
|
2022-02-23 10:57:11 +00:00
|
|
|
};
|
2020-09-18 10:32:07 +00:00
|
|
|
|
|
|
|
match item {
|
2022-07-21 14:05:52 +00:00
|
|
|
ModItem::Mod(m) => self.collect_module(m, &attrs),
|
2020-09-18 10:32:07 +00:00
|
|
|
ModItem::Import(import_id) => {
|
2021-05-25 23:01:58 +00:00
|
|
|
let imports = Import::from_use(
|
2022-02-23 10:57:11 +00:00
|
|
|
db,
|
2021-05-25 23:01:58 +00:00
|
|
|
krate,
|
2021-06-13 03:54:16 +00:00
|
|
|
self.item_tree,
|
2021-07-19 12:53:18 +00:00
|
|
|
ItemTreeId::new(self.tree_id, import_id),
|
2021-05-25 23:01:58 +00:00
|
|
|
);
|
|
|
|
self.def_collector.unresolved_imports.extend(imports.into_iter().map(
|
|
|
|
|import| ImportDirective {
|
2022-02-23 10:57:11 +00:00
|
|
|
module_id: self.module_id,
|
2021-05-25 23:01:58 +00:00
|
|
|
import,
|
|
|
|
status: PartialResolvedImport::Unresolved,
|
|
|
|
},
|
|
|
|
));
|
2020-09-18 10:32:07 +00:00
|
|
|
}
|
|
|
|
ModItem::ExternCrate(import_id) => {
|
|
|
|
self.def_collector.unresolved_imports.push(ImportDirective {
|
|
|
|
module_id: self.module_id,
|
|
|
|
import: Import::from_extern_crate(
|
2022-02-23 10:57:11 +00:00
|
|
|
db,
|
2020-12-18 19:37:26 +00:00
|
|
|
krate,
|
2021-06-13 03:54:16 +00:00
|
|
|
self.item_tree,
|
2021-07-19 12:53:18 +00:00
|
|
|
ItemTreeId::new(self.tree_id, import_id),
|
2020-09-18 10:32:07 +00:00
|
|
|
),
|
|
|
|
status: PartialResolvedImport::Unresolved,
|
|
|
|
})
|
|
|
|
}
|
2021-12-07 16:31:26 +00:00
|
|
|
ModItem::ExternBlock(block) => self.collect(
|
|
|
|
&self.item_tree[block].children,
|
|
|
|
ItemContainerId::ExternBlockId(
|
|
|
|
ExternBlockLoc {
|
|
|
|
container: module,
|
|
|
|
id: ItemTreeId::new(self.tree_id, block),
|
|
|
|
}
|
2022-02-23 10:57:11 +00:00
|
|
|
.intern(db),
|
2021-12-07 16:31:26 +00:00
|
|
|
),
|
|
|
|
),
|
|
|
|
ModItem::MacroCall(mac) => self.collect_macro_call(&self.item_tree[mac], container),
|
2022-03-08 20:41:19 +00:00
|
|
|
ModItem::MacroRules(id) => self.collect_macro_rules(id, module),
|
|
|
|
ModItem::MacroDef(id) => self.collect_macro_def(id, module),
|
2020-09-18 10:32:07 +00:00
|
|
|
ModItem::Impl(imp) => {
|
2021-03-09 18:09:02 +00:00
|
|
|
let impl_id =
|
2021-07-19 12:53:18 +00:00
|
|
|
ImplLoc { container: module, id: ItemTreeId::new(self.tree_id, imp) }
|
2022-02-23 10:57:11 +00:00
|
|
|
.intern(db);
|
2020-09-18 10:32:07 +00:00
|
|
|
self.def_collector.def_map.modules[self.module_id].scope.define_impl(impl_id)
|
|
|
|
}
|
|
|
|
ModItem::Function(id) => {
|
2022-02-23 10:57:11 +00:00
|
|
|
let it = &self.item_tree[id];
|
2022-03-09 10:26:06 +00:00
|
|
|
let fn_id =
|
|
|
|
FunctionLoc { container, id: ItemTreeId::new(self.tree_id, id) }.intern(db);
|
2020-09-18 14:43:50 +00:00
|
|
|
|
2022-03-09 13:33:39 +00:00
|
|
|
let vis = resolve_vis(def_map, &self.item_tree[it.visibility]);
|
2023-01-10 18:48:51 +00:00
|
|
|
if self.def_collector.is_proc_macro && self.module_id == def_map.root {
|
|
|
|
if let Some(proc_macro) = attrs.parse_proc_macro_decl(&it.name) {
|
|
|
|
let crate_root = def_map.module_id(def_map.root);
|
|
|
|
self.def_collector.export_proc_macro(
|
|
|
|
proc_macro,
|
|
|
|
ItemTreeId::new(self.tree_id, id),
|
|
|
|
fn_id,
|
|
|
|
crate_root,
|
|
|
|
);
|
2022-02-23 10:57:11 +00:00
|
|
|
}
|
2022-03-09 13:33:39 +00:00
|
|
|
}
|
|
|
|
|
2022-03-09 10:26:06 +00:00
|
|
|
update_def(self.def_collector, fn_id.into(), &it.name, vis, false);
|
2020-09-18 10:32:07 +00:00
|
|
|
}
|
|
|
|
ModItem::Struct(id) => {
|
|
|
|
let it = &self.item_tree[id];
|
2020-06-15 17:16:14 +00:00
|
|
|
|
2022-09-21 22:05:30 +00:00
|
|
|
let vis = resolve_vis(def_map, &self.item_tree[it.visibility]);
|
2022-02-23 10:57:11 +00:00
|
|
|
update_def(
|
|
|
|
self.def_collector,
|
|
|
|
StructLoc { container: module, id: ItemTreeId::new(self.tree_id, id) }
|
|
|
|
.intern(db)
|
2020-09-18 10:32:07 +00:00
|
|
|
.into(),
|
2022-02-23 10:57:11 +00:00
|
|
|
&it.name,
|
|
|
|
vis,
|
|
|
|
!matches!(it.fields, Fields::Record(_)),
|
|
|
|
);
|
2020-09-18 10:32:07 +00:00
|
|
|
}
|
|
|
|
ModItem::Union(id) => {
|
|
|
|
let it = &self.item_tree[id];
|
2020-06-15 17:16:14 +00:00
|
|
|
|
2022-09-21 22:05:30 +00:00
|
|
|
let vis = resolve_vis(def_map, &self.item_tree[it.visibility]);
|
2022-02-23 10:57:11 +00:00
|
|
|
update_def(
|
|
|
|
self.def_collector,
|
|
|
|
UnionLoc { container: module, id: ItemTreeId::new(self.tree_id, id) }
|
|
|
|
.intern(db)
|
2020-09-18 10:32:07 +00:00
|
|
|
.into(),
|
2022-02-23 10:57:11 +00:00
|
|
|
&it.name,
|
|
|
|
vis,
|
|
|
|
false,
|
|
|
|
);
|
2020-09-18 10:32:07 +00:00
|
|
|
}
|
|
|
|
ModItem::Enum(id) => {
|
|
|
|
let it = &self.item_tree[id];
|
2020-06-15 17:16:14 +00:00
|
|
|
|
2022-09-21 22:05:30 +00:00
|
|
|
let vis = resolve_vis(def_map, &self.item_tree[it.visibility]);
|
2022-02-23 10:57:11 +00:00
|
|
|
update_def(
|
|
|
|
self.def_collector,
|
|
|
|
EnumLoc { container: module, id: ItemTreeId::new(self.tree_id, id) }
|
|
|
|
.intern(db)
|
2020-09-18 10:32:07 +00:00
|
|
|
.into(),
|
2022-02-23 10:57:11 +00:00
|
|
|
&it.name,
|
|
|
|
vis,
|
|
|
|
false,
|
|
|
|
);
|
2020-09-18 10:32:07 +00:00
|
|
|
}
|
|
|
|
ModItem::Const(id) => {
|
|
|
|
let it = &self.item_tree[id];
|
2022-02-23 10:57:11 +00:00
|
|
|
let const_id =
|
|
|
|
ConstLoc { container, id: ItemTreeId::new(self.tree_id, id) }.intern(db);
|
2021-04-07 01:12:40 +00:00
|
|
|
|
|
|
|
match &it.name {
|
|
|
|
Some(name) => {
|
2022-09-21 22:05:30 +00:00
|
|
|
let vis = resolve_vis(def_map, &self.item_tree[it.visibility]);
|
2022-02-23 10:57:11 +00:00
|
|
|
update_def(self.def_collector, const_id.into(), name, vis, false);
|
2021-04-07 01:12:40 +00:00
|
|
|
}
|
|
|
|
None => {
|
|
|
|
// const _: T = ...;
|
|
|
|
self.def_collector.def_map.modules[self.module_id]
|
|
|
|
.scope
|
|
|
|
.define_unnamed_const(const_id);
|
|
|
|
}
|
2020-06-15 17:16:14 +00:00
|
|
|
}
|
|
|
|
}
|
2020-09-18 10:32:07 +00:00
|
|
|
ModItem::Static(id) => {
|
|
|
|
let it = &self.item_tree[id];
|
2020-06-15 17:16:14 +00:00
|
|
|
|
2022-09-21 22:05:30 +00:00
|
|
|
let vis = resolve_vis(def_map, &self.item_tree[it.visibility]);
|
2022-02-23 10:57:11 +00:00
|
|
|
update_def(
|
|
|
|
self.def_collector,
|
|
|
|
StaticLoc { container, id: ItemTreeId::new(self.tree_id, id) }
|
|
|
|
.intern(db)
|
2020-09-18 10:32:07 +00:00
|
|
|
.into(),
|
2022-02-23 10:57:11 +00:00
|
|
|
&it.name,
|
|
|
|
vis,
|
|
|
|
false,
|
|
|
|
);
|
2019-09-29 22:52:15 +00:00
|
|
|
}
|
2020-09-18 10:32:07 +00:00
|
|
|
ModItem::Trait(id) => {
|
|
|
|
let it = &self.item_tree[id];
|
|
|
|
|
2022-09-21 22:05:30 +00:00
|
|
|
let vis = resolve_vis(def_map, &self.item_tree[it.visibility]);
|
2022-02-23 10:57:11 +00:00
|
|
|
update_def(
|
|
|
|
self.def_collector,
|
|
|
|
TraitLoc { container: module, id: ItemTreeId::new(self.tree_id, id) }
|
|
|
|
.intern(db)
|
2020-09-18 10:32:07 +00:00
|
|
|
.into(),
|
2022-02-23 10:57:11 +00:00
|
|
|
&it.name,
|
|
|
|
vis,
|
|
|
|
false,
|
|
|
|
);
|
2020-09-18 10:32:07 +00:00
|
|
|
}
|
2023-03-03 15:24:07 +00:00
|
|
|
ModItem::TraitAlias(id) => {
|
|
|
|
let it = &self.item_tree[id];
|
|
|
|
|
|
|
|
let vis = resolve_vis(def_map, &self.item_tree[it.visibility]);
|
|
|
|
update_def(
|
|
|
|
self.def_collector,
|
|
|
|
TraitAliasLoc { container: module, id: ItemTreeId::new(self.tree_id, id) }
|
|
|
|
.intern(db)
|
|
|
|
.into(),
|
|
|
|
&it.name,
|
|
|
|
vis,
|
|
|
|
false,
|
|
|
|
);
|
|
|
|
}
|
2020-09-18 10:32:07 +00:00
|
|
|
ModItem::TypeAlias(id) => {
|
|
|
|
let it = &self.item_tree[id];
|
|
|
|
|
2022-09-21 22:05:30 +00:00
|
|
|
let vis = resolve_vis(def_map, &self.item_tree[it.visibility]);
|
2022-02-23 10:57:11 +00:00
|
|
|
update_def(
|
|
|
|
self.def_collector,
|
|
|
|
TypeAliasLoc { container, id: ItemTreeId::new(self.tree_id, id) }
|
|
|
|
.intern(db)
|
2021-12-07 16:31:26 +00:00
|
|
|
.into(),
|
2022-02-23 10:57:11 +00:00
|
|
|
&it.name,
|
|
|
|
vis,
|
|
|
|
false,
|
|
|
|
);
|
2020-09-18 10:32:07 +00:00
|
|
|
}
|
|
|
|
}
|
2019-03-02 20:59:04 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-07-21 14:05:52 +00:00
|
|
|
fn collect_module(&mut self, module_id: FileItemTreeId<Mod>, attrs: &Attrs) {
|
2019-11-24 13:03:02 +00:00
|
|
|
let path_attr = attrs.by_key("path").string_value();
|
|
|
|
let is_macro_use = attrs.by_key("macro_use").exists();
|
2022-07-21 14:05:52 +00:00
|
|
|
let module = &self.item_tree[module_id];
|
2020-06-15 17:16:14 +00:00
|
|
|
match &module.kind {
|
2019-07-13 18:51:20 +00:00
|
|
|
// inline module, just recurse
|
2020-06-15 17:16:14 +00:00
|
|
|
ModKind::Inline { items } => {
|
2019-12-26 14:49:13 +00:00
|
|
|
let module_id = self.push_child_module(
|
2020-06-15 17:16:14 +00:00
|
|
|
module.name.clone(),
|
2021-07-19 12:53:18 +00:00
|
|
|
AstId::new(self.file_id(), module.ast_id),
|
2019-12-26 14:49:13 +00:00
|
|
|
None,
|
2020-06-24 13:36:18 +00:00
|
|
|
&self.item_tree[module.visibility],
|
2022-07-21 14:05:52 +00:00
|
|
|
module_id,
|
2019-12-26 14:49:13 +00:00
|
|
|
);
|
2019-09-06 16:55:58 +00:00
|
|
|
|
2020-11-04 14:31:35 +00:00
|
|
|
if let Some(mod_dir) = self.mod_dir.descend_into_definition(&module.name, path_attr)
|
|
|
|
{
|
|
|
|
ModCollector {
|
|
|
|
def_collector: &mut *self.def_collector,
|
|
|
|
macro_depth: self.macro_depth,
|
|
|
|
module_id,
|
2021-07-19 12:53:18 +00:00
|
|
|
tree_id: self.tree_id,
|
2020-11-04 14:31:35 +00:00
|
|
|
item_tree: self.item_tree,
|
|
|
|
mod_dir,
|
|
|
|
}
|
2021-12-07 16:31:26 +00:00
|
|
|
.collect_in_top_module(&*items);
|
2020-11-04 14:31:35 +00:00
|
|
|
if is_macro_use {
|
|
|
|
self.import_all_legacy_macros(module_id);
|
|
|
|
}
|
2019-09-06 16:55:58 +00:00
|
|
|
}
|
2019-03-02 20:59:04 +00:00
|
|
|
}
|
2019-07-13 18:51:20 +00:00
|
|
|
// out of line module, resolve, parse and recurse
|
2022-03-11 15:49:41 +00:00
|
|
|
ModKind::Outline => {
|
2021-07-19 12:53:18 +00:00
|
|
|
let ast_id = AstId::new(self.tree_id.file_id(), module.ast_id);
|
2021-01-31 18:26:04 +00:00
|
|
|
let db = self.def_collector.db;
|
2021-07-19 12:53:18 +00:00
|
|
|
match self.mod_dir.resolve_declaration(db, self.file_id(), &module.name, path_attr)
|
|
|
|
{
|
2020-06-11 09:04:09 +00:00
|
|
|
Ok((file_id, is_mod_rs, mod_dir)) => {
|
2021-03-13 01:24:26 +00:00
|
|
|
let item_tree = db.file_item_tree(file_id.into());
|
2022-02-23 14:55:06 +00:00
|
|
|
let krate = self.def_collector.def_map.krate;
|
2021-09-03 14:00:50 +00:00
|
|
|
let is_enabled = item_tree
|
2022-02-23 14:55:06 +00:00
|
|
|
.top_level_attrs(db, krate)
|
2021-03-19 17:24:04 +00:00
|
|
|
.cfg()
|
2021-11-18 20:43:54 +00:00
|
|
|
.map_or(true, |cfg| self.is_cfg_enabled(&cfg));
|
2021-09-03 14:00:50 +00:00
|
|
|
if is_enabled {
|
2021-03-19 17:24:04 +00:00
|
|
|
let module_id = self.push_child_module(
|
|
|
|
module.name.clone(),
|
|
|
|
ast_id,
|
|
|
|
Some((file_id, is_mod_rs)),
|
|
|
|
&self.item_tree[module.visibility],
|
2022-07-21 14:05:52 +00:00
|
|
|
module_id,
|
2021-03-19 17:24:04 +00:00
|
|
|
);
|
|
|
|
ModCollector {
|
2022-02-23 14:55:06 +00:00
|
|
|
def_collector: self.def_collector,
|
2021-03-19 17:24:04 +00:00
|
|
|
macro_depth: self.macro_depth,
|
|
|
|
module_id,
|
2021-07-19 12:53:18 +00:00
|
|
|
tree_id: TreeId::new(file_id.into(), None),
|
2021-03-19 17:24:04 +00:00
|
|
|
item_tree: &item_tree,
|
|
|
|
mod_dir,
|
|
|
|
}
|
2021-12-07 16:31:26 +00:00
|
|
|
.collect_in_top_module(item_tree.top_level_items());
|
2021-11-18 20:43:54 +00:00
|
|
|
let is_macro_use = is_macro_use
|
2021-03-19 17:24:04 +00:00
|
|
|
|| item_tree
|
2022-02-23 14:55:06 +00:00
|
|
|
.top_level_attrs(db, krate)
|
2021-03-19 17:24:04 +00:00
|
|
|
.by_key("macro_use")
|
2021-11-18 20:43:54 +00:00
|
|
|
.exists();
|
|
|
|
if is_macro_use {
|
2021-03-19 17:24:04 +00:00
|
|
|
self.import_all_legacy_macros(module_id);
|
|
|
|
}
|
2019-09-06 16:55:58 +00:00
|
|
|
}
|
2019-03-02 20:59:04 +00:00
|
|
|
}
|
2022-03-11 15:49:41 +00:00
|
|
|
Err(candidates) => {
|
2022-04-02 14:14:19 +00:00
|
|
|
self.push_child_module(
|
|
|
|
module.name.clone(),
|
|
|
|
ast_id,
|
|
|
|
None,
|
|
|
|
&self.item_tree[module.visibility],
|
2022-07-21 14:05:52 +00:00
|
|
|
module_id,
|
2022-04-02 14:14:19 +00:00
|
|
|
);
|
2020-09-16 12:52:39 +00:00
|
|
|
self.def_collector.def_map.diagnostics.push(
|
2022-03-11 15:49:41 +00:00
|
|
|
DefDiagnostic::unresolved_module(self.module_id, ast_id, candidates),
|
2020-09-16 12:52:39 +00:00
|
|
|
);
|
|
|
|
}
|
2019-03-23 15:35:14 +00:00
|
|
|
};
|
2019-03-02 20:59:04 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-13 13:38:02 +00:00
|
|
|
fn push_child_module(
|
|
|
|
&mut self,
|
|
|
|
name: Name,
|
2019-03-26 14:25:14 +00:00
|
|
|
declaration: AstId<ast::Module>,
|
2020-06-11 09:04:09 +00:00
|
|
|
definition: Option<(FileId, bool)>,
|
2019-12-26 14:57:14 +00:00
|
|
|
visibility: &crate::visibility::RawVisibility,
|
2022-07-21 14:05:52 +00:00
|
|
|
mod_tree_id: FileItemTreeId<Mod>,
|
2019-11-23 13:49:53 +00:00
|
|
|
) -> LocalModuleId {
|
2022-02-23 14:55:06 +00:00
|
|
|
let def_map = &mut self.def_collector.def_map;
|
|
|
|
let vis = def_map
|
2023-02-19 14:30:49 +00:00
|
|
|
.resolve_visibility(self.def_collector.db, self.module_id, visibility, false)
|
2019-12-26 15:00:10 +00:00
|
|
|
.unwrap_or(Visibility::Public);
|
2021-07-12 17:04:41 +00:00
|
|
|
let origin = match definition {
|
2022-07-21 14:05:52 +00:00
|
|
|
None => ModuleOrigin::Inline {
|
|
|
|
definition: declaration,
|
|
|
|
definition_tree_id: ItemTreeId::new(self.tree_id, mod_tree_id),
|
|
|
|
},
|
|
|
|
Some((definition, is_mod_rs)) => ModuleOrigin::File {
|
|
|
|
declaration,
|
|
|
|
definition,
|
|
|
|
is_mod_rs,
|
|
|
|
declaration_tree_id: ItemTreeId::new(self.tree_id, mod_tree_id),
|
|
|
|
},
|
2020-06-18 14:02:45 +00:00
|
|
|
};
|
2021-11-18 20:43:54 +00:00
|
|
|
|
2023-04-28 19:34:31 +00:00
|
|
|
let modules = &mut def_map.modules;
|
2021-07-12 18:13:43 +00:00
|
|
|
let res = modules.alloc(ModuleData::new(origin, vis));
|
2021-07-12 17:04:41 +00:00
|
|
|
modules[res].parent = Some(self.module_id);
|
2019-12-20 16:09:13 +00:00
|
|
|
for (name, mac) in modules[self.module_id].scope.collect_legacy_macros() {
|
2022-07-05 09:28:47 +00:00
|
|
|
for &mac in &mac {
|
|
|
|
modules[res].scope.define_legacy_macro(name.clone(), mac);
|
|
|
|
}
|
2019-12-20 16:09:13 +00:00
|
|
|
}
|
2019-03-14 08:53:40 +00:00
|
|
|
modules[self.module_id].children.insert(name.clone(), res);
|
2021-11-18 20:43:54 +00:00
|
|
|
|
2022-02-23 14:55:06 +00:00
|
|
|
let module = def_map.module_id(res);
|
2021-11-18 20:43:54 +00:00
|
|
|
let def = ModuleDefId::from(module);
|
|
|
|
|
2022-02-23 14:55:06 +00:00
|
|
|
def_map.modules[self.module_id].scope.declare(def);
|
2020-06-25 01:42:44 +00:00
|
|
|
self.def_collector.update(
|
|
|
|
self.module_id,
|
2020-07-21 15:52:43 +00:00
|
|
|
&[(Some(name), PerNs::from_def(def, vis, false))],
|
2020-06-25 01:42:44 +00:00
|
|
|
vis,
|
2020-06-25 16:42:12 +00:00
|
|
|
ImportType::Named,
|
2020-06-25 01:42:44 +00:00
|
|
|
);
|
2019-03-02 20:59:04 +00:00
|
|
|
res
|
|
|
|
}
|
|
|
|
|
2021-05-19 13:17:57 +00:00
|
|
|
/// Resolves attributes on an item.
|
|
|
|
///
|
|
|
|
/// Returns `Err` when some attributes could not be resolved to builtins and have been
|
|
|
|
/// registered as unresolved.
|
2021-05-20 17:56:04 +00:00
|
|
|
///
|
2021-10-21 10:21:34 +00:00
|
|
|
/// If `ignore_up_to` is `Some`, attributes preceding and including that attribute will be
|
2021-05-20 17:56:04 +00:00
|
|
|
/// assumed to be resolved already.
|
2021-12-07 16:31:26 +00:00
|
|
|
fn resolve_attributes(
|
|
|
|
&mut self,
|
|
|
|
attrs: &Attrs,
|
|
|
|
mod_item: ModItem,
|
|
|
|
container: ItemContainerId,
|
|
|
|
) -> Result<(), ()> {
|
2021-05-20 17:56:04 +00:00
|
|
|
let mut ignore_up_to =
|
2021-07-19 12:53:18 +00:00
|
|
|
self.def_collector.skip_attrs.get(&InFile::new(self.file_id(), mod_item)).copied();
|
2021-05-22 00:30:03 +00:00
|
|
|
let iter = attrs
|
|
|
|
.iter()
|
|
|
|
.dedup_by(|a, b| {
|
|
|
|
// FIXME: this should not be required, all attributes on an item should have a
|
|
|
|
// unique ID!
|
|
|
|
// Still, this occurs because `#[cfg_attr]` can "expand" to multiple attributes:
|
|
|
|
// #[cfg_attr(not(off), unresolved, unresolved)]
|
|
|
|
// struct S;
|
|
|
|
// We should come up with a different way to ID attributes.
|
|
|
|
a.id == b.id
|
|
|
|
})
|
|
|
|
.skip_while(|attr| match ignore_up_to {
|
|
|
|
Some(id) if attr.id == id => {
|
|
|
|
ignore_up_to = None;
|
|
|
|
true
|
|
|
|
}
|
|
|
|
Some(_) => true,
|
|
|
|
None => false,
|
|
|
|
});
|
|
|
|
|
|
|
|
for attr in iter {
|
2022-01-06 11:30:16 +00:00
|
|
|
if self.def_collector.def_map.is_builtin_or_registered_attr(&attr.path) {
|
2021-05-20 17:56:04 +00:00
|
|
|
continue;
|
2021-11-17 18:46:32 +00:00
|
|
|
}
|
|
|
|
tracing::debug!("non-builtin attribute {}", attr.path);
|
2021-05-19 13:17:57 +00:00
|
|
|
|
2021-11-17 18:46:32 +00:00
|
|
|
let ast_id = AstIdWithPath::new(
|
|
|
|
self.file_id(),
|
|
|
|
mod_item.ast_id(self.item_tree),
|
|
|
|
attr.path.as_ref().clone(),
|
|
|
|
);
|
|
|
|
self.def_collector.unresolved_macros.push(MacroDirective {
|
|
|
|
module_id: self.module_id,
|
|
|
|
depth: self.macro_depth + 1,
|
2021-11-26 02:57:25 +00:00
|
|
|
kind: MacroDirectiveKind::Attr {
|
|
|
|
ast_id,
|
|
|
|
attr: attr.clone(),
|
|
|
|
mod_item,
|
|
|
|
tree: self.tree_id,
|
|
|
|
},
|
2021-12-07 16:31:26 +00:00
|
|
|
container,
|
2021-11-17 18:46:32 +00:00
|
|
|
});
|
2021-05-19 13:17:57 +00:00
|
|
|
|
2021-11-17 18:46:32 +00:00
|
|
|
return Err(());
|
2021-05-19 13:17:57 +00:00
|
|
|
}
|
2021-05-20 17:56:04 +00:00
|
|
|
|
|
|
|
Ok(())
|
2021-05-19 13:17:57 +00:00
|
|
|
}
|
|
|
|
|
2022-03-08 20:41:19 +00:00
|
|
|
fn collect_macro_rules(&mut self, id: FileItemTreeId<MacroRules>, module: ModuleId) {
|
2020-12-17 23:23:46 +00:00
|
|
|
let krate = self.def_collector.def_map.krate;
|
2020-12-16 22:42:03 +00:00
|
|
|
let mac = &self.item_tree[id];
|
2020-12-17 23:23:46 +00:00
|
|
|
let attrs = self.item_tree.attrs(self.def_collector.db, krate, ModItem::from(id).into());
|
2021-07-19 12:53:18 +00:00
|
|
|
let ast_id = InFile::new(self.file_id(), mac.ast_id.upcast());
|
2019-10-29 08:15:51 +00:00
|
|
|
|
2020-12-16 22:42:03 +00:00
|
|
|
let export_attr = attrs.by_key("macro_export");
|
|
|
|
|
|
|
|
let is_export = export_attr.exists();
|
2022-03-08 20:41:19 +00:00
|
|
|
let local_inner = if is_export {
|
2021-11-18 20:43:54 +00:00
|
|
|
export_attr.tt_values().flat_map(|it| &it.token_trees).any(|it| match it {
|
2020-12-16 22:42:03 +00:00
|
|
|
tt::TokenTree::Leaf(tt::Leaf::Ident(ident)) => {
|
|
|
|
ident.text.contains("local_inner_macros")
|
|
|
|
}
|
|
|
|
_ => false,
|
|
|
|
})
|
|
|
|
} else {
|
|
|
|
false
|
|
|
|
};
|
|
|
|
|
2020-12-15 14:37:37 +00:00
|
|
|
// Case 1: builtin macros
|
2022-03-08 20:41:19 +00:00
|
|
|
let expander = if attrs.by_key("rustc_builtin_macro").exists() {
|
2021-04-03 01:13:04 +00:00
|
|
|
// `#[rustc_builtin_macro = "builtin_name"]` overrides the `macro_rules!` name.
|
|
|
|
let name;
|
|
|
|
let name = match attrs.by_key("rustc_builtin_macro").string_value() {
|
|
|
|
Some(it) => {
|
|
|
|
// FIXME: a hacky way to create a Name from string.
|
2023-01-31 10:49:49 +00:00
|
|
|
name =
|
|
|
|
tt::Ident { text: it.clone(), span: tt::TokenId::unspecified() }.as_name();
|
2021-04-03 01:13:04 +00:00
|
|
|
&name
|
|
|
|
}
|
2021-09-09 19:32:41 +00:00
|
|
|
None => {
|
2021-11-18 20:43:54 +00:00
|
|
|
let explicit_name =
|
|
|
|
attrs.by_key("rustc_builtin_macro").tt_values().next().and_then(|tt| {
|
|
|
|
match tt.token_trees.first() {
|
|
|
|
Some(tt::TokenTree::Leaf(tt::Leaf::Ident(name))) => Some(name),
|
|
|
|
_ => None,
|
|
|
|
}
|
|
|
|
});
|
|
|
|
match explicit_name {
|
2021-09-09 19:32:41 +00:00
|
|
|
Some(ident) => {
|
|
|
|
name = ident.as_name();
|
|
|
|
&name
|
|
|
|
}
|
|
|
|
None => &mac.name,
|
|
|
|
}
|
|
|
|
}
|
2021-04-03 01:13:04 +00:00
|
|
|
};
|
2022-03-08 20:41:19 +00:00
|
|
|
match find_builtin_macro(name) {
|
|
|
|
Some(Either::Left(it)) => MacroExpander::BuiltIn(it),
|
|
|
|
Some(Either::Right(it)) => MacroExpander::BuiltInEager(it),
|
2021-05-30 02:19:47 +00:00
|
|
|
None => {
|
|
|
|
self.def_collector
|
|
|
|
.def_map
|
|
|
|
.diagnostics
|
|
|
|
.push(DefDiagnostic::unimplemented_builtin_macro(self.module_id, ast_id));
|
2022-03-08 20:41:19 +00:00
|
|
|
return;
|
2021-05-30 02:19:47 +00:00
|
|
|
}
|
2019-03-02 20:59:04 +00:00
|
|
|
}
|
2022-03-08 20:41:19 +00:00
|
|
|
} else {
|
|
|
|
// Case 2: normal `macro_rules!` macro
|
|
|
|
MacroExpander::Declarative
|
2020-12-15 14:37:37 +00:00
|
|
|
};
|
2023-01-30 14:41:08 +00:00
|
|
|
let allow_internal_unsafe = attrs.by_key("allow_internal_unsafe").exists();
|
2022-03-08 20:41:19 +00:00
|
|
|
|
|
|
|
let macro_id = MacroRulesLoc {
|
|
|
|
container: module,
|
|
|
|
id: ItemTreeId::new(self.tree_id, id),
|
|
|
|
local_inner,
|
2023-01-30 14:41:08 +00:00
|
|
|
allow_internal_unsafe,
|
2022-03-08 20:41:19 +00:00
|
|
|
expander,
|
|
|
|
}
|
|
|
|
.intern(self.def_collector.db);
|
2021-03-27 05:44:54 +00:00
|
|
|
self.def_collector.define_macro_rules(
|
|
|
|
self.module_id,
|
|
|
|
mac.name.clone(),
|
|
|
|
macro_id,
|
|
|
|
is_export,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2022-03-08 20:41:19 +00:00
|
|
|
fn collect_macro_def(&mut self, id: FileItemTreeId<MacroDef>, module: ModuleId) {
|
2021-03-27 05:44:54 +00:00
|
|
|
let krate = self.def_collector.def_map.krate;
|
|
|
|
let mac = &self.item_tree[id];
|
2021-07-19 12:53:18 +00:00
|
|
|
let ast_id = InFile::new(self.file_id(), mac.ast_id.upcast());
|
2021-03-27 05:44:54 +00:00
|
|
|
|
2021-10-28 16:40:38 +00:00
|
|
|
// Case 1: builtin macros
|
2022-11-07 12:24:17 +00:00
|
|
|
let mut helpers_opt = None;
|
2021-03-27 05:44:54 +00:00
|
|
|
let attrs = self.item_tree.attrs(self.def_collector.db, krate, ModItem::from(id).into());
|
2022-03-08 20:41:19 +00:00
|
|
|
let expander = if attrs.by_key("rustc_builtin_macro").exists() {
|
|
|
|
if let Some(expander) = find_builtin_macro(&mac.name) {
|
|
|
|
match expander {
|
|
|
|
Either::Left(it) => MacroExpander::BuiltIn(it),
|
|
|
|
Either::Right(it) => MacroExpander::BuiltInEager(it),
|
2021-05-30 02:19:47 +00:00
|
|
|
}
|
2022-03-08 20:41:19 +00:00
|
|
|
} else if let Some(expander) = find_builtin_derive(&mac.name) {
|
2022-11-07 12:24:17 +00:00
|
|
|
if let Some(attr) = attrs.by_key("rustc_builtin_macro").tt_values().next() {
|
|
|
|
// NOTE: The item *may* have both `#[rustc_builtin_macro]` and `#[proc_macro_derive]`,
|
|
|
|
// in which case rustc ignores the helper attributes from the latter, but it
|
|
|
|
// "doesn't make sense in practice" (see rust-lang/rust#87027).
|
|
|
|
if let Some((name, helpers)) =
|
|
|
|
parse_macro_name_and_helper_attrs(&attr.token_trees)
|
|
|
|
{
|
|
|
|
// NOTE: rustc overrides the name if the macro name if it's different from the
|
|
|
|
// macro name, but we assume it isn't as there's no such case yet. FIXME if
|
|
|
|
// the following assertion fails.
|
|
|
|
stdx::always!(
|
|
|
|
name == mac.name,
|
|
|
|
"built-in macro {} has #[rustc_builtin_macro] which declares different name {}",
|
|
|
|
mac.name,
|
|
|
|
name
|
|
|
|
);
|
|
|
|
helpers_opt = Some(helpers);
|
|
|
|
}
|
|
|
|
}
|
2022-03-08 20:41:19 +00:00
|
|
|
MacroExpander::BuiltInDerive(expander)
|
|
|
|
} else if let Some(expander) = find_builtin_attr(&mac.name) {
|
|
|
|
MacroExpander::BuiltInAttr(expander)
|
|
|
|
} else {
|
|
|
|
self.def_collector
|
|
|
|
.def_map
|
|
|
|
.diagnostics
|
|
|
|
.push(DefDiagnostic::unimplemented_builtin_macro(self.module_id, ast_id));
|
|
|
|
return;
|
2021-03-27 05:44:54 +00:00
|
|
|
}
|
2022-03-08 20:41:19 +00:00
|
|
|
} else {
|
|
|
|
// Case 2: normal `macro`
|
|
|
|
MacroExpander::Declarative
|
2021-03-27 05:44:54 +00:00
|
|
|
};
|
2023-01-30 14:41:08 +00:00
|
|
|
let allow_internal_unsafe = attrs.by_key("allow_internal_unsafe").exists();
|
2021-03-27 05:44:54 +00:00
|
|
|
|
2023-01-30 14:41:08 +00:00
|
|
|
let macro_id = Macro2Loc {
|
|
|
|
container: module,
|
|
|
|
id: ItemTreeId::new(self.tree_id, id),
|
|
|
|
expander,
|
|
|
|
allow_internal_unsafe,
|
|
|
|
}
|
|
|
|
.intern(self.def_collector.db);
|
2021-03-27 05:44:54 +00:00
|
|
|
self.def_collector.define_macro_def(
|
|
|
|
self.module_id,
|
|
|
|
mac.name.clone(),
|
|
|
|
macro_id,
|
|
|
|
&self.item_tree[mac.visibility],
|
|
|
|
);
|
2022-11-07 12:24:17 +00:00
|
|
|
if let Some(helpers) = helpers_opt {
|
|
|
|
self.def_collector
|
|
|
|
.def_map
|
|
|
|
.exported_derives
|
|
|
|
.insert(macro_id_to_def_id(self.def_collector.db, macro_id.into()), helpers);
|
|
|
|
}
|
2020-12-15 14:37:37 +00:00
|
|
|
}
|
|
|
|
|
2021-12-07 16:31:26 +00:00
|
|
|
fn collect_macro_call(&mut self, mac: &MacroCall, container: ItemContainerId) {
|
2021-11-18 20:43:54 +00:00
|
|
|
let ast_id = AstIdWithPath::new(self.file_id(), mac.ast_id, ModPath::clone(&mac.path));
|
2020-12-15 14:37:37 +00:00
|
|
|
|
|
|
|
// Case 1: try to resolve in legacy scope and expand macro_rules
|
2023-04-16 16:29:42 +00:00
|
|
|
if let Ok(res) = macro_call_as_call_id(
|
2023-04-17 15:31:39 +00:00
|
|
|
self.def_collector.db.upcast(),
|
2021-02-28 11:12:11 +00:00
|
|
|
&ast_id,
|
2021-09-05 19:30:06 +00:00
|
|
|
mac.expand_to,
|
2021-02-28 11:12:11 +00:00
|
|
|
self.def_collector.def_map.krate,
|
|
|
|
|path| {
|
2020-06-11 10:08:24 +00:00
|
|
|
path.as_ident().and_then(|name| {
|
2021-02-04 12:44:54 +00:00
|
|
|
self.def_collector.def_map.with_ancestor_maps(
|
|
|
|
self.def_collector.db,
|
|
|
|
self.module_id,
|
2022-03-08 20:41:19 +00:00
|
|
|
&mut |map, module| {
|
|
|
|
map[module]
|
|
|
|
.scope
|
|
|
|
.get_legacy_macro(name)
|
2022-07-05 09:28:47 +00:00
|
|
|
.and_then(|it| it.last())
|
2022-12-30 08:42:44 +00:00
|
|
|
.map(|&it| macro_id_to_def_id(self.def_collector.db, it))
|
2022-03-08 20:41:19 +00:00
|
|
|
},
|
2021-02-04 12:44:54 +00:00
|
|
|
)
|
2020-06-11 10:08:24 +00:00
|
|
|
})
|
2021-02-28 11:12:11 +00:00
|
|
|
},
|
|
|
|
) {
|
2023-04-16 16:29:42 +00:00
|
|
|
// Legacy macros need to be expanded immediately, so that any macros they produce
|
|
|
|
// are in scope.
|
|
|
|
if let Some(val) = res {
|
|
|
|
self.def_collector.collect_macro_expansion(
|
|
|
|
self.module_id,
|
|
|
|
val,
|
|
|
|
self.macro_depth + 1,
|
|
|
|
container,
|
|
|
|
);
|
2021-03-14 05:28:10 +00:00
|
|
|
}
|
2023-04-16 16:29:42 +00:00
|
|
|
|
|
|
|
return;
|
2019-03-02 20:59:04 +00:00
|
|
|
}
|
|
|
|
|
2020-12-15 14:37:37 +00:00
|
|
|
// Case 2: resolve in module scope, expand during name resolution.
|
2021-05-20 11:12:29 +00:00
|
|
|
self.def_collector.unresolved_macros.push(MacroDirective {
|
2019-12-08 12:33:42 +00:00
|
|
|
module_id: self.module_id,
|
2020-03-13 12:57:44 +00:00
|
|
|
depth: self.macro_depth + 1,
|
2021-09-05 19:30:06 +00:00
|
|
|
kind: MacroDirectiveKind::FnLike { ast_id, expand_to: mac.expand_to },
|
2021-12-07 16:31:26 +00:00
|
|
|
container,
|
2019-12-08 12:33:42 +00:00
|
|
|
});
|
2019-03-02 20:59:04 +00:00
|
|
|
}
|
2019-09-06 16:55:58 +00:00
|
|
|
|
2019-11-23 13:49:53 +00:00
|
|
|
fn import_all_legacy_macros(&mut self, module_id: LocalModuleId) {
|
2019-12-20 16:09:13 +00:00
|
|
|
let macros = self.def_collector.def_map[module_id].scope.collect_legacy_macros();
|
2022-07-05 09:28:47 +00:00
|
|
|
for (name, macs) in macros {
|
|
|
|
macs.last().map(|&mac| {
|
|
|
|
self.def_collector.define_legacy_macro(self.module_id, name.clone(), mac)
|
|
|
|
});
|
2019-09-06 16:55:58 +00:00
|
|
|
}
|
|
|
|
}
|
2019-09-29 22:52:15 +00:00
|
|
|
|
2020-10-22 17:19:18 +00:00
|
|
|
fn is_cfg_enabled(&self, cfg: &CfgExpr) -> bool {
|
|
|
|
self.def_collector.cfg_options.check(cfg) != Some(false)
|
2019-09-29 22:52:15 +00:00
|
|
|
}
|
2020-10-20 15:49:21 +00:00
|
|
|
|
2022-09-21 22:05:30 +00:00
|
|
|
fn emit_unconfigured_diagnostic(&mut self, item: ModItem, cfg: &CfgExpr) {
|
|
|
|
let ast_id = item.ast_id(self.item_tree);
|
|
|
|
|
|
|
|
let ast_id = InFile::new(self.file_id(), ast_id.upcast());
|
2020-10-22 17:19:18 +00:00
|
|
|
self.def_collector.def_map.diagnostics.push(DefDiagnostic::unconfigured_code(
|
|
|
|
self.module_id,
|
2022-09-21 22:05:30 +00:00
|
|
|
ast_id,
|
2020-10-22 17:19:18 +00:00
|
|
|
cfg.clone(),
|
|
|
|
self.def_collector.cfg_options.clone(),
|
|
|
|
));
|
2020-10-20 15:49:21 +00:00
|
|
|
}
|
2021-07-19 12:53:18 +00:00
|
|
|
|
|
|
|
fn file_id(&self) -> HirFileId {
|
|
|
|
self.tree_id.file_id()
|
|
|
|
}
|
2019-03-02 20:59:04 +00:00
|
|
|
}
|
|
|
|
|
2019-11-03 17:53:17 +00:00
|
|
|
#[cfg(test)]
|
2019-04-22 07:33:55 +00:00
|
|
|
mod tests {
|
2019-12-08 12:33:42 +00:00
|
|
|
use crate::{db::DefDatabase, test_db::TestDB};
|
2020-08-13 14:25:38 +00:00
|
|
|
use base_db::{fixture::WithFixture, SourceDatabase};
|
2019-11-03 17:53:17 +00:00
|
|
|
|
|
|
|
use super::*;
|
|
|
|
|
2021-01-18 19:18:05 +00:00
|
|
|
fn do_collect_defs(db: &dyn DefDatabase, def_map: DefMap) -> DefMap {
|
2019-04-22 07:33:55 +00:00
|
|
|
let mut collector = DefCollector {
|
|
|
|
db,
|
|
|
|
def_map,
|
2021-09-28 19:23:46 +00:00
|
|
|
deps: FxHashMap::default(),
|
2019-04-22 07:33:55 +00:00
|
|
|
glob_imports: FxHashMap::default(),
|
|
|
|
unresolved_imports: Vec::new(),
|
2022-05-26 10:59:57 +00:00
|
|
|
indeterminate_imports: Vec::new(),
|
2021-05-20 11:12:29 +00:00
|
|
|
unresolved_macros: Vec::new(),
|
2019-10-10 11:45:05 +00:00
|
|
|
mod_dirs: FxHashMap::default(),
|
2019-09-29 22:52:15 +00:00
|
|
|
cfg_options: &CfgOptions::default(),
|
2020-03-25 12:14:22 +00:00
|
|
|
proc_macros: Default::default(),
|
2020-06-26 01:34:39 +00:00
|
|
|
from_glob_import: Default::default(),
|
2021-05-20 18:18:53 +00:00
|
|
|
skip_attrs: Default::default(),
|
2022-03-09 13:33:39 +00:00
|
|
|
is_proc_macro: false,
|
2023-04-22 09:22:29 +00:00
|
|
|
hygienes: FxHashMap::default(),
|
2019-04-22 07:33:55 +00:00
|
|
|
};
|
2021-01-21 14:22:17 +00:00
|
|
|
collector.seed_with_top_level();
|
2019-04-22 07:33:55 +00:00
|
|
|
collector.collect();
|
2019-12-08 12:33:42 +00:00
|
|
|
collector.def_map
|
2019-04-22 07:33:55 +00:00
|
|
|
}
|
|
|
|
|
2021-06-14 19:55:05 +00:00
|
|
|
fn do_resolve(not_ra_fixture: &str) -> DefMap {
|
2021-07-12 17:14:58 +00:00
|
|
|
let (db, file_id) = TestDB::with_single_file(not_ra_fixture);
|
2019-11-15 10:16:16 +00:00
|
|
|
let krate = db.test_crate();
|
2019-04-22 07:33:55 +00:00
|
|
|
|
2021-01-21 14:22:17 +00:00
|
|
|
let edition = db.crate_graph()[krate].edition;
|
2021-07-12 17:14:58 +00:00
|
|
|
let module_origin = ModuleOrigin::CrateRoot { definition: file_id };
|
2022-07-14 21:22:54 +00:00
|
|
|
let def_map =
|
|
|
|
DefMap::empty(krate, edition, ModuleData::new(module_origin, Visibility::Public));
|
2019-12-08 12:33:42 +00:00
|
|
|
do_collect_defs(&db, def_map)
|
2019-04-22 07:33:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2020-03-13 12:57:44 +00:00
|
|
|
fn test_macro_expand_will_stop_1() {
|
|
|
|
do_resolve(
|
|
|
|
r#"
|
2021-06-15 08:58:39 +00:00
|
|
|
macro_rules! foo {
|
|
|
|
($($ty:ty)*) => { foo!($($ty)*); }
|
|
|
|
}
|
|
|
|
foo!(KABOOM);
|
|
|
|
"#,
|
|
|
|
);
|
|
|
|
do_resolve(
|
|
|
|
r#"
|
|
|
|
macro_rules! foo {
|
|
|
|
($($ty:ty)*) => { foo!(() $($ty)*); }
|
|
|
|
}
|
|
|
|
foo!(KABOOM);
|
|
|
|
"#,
|
2020-03-13 12:57:44 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2021-06-14 19:55:05 +00:00
|
|
|
#[ignore]
|
2020-03-13 12:57:44 +00:00
|
|
|
#[test]
|
|
|
|
fn test_macro_expand_will_stop_2() {
|
2021-06-14 19:55:05 +00:00
|
|
|
// FIXME: this test does succeed, but takes quite a while: 90 seconds in
|
|
|
|
// the release mode. That's why the argument is not an ra_fixture --
|
|
|
|
// otherwise injection highlighting gets stuck.
|
|
|
|
//
|
|
|
|
// We need to find a way to fail this faster.
|
2019-12-08 12:33:42 +00:00
|
|
|
do_resolve(
|
2019-04-22 07:33:55 +00:00
|
|
|
r#"
|
2021-06-14 19:55:05 +00:00
|
|
|
macro_rules! foo {
|
|
|
|
($($ty:ty)*) => { foo!($($ty)* $($ty)*); }
|
|
|
|
}
|
|
|
|
foo!(KABOOM);
|
|
|
|
"#,
|
2019-04-22 07:33:55 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|